归并排序、快速排序、堆排序
/**
* 归并排序是建立在归并操作上的一种有效的排序算法。
* 该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。
* 将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。
* 若将两个有序表合并成一个有序表,称为2-路归并。
* <p>
* 算法描述:
* 1.把长度为n的输入序列分成两个长度为n/2的子序列;
* 2.对这两个子序列分别采用归并排序;
* 3.将两个排序好的子序列合并成一个最终的排序序列。
*
* @param randomInts
*/
private static int[] mergeSort(int[] randomInts) {
int length = randomInts.length;
if (length < 2) {
return randomInts;
}
int middleIndex = (int) Math.floor(length / 2);
int[] left = Arrays.copyOfRange(randomInts, 0, middleIndex);
int[] right = Arrays.copyOfRange(randomInts, middleIndex, length);
return merge(mergeSort(left), mergeSort(right));
}
private static int[] merge(int[] left, int[] right) {
int leftIndex, rightIndex, resultIndex;
int leftLength, rightLength;
leftIndex = rightIndex = resultIndex = 0;
leftLength = left.length;
rightLength = right.length;
int[] result = new int[leftLength + rightLength];
while (leftIndex < leftLength && rightIndex < rightLength) {
result[resultIndex++] = left[leftIndex] < right[rightIndex] ? left[leftIndex++] : right[rightIndex++];
}
if (leftIndex < leftLength) {
System.arraycopy(left, leftIndex, result, resultIndex, leftLength - leftIndex);
} else if (rightIndex < rightLength) {
System.arraycopy(right, rightIndex, result, resultIndex, rightLength - rightIndex);
}
return result;
}
private static void swap(int[] a, int i, int j) {
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
private static int partition(int[] a, int left, int right) {
int pivot = left;
int index = pivot + 1;
for (int i = index; i <= right; i++) {
if (a[pivot] > a[i]) {
swap(a, i, index);
index++;
}
}
swap(a, index - 1, pivot);
return index - 1;
}
/**
* 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,
* 其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。
*
* 算法描述
* 快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:
* 1.从数列中挑出一个元素,称为 “基准”(pivot);
* 2.重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。
* 在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
* 3.递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。
* @param randomInts
* @param left
* @param right
*/
private static void quickSort(int[] randomInts, int left, int right) {
if (left < right) {
int partitionIndex = partition(randomInts, left, right);
quickSort(randomInts, left, partitionIndex - 1);
quickSort(randomInts, partitionIndex + 1, right);
}
}
private static void buildMaxHeap(int[] a) {
int length = a.length;
for (int i = (int) Math.floor(length / 2); i >= 0; i--) {
heapAdjust(a, 0, length);
}
}
private static void heapAdjust(int[] a, int parentIndex, int length) {
int leftIndex = parentIndex * 2 + 1;
int rightIndex = parentIndex * 2 + 2;
int largest = parentIndex;
if (leftIndex < length && a[leftIndex] > a[largest]) {
largest = leftIndex;
}
if (rightIndex < length && a[rightIndex] > a[largest]) {
largest = rightIndex;
}
if (largest != parentIndex) {
swap(a, largest, parentIndex);
heapAdjust(a, largest, length);
}
}
/**
* 堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。
* 堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。
*
* 算法描述:
* 1.将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
* 2.将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
* 3.由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,
* 然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。
* 不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。
* @param a
*/
private static void heapSort(int[] a) {
buildMaxHeap(a);
int length = a.length;
for (int i = length - 1; i > 0; i--) {
swap(a, 0, i);
length--;
heapAdjust(a, 0, length);
}
}
参考文档
十大经典排序算法(动图演示)