1. 随机快速排序(不稳定)
- l + (int) (Math.random() * (r - l + 1)) 解析:
- 假设 l = 4,r = 9
- 目的:随机选择 4 ~ 9 之间的一个数,使它与末尾的数交换位置
- Math.random() * ( 9 - 4 )所得出的范围是 [ 0 , 4 ]
- Math.random() * ( 9 - 4 + 1 )所得出的范围是 [ 0 , 5 ] ,所以这里采用 r - l + 1
- l + (int) (Math.random() * (r - l + 1)) 表示的则是 [ 4 , 9 ] 之间的数,符合题意
- partition 方法的作用是先将与所选随机值相同的值放在一起,然后得到它们的范围。假设是 1,3,4,5,5,5,5,6,8 ,则 p[0] 表示第一个5,p[1] 表示最后一个5
- if (arr[l] < arr[r]) { swap(arr, ++less, l++ ); 这一步交换的意义是:当前面找到和 5 相同的值时,l++,那么后面执行这个交换操作可以把前面找到的 5 往后面移,以此将5移动到一块。
- less 表示小于 5 的区域,最开始里面是空,所以 less = l-1
- more 表示大于 5 的区域,最开始里面只有最右边的值(5),所以 more = r 。循环结束后通过 swap(arr, more, r); 将最后面的 5 加入到前面集结好的 555 的末尾处。
- 由于是随机在中间取的值(假设是5)与末尾值进行的交换,然后用这个末尾值开始普通快排,所以它的时间复杂度是 O(nlogn) 。
- 快排常数项的操作和数量很少,所以它被广泛使用。
public class QuickSort {
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
int[] p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1);
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
swap(arr, ++less, l++);
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);
} else {
l++;
}
}
swap(arr, more, r);
return new int[]{less + 1, more};
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
QuickSort sort = new QuickSort();
int[] arr = {5, 3, 5, 6, 1, 4, 5, 8, 5};
sort.quickSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}
2. 堆排序(不稳定)
public class HeapSort {
public static void heapSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
int size = arr.length;
swap(arr, 0, --size);
while (size > 0) {
heapify(arr, 0, size);
swap(arr, 0, --size);
}
}
public static void heapInsert(int[] arr, int index) {
while (arr[index] > arr[(index - 1) / 2]) {
swap(arr, index, (index - 1) / 2);
index = (index - 1) / 2;
}
}
public static void heapify(int[] arr, int index, int size) {
int left = index * 2 + 1;
while (left < size) {
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index) {
break;
}
swap(arr, largest, index);
index = largest;
left = index * 2 + 1;
}
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
public static void main(String[] args) {
HeapSort a = new HeapSort();
int[] arr = {3, 2, 4, 5, 9, 6, 4, 7, 8, 4, 1};
a.heapSort(arr);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
}
}
3.插入排序(稳定)
- 将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序,时间复杂度为O(n2)。是稳定的排序方法。类似于玩扑克牌,手里的牌都排好序了,每抽一张牌时便将它插入到合适的位置,使手里的扑克牌一直有序。
4.选择排序(不稳定)
- 每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,然后,再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。以此类推,直到全部待排序的数据元素排完。 选择排序是不稳定的排序方法。