public class Bubble {
// 对数组a中的元素进行排序
public static void sort(Comparable[] a) {
for(int i=a.length-1;i>0;i--) {
for(int j=0;j<i;j++) {
if (greater(a[j],a[j+1])) {
exch(a,j,j+1);
}
}
}
}
// 比较v元素是否大于w元素
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
// 数组元素i和j交换位置
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
public class Selection {
// 对数组a中的元素进行排序
public static void sort(Comparable[] a){
for(int i=0;i<a.length-1;i++) {
//假定本次遍历,最小值所在索引是i
int minIndex = i;
for(int j=i+1;j< a.length;j++) {
if(greater(a[minIndex],a[j])) {
//更换最小值所在索引
minIndex = j;
}
}
//交换索引i和索引minIndex处的值
exch(a, i, minIndex);
}
}
// 比较v元素是否大于w元素
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
// 交换数组a中,索引i和索引j处的值
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
public class Insertion {
// 对数组a中的元素进行排序
public static void sort(Comparable[] a) {
for(int i=1;i< a.length;i++) {
// 当前元素为a[i],依次和i前面的元素比较,找到一个小于a[i]的元素
for(int j=i;j>=1;j--) {
if (greater(a[j-1],a[j])) {
// 交换元素
exch(a, j, j-1);
}else {
break;
}
}
}
}
// 比较v元素是否大于w元素
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
// 交换数组a中,索引i和索引j处的值
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
public class Shell {
public static void sort(Comparable[] a) {
int N = a.length;
// 确定增长量h的最大值
int h = 1;
while(h<N/2) {
h = h * 2 + 1;
}
// 当增长量h小于1,排序结束
while(h>=1) {
// 找到待插入的元素
for(int i=h;i<N;i++) {
// a[i]就是待插入的元素
// 把a[i]插入到a[i-h],a[i-2h],a[i-3h]....序列中
for(int j=i;j>=h;j-=h) {
// a[j]就是待插入的元素,依次和a[j-h],a[j-2h],a[j-3h]进行比较,如果a[j]小,那么交换位置
if(greater(a[j-h],a[j])) {
exch(a, j, j-h);
}else {
break;
}
}
}
h /= 2;
}
}
// 比较v元素是否大于w元素
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
// 交换数组a中,索引i和索引j处的值
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
public class Merge {
//定义一个辅助数组
private static Comparable[] assist;
//对数组a中的元素进行排序
public static void sort(Comparable[] a) {
assist = new Comparable[a.length];
int lo = 0;
int hi = a.length-1;
sort(a,lo,hi);
}
//对数组a从lo到hi的元素进行排序
private static void sort(Comparable[] a,int lo, int hi) {
if (lo==hi) {
return;
}
int mid = (lo+hi)/2;
//对lo到mid之间的元素进行排序
sort(a,lo,mid);
//对mid+1到hi之间的元素进行排序
sort(a,mid+1,hi);
//对lo到mid这组数组和mid+1到hi这组数据进行归并
merge(a,lo,mid,hi);
}
//对数组中,从lo到mid为一组,从mid+1到hi为一组,对这两组数据进行归并
private static void merge(Comparable[] a, int lo, int mid, int hi) {
int i = lo;//定义一个指针,指向assist数组中开始填充数据的索引
int p1 = lo;//定义一个指针,指向第一组数据的第一个元素
int p2 = mid+1;//定义一个指针,指向第二组数据的第一个元素
//lo到mid这组数据和mid+1到hi这组数据归并到辅助数组assist对应的索引处
//比较左边小组和右边小组中的元素大小,如果右边比左边小,把右边数据填充到assist数组中,否则填充左边
while(p1<=mid && p2<=hi) {
if (greater(a[p1],a[p2])) {
assist[i++] = a[p2++];
} else {
assist[i++] = a[p1++];
}
}
//上面的循环结束后,如果退出循环的条件是p1<=mid,则证明左边小组中的数据已经归并完毕;如果退出循环的条件是p2<=hi,则证明右边小组的数据已经填充完毕
//所以需要把未填充完毕的数据继续填充到assist中,下面两个循环,会执行其中一个
while (p1<=mid) {
assist[i++] = a[p1++];
}
while (p2<=hi) {
assist[i++] = a[p2++];
}
//到目前为止,assist数组中从lo到hi的元素都是有序的,再把数据拷贝到a数组中对应的索引处
for (int index=lo;index<=hi;index++) {
a[index] = assist[index];
}
}
// 比较v元素是否大于w元素
private static boolean greater(Comparable v, Comparable w) {
return v.compareTo(w) > 0;
}
}
public class Quick {
public static void sort(Comparable[] a) {
int lo = 0;
int hi = a.length - 1;
quicksort(a, lo, hi);
}
private static void quicksort(Comparable[] a, int lo, int hi) {
if (lo >= hi) return;
Comparable key = a[lo]; // 把最左边的元素当作基准值
int left = lo; // 定义一个左指针,初始指向最左边元素
int right = hi; // 定义一个右指针,初始指向最右边元素
// 进行切分
while(left < right){
// 先从右往左扫描,找到一个比基准值小的元素
while(greaterOrequal(a[right],key) && left < right){
right--;
}
// 再从左往右扫描,找一个比基准值大的元素
while (greaterOrequal(key,a[left]) && left < right){
left++;
}
//交换left和right索引处的元素
exch(a,left,right);
}
// 交换最后left索引处和基准值所在索引处的值,交换right也可以,因为left和right最终会相等
exch(a, lo, left);
// 继续迭代
quicksort(a, lo, left - 1);
quicksort(a, left + 1, hi);
}
// 比较v元素是否大于等于w元素
private static boolean greaterOrequal(Comparable v, Comparable w) {
return v.compareTo(w) >= 0;
}
// i索引和j索引处的元素互换
private static void exch(Comparable[] a, int i, int j) {
Comparable t = a[i];
a[i] = a[j];
a[j] = t;
}
}
public class Test {
public static void main(String[] args) throws Exception {
Integer[] arr = {
8,6,1,2,7,40,8,56,21,88};
// Bubble.sort(arr);
// Selection.sort(arr);
// Insertion.sort(arr);
// Shell.sort(arr);
// Merge.sort(arr);
Quick.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
[1, 2, 6, 7, 8, 8, 21, 40, 56, 88]
只有当arr[i]>arr[i+1]的时候,才会交换元素位置,相等的时候不交换。
所以冒泡排序是稳定的。
选择排序是给每个位置选择当前元素最小的。例如有数据{5(1),8,5(2),2,9},第一遍选择到的最小元素为2,所以5(1)会和2进行位置交换,此时5(1)到了5(2)的后面,破坏了稳定性。
所以选择排序是不稳定的。
插入排序是从有序序列的末尾开始,也就是想要插入的元素和已经有序的最大者开始比起,如果不比它小则直接插入在其后面,否则一直往前找直到找到它插入的位置。
如果碰见一个和插入元素相等的,那么把要插入的元素放在相等元素的后面,相等元素的前后顺序没有改变。
所以插入排序是稳定的。
希尔排序是按照不同步长对元素进行插入排序,虽然一次插入排序是稳定的,不会改变相同元素的相对顺序,但在不同的插入排序过程中,相同的元素可能在各自的插入排序中移动,最后其稳定性就会被打乱。
所以希尔排序是不稳定的。
归并排序在归并过程中,只有当前面的元素比后面的元素大时才会交换位置,如果元素相等则先加入前面的元素,不会破坏稳定性。
所以归并排序是稳定的。
快速排序需要一个基准值,在基准值右侧找一个比基准值小的元素,在基准值左侧找一个比基准值大的元素,然后交换这两个元素,会破坏稳定性。
所以快速排序是不稳定的。