1.冒泡排序
冒泡排序是不是稳定的主要根据 IF 判断的条件进行判断,若相同元素不发生交换,那么这就是稳定的
1 public static void maopao(int[] arr) 2 { 3 for (int i = 0; i < arr.Length; i++) 4 { 5 for (int j = 0; j < arr.Length - 1 - i; j++) 6 { 7 if (arr[j] > arr[j + 1]) 8 { 9 int temp = arr[j + 1]; 10 arr[j + 1] = arr[j]; 11 arr[j] = temp; 12 } 13 } 14 } 15 }
2.快速排序
快速排序是不稳定的,主要发生的原因在基准值与左右游动的下标元素之间,例如:3 3 7 2 8 9 ,在这里第一个 3 会与 2 发生交换,导致两个 3 的相对位置发生变化。
我这里是使用递归实现,用循环也可以实现。
1 public static void quickSort(int[] arr, int begin, int end) 2 { 3 if (begin >= end) return; 4 int a = begin; 5 int b = end; 6 int jizhun = arr[begin]; 7 int index = end; 8 while (begin < end) 9 { 10 //如果基准值大于元素值,元素值要插入到起始位 11 if (jizhun > arr[index]) 12 { 13 arr[begin] = arr[index]; 14 begin++; 15 index = begin; 16 } 17 else { 18 arr[end] = arr[index]; 19 end--; 20 index = end; 21 } 22 if (begin == end) 23 { 24 arr[begin] = jizhun; 25 } 26 } 27 quickSort(arr, a, index - 1); 28 quickSort(arr, index + 1, b); 29 }
3.插入排序
插入排序是稳定的排序,因为这种排序每次比较的步长只有1 ,不会出现跳跃的情况,有人可能会觉得插入排序和冒泡排序简直就是一摸一样,有什么区别的?这个疑问一开始我也有,后来根据资料,插入排序与冒泡排序的区别主要在内层循环 ,如果需要排序的集合是有序的,那么插入排序的内层比较的次数相对于冒泡排序将会大大较少。但是冒泡排序可以优化,当不发生交换的时候结束内层 for 循环,这样的话两种的区别就基本没有了。
public static void insertSort(int[] arr) { for (int i = 0; i < arr.Length - 1; i++) { int begin = i; while (arr[begin + 1] < arr[begin]) { int temp = arr[begin + 1]; arr[begin + 1] = arr[begin]; arr[begin] = temp; begin--; if (begin < 0) break; } } }
4.希尔排序
希尔排序其本质就是插入排序,只是插入排序每次的步长都是1,而希尔排序的步长是在逐步缩减,可以将位置变化大的数据迅速放到前面或者后面,相对于插入排序来说减少了移动的次序。但是由于这个特性,导致希尔排序变成不稳定的,在大幅度移动的过程中,其稳定性被破坏,例如 98 98 1 34 5 在这个例子中,第一个98 在步长为2 的情况下会被移动到5的位置,这样相对第二个98 ,他从前面移动到了后面,丢失稳定性。
public static void xierSort(int[] arr, int step) { if (step == 0) return; for (int i = 0; i < arr.Length - step; i++) { int begin = i; while (arr[begin] > arr[begin + step]) { int temp = arr[begin + step]; arr[begin + step] = arr[begin]; arr[begin] = temp; begin = begin - step; if (begin < 0) break; } } show(arr); xierSort(arr, step / 2); }
5.选择排序
选择排序的思想是在一次循环中找到最小的元素下标,然后和起始元素进行交换,这种也是不稳定的,例如 5 5 1 6 7 在这个集合中 第一个5会在第一次交换中与 1 发生教会,稳定性丢失
public static void selectSort(int[] arr) { for (int i = 0; i < arr.Length; i++) { int minIndex = i; for (int j = i; j < arr.Length; j++) { // > 正序 < 倒叙 if (arr[minIndex] > arr[j]) { minIndex = j; } } int temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } }
6.归并排序
归并排序的思想是永远保证左右是有序的,这是前提,如果不是有序的就递归下去,知道左右各有1个元素时,进行交换,归并排序是稳定的。
public static void guibingSort(int[] arr, int low, int high) { if (low == high) return ; int middle = (high + low - 1) / 2; guibingSort(arr, low, middle); guibingSort(arr, middle + 1, high); int[] temp = new int[high - low+1]; //前一个数组的指针 int i = low; //后一个数组的指针 int j = middle + 1; //临时数组指针 int index = 0; while (i <= middle && j <= high) { temp[index++] = arr[i] <= arr[j] ? arr[i++]:arr[j++] ; } //多余元素写入 while (i <= middle) { temp[index++] = arr[i++]; } while (j <= high) { temp[index++] = arr[j++]; } for (int m = 0; m < temp.Length; m++) { arr[low + m] = temp[m]; } }
7.基数排序
空间换时间的排序方式,是稳定的,用队列实现,如果用数组实现,需要记录桶中元素的个数,才能保证先进先出
public static void jizhuSort(int[] arr) { //产生10个桶 queue[] bar = new queue[10]; for (int i = 0; i < bar.Length; i++) { bar[i] = new queue(); } bool go = true; for (int k = 0; go ; k++) { int O = 0; //所有数字存入桶中,第一次 for (int i = 0; i < arr.Length; i++) { for (int j = 0; j < bar.Length; j++) { int a = (int)(arr[i] / Math.Pow(10, k)) % 10; if (a == j) { if (j != 0) O = j; bar[j].add(arr[i]); } } } //取出所有数字 for (int i = 0,m = 0; i < bar.Length; i++) { while (!bar[i].isempty()) { arr[m++] = bar[i].push(); } } if (O == 0) go = false; } }