稳定性定义:排序前后两个相等的数相对位置不变,则算法稳定。
稳定性得好处:从一个键上排序,然后再从另一个键上排序,第一个键排序的结果可以为第二个键排序所用。
稳定的:
1.插入排序(O(n*n)):将一个元素插入到已经排好序的列表中
public void selectionSort(int[] a) { if (null ==a || a.length < 2) { return; } for (int i = 1; i < a.length; i++) { int temp = a[i]; // 暂存 int j = i - 1; while (j >= 0 && temp < a[j]) { a[j+1] = a[j]; j--; } a[j+1] = temp; } }
2.冒泡排序(O(n*n)):相邻两个元素比较大小进行交换,一趟冒泡后会有一个元素到达最终位置
public void bubbleSort(int[] a) { if (null == a || a.length < 2) { return; } boolean flag; for (int i = 0; i < a.length - 1; i++) { flag = false; for (int j = 0; j < a.length - 1 - i; j++) { if (a[j] > a[j+1]) { int temp = a[j]; a[j] = a[j+1]; a[j+1] = temp; flag = true; } if (flag == false) { return; } } } }
3.归并排序(nlogn):两个有序序列的合并,方法:分治 + 递归
public static int[] sort(int[] nums, int low, int high) { int mid = (low + high) / 2; if (low < high) { // 左边 sort(nums, low, mid); // 右边 sort(nums, mid + 1, high); // 左右归并 merge(nums, low, mid, high); } return nums; } /** * 将数组中low到high位置的数进行排序 * @param nums 待排序数组 * @param low 待排的开始位置 * @param mid 待排中间位置 * @param high 待排结束位置 */ public static void merge(int[] nums, int low, int mid, int high) { int[] temp = new int[high - low + 1]; int i = low;// 左指针 int j = mid + 1;// 右指针 int k = 0; // 把较小的数先移到新数组中 while (i <= mid && j <= high) { if (nums[i] < nums[j]) { temp[k++] = nums[i++]; } else { temp[k++] = nums[j++]; } } // 把左边剩余的数移入数组 while (i <= mid) { temp[k++] = nums[i++]; } // 把右边边剩余的数移入数组 while (j <= high) { temp[k++] = nums[j++]; } // 把新数组中的数覆盖nums数组 for (int k2 = 0; k2 < temp.length; k2++) { nums[k2 + low] = temp[k2]; } }
不稳定:
1.希尔排序(n的1.3次方):按步长进行分组,组内直接插入,缩小增量再次进行此步骤,增量为1时相当于一次直接插入
public void shellSort(int[] a) { if (null == a || a.length < 2) { return; } for (int d = a.length/2; d > 0; d/=2) { for (int i = d; i < a.length; i++) { // 内部直接插入 int temp = a[i]; int j = i - d; while (j >= 0 && temp < a[j]) { a[j+d] = a[j]; j -= d; } a[j+d] = temp; } } }
2.选择排序(n*n):每次从无序序列选择一个最小的与第一个元素交换,再从剩下的里面找最小的和第二个元素交换。。
public void selectSort(int[] a) { if (null == a || a.length < 2) { return; } for (int i = 0; i < a.length; i++) { int k = i; for (int j = i + 1; j < a.length; j++) { if (a[j] < a[k]) { k = j; } } if (k != i) { int temp = a[k]; a[k] = a[i]; a[i] = temp; } } }
3.快速排序(nlogn):通过一趟排序将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分关键字小,则分别对这两部分继续进行排序,直到整个序列有序。
public void quickSort(int[] a, int low, int high) { if (low < high) { int mid = partition(a, low, high); quickSort(a, low, mid - 1); quickSort(a, mid + 1, high); } } private int partition(int[] a, int low, int high) { int pivot = a[low]; while (low < high) { while (low < high && a[high] >= pivot) { high--; } a[low] = a[high]; while (low < high && a[low] <= pivot) { low++; } a[high] = a[low]; } a[low] = pivot; return low; }
4.堆排序(nlogn):利用堆的特性,建堆,调整堆
// 堆排序 public void heapSort(int[] a) { if (null == a || a.length < 2) { return; } buildMaxHeap(a); for (int i = a.length - 1; i >= 0; i--) { int temp = a[0]; a[0] = a[i]; a[i] = temp; adjustHeap(a, i, 0); } } // 建堆 private void buildMaxHeap(int[] a) { for (int i = a.length/2; i >= 0; i--) { adjustHeap(a, a.length, i); } } // 调整堆 private void adjustHeap(int[] a, int size, int parent) { int left = 2 * parent + 1; int right = 2 * parent + 2; int largest = parent; if (left < size && a[left] > a[largest]) { largest = left; } if (right < size && a[right] > a[largest]) { largest = right; } if (parent != largest) { int temp = a[parent]; a[parent] = a[largest]; a[largest] = temp; adjustHeap(a, size, largest); } }