对排序实现的总结,以下都是基于升序排序[1,2,3…]:
插入排序:
两层循环嵌套,第一层从第二位开始,index逐步递增;
第二层,innerIndex从index-1逐步递减,,在index之前都为有序,如果data[innerIndex] > data[index]
,则innerIndex++
腾出位置(这是插入排序的特点),一直到条件失败,退出内存循环,交换innerIndex 跟index。平均时间复杂度为O(n^2)
归并排序: 递归实现,先逐层一分为二,一直到只有一个数字,然后把拆解出来的数字逐层合并回来。复杂度分解为二叉树,合并为倒二叉树,时间复杂度为O(nlogn)
快速排序:快速排序的特点是取一个值为参考值pivot,小于pivot的在左边,大于pivot的在右边,这样左边的数据就不需要跟右边的数据比较,效率明显提高。但是,极端情况下,取得pivot一边都是只有一个值,就退化为另一边都是满数据,退化为冒泡排序了。为了逆序导致的复杂度退化为O(n^2), 这里用三者取中值法,来实现快速排序。平均时间复杂度为O(nlogn).
堆排序:堆实际为完全二叉树,也就是用数组为容器。
大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i+2]
先建大顶堆,然后把顶端的值跟最后的值交换,堆大小减一,再次构建大顶堆。重复以上步骤,一直到堆减少为空,数组就是一个递增序列。
分析复杂度:建堆的时候,从节点开始遍历,length/2 - 1
为index最大的节点,因为叶子节点2*(length/2 - 1) + 1 = length -1
, 反证法如果length/2为index最大的节点,那么叶子节点2*(length/2) + 1 = length +1
, 超过容量。建堆每个节点排序时间复杂度为O(logn), 所以建堆复杂度为n/2 * logn; 每次去掉最大值再次建堆,时间复杂度小于 n* logn。 两个过程的和小于3n/2 *logn, 时间复杂度为O(nlogn).
import java.util.Arrays;
public class InsertionSort {
public void insertSort(int[] data) {
for (int i = 1; i < data.length; i++) {
int currentNumber = data[i];
int j = i - 1;
while (j >= 0 && data[j] > currentNumber) {
data[j + 1] = data[j];
j--;
}
data[j+1] = currentNumber;
}
}
public static void main(String[] args) {
int[] data = new int[]{4, 6, 5, 3, 7, 1, 2};
System.out.println(Arrays.toString(data));
InsertionSort obj = new InsertionSort();
obj.insertSort(data);
System.out.println(Arrays.toString(data));
}
}
import java.util.Arrays;
public class MergeSort {
public void mergeSort(int[] data) {
int[] temp = new int[data.length];
subMergeSort(data, 0, data.length - 1, temp);
}
public void subMergeSort(int[] data, int left, int right, int[] temp) {
if (left < right) {
int mid = left + (right - left) / 2;
subMergeSort(data, left, mid, temp);
subMergeSort(data, mid + 1, right, temp);
merge(data, left, mid, right, temp);
}
}
public void merge(int[] data, int left, int mid, int right, int[] temp) {
int i = left;
int k = mid + 1;
int t = 0;
while (i <= mid && k <= right) {
if (data[i] < data[k]) {
temp[t++] = data[i++];
} else {
temp[t++] = data[k++];
}
}
while (i <= mid) {
temp[t++] = data[i++];
}
while (k <= right) {
temp[t++] = data[k++];
}
t = 0;
while (left <= right) {
data[left++] = temp[t++];
}
}
public static void main(String[] args) {
int[] data = new int[]{4, 6, 5, 3, 7, 1, 2};
System.out.println(Arrays.toString(data));
MergeSort obj = new MergeSort();
obj.mergeSort(data);
System.out.println(Arrays.toString(data));
}
}
import java.util.Arrays;
public class QuickSort {
public static void quickSort(int[] data) {
// divide to left, right index
subQuickSort(data, 0, data.length - 1);
}
public static void subQuickSort(int[] data, int leftIndex, int rightIndex) {
if (leftIndex >= rightIndex) {
return;
}
// pivot data: mid of the three number, and swap to right -1
buildPivotCloseToRight(data, leftIndex, rightIndex);
int i = leftIndex;
int k = rightIndex - 1;
int pivot = data[k];
// two point from two side, ++left, --right
while (true) {
// while ++left > pivot
while ((i+1) < rightIndex && data[++i] < pivot) {
}
// while --right < pivot
while ((k - 1) > leftIndex && data[--k] > pivot) {
}
// left < right, then swap
if (i < k) {
swap(data, i, k);
} else {
break;
}
}
// if left < pivotIndex ,swap
if (i < rightIndex - 1) {
swap(data, i, rightIndex - 1);
}
// divide two sub quick sort
subQuickSort(data, leftIndex, i);
subQuickSort(data, i + 1, rightIndex);
}
public static void buildPivotCloseToRight(int[] data, int leftIndex, int rightIndex) {
int midIndex = leftIndex + (rightIndex - leftIndex) / 2;
// swap small in left, between left, mid
if (data[leftIndex] > data[midIndex]) {
swap(data, leftIndex, midIndex);
}
// swap small in left, between left, right
if (data[leftIndex] > data[rightIndex]) {
swap(data, leftIndex, rightIndex);
}
// swap big in right, between mid, right
if (data[midIndex] > data[rightIndex]) {
swap(data, midIndex, rightIndex);
}
// swap pivot int right -1
swap(data, midIndex, rightIndex - 1);
}
public static void swap(int[] data, int i, int k) {
int temp = data[i];
data[i] = data[k];
data[k] = temp;
}
public static void main(String[] args) {
int[] data = new int[]{4, 6, 5, 3, 7, 1, 2};
System.out.println(Arrays.toString(data));
quickSort(data);
System.out.println(Arrays.toString(data));
}
}
import java.util.Arrays;
public class HeapSort {
public static void heapSort(int[] data) {
// build top big heap
for (int i = data.length/2 -1; i >= 0; i--) {
// build heap
buildHeap(data, i, data.length);
}
// change seat between the first and the last, length--
for (int k = data.length - 1; k >=0; k--) {
// change seat between first and last one
swap(data, 0, k);
// build heap
buildHeap(data, 0, k);
}
}
public static void buildHeap(int[] data, int nodeIndex, int length) {
int temp = data[nodeIndex];
for (int k = nodeIndex * 2 + 1; k < length; k = k * 2 + 1) {
if (k + 1 < length && data[k] < data[k + 1]) {
k = k + 1;
}
if (data[k] > temp) {
data[nodeIndex] = data[k];
nodeIndex = k;
} else {
break;
}
}
data[nodeIndex] = temp;
}
public static void swap(int[] data, int i, int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
public static void main(String[] args) {
int[] data = new int[]{4, 6, 5, 3, 7, 1, 2};
System.out.println(Arrays.toString(data));
heapSort(data);
System.out.println(Arrays.toString(data));
}
}
[4, 6, 5, 3, 7, 1, 2]
[1, 2, 3, 4, 5, 6, 7]
排序实现一遍,bug free不容易,不信,请您试试?
代码下载:
https://github.com/zgpeace/awesome-java-leetcode/blob/master/code/LeetCode/src/popular/Sorting/InsertionSort.java
https://github.com/zgpeace/awesome-java-leetcode/blob/master/code/LeetCode/src/popular/Sorting/MergeSort.java
https://github.com/zgpeace/awesome-java-leetcode/blob/master/code/LeetCode/src/popular/Sorting/QuickSort.java
https://github.com/zgpeace/awesome-java-leetcode/blob/master/code/LeetCode/src/popular/Sorting/HeapSort.java
参考:
https://www.cnblogs.com/chengxiao/p/6103002.html
https://www.cnblogs.com/chengxiao/p/6194356.html
https://www.cnblogs.com/chengxiao/p/6262208.html
https://www.cnblogs.com/chengxiao/p/6129630.html
https://zh.wikipedia.org/wiki/排序算法