转载既然注明出处了,就厚颜无耻的列出其代码实现和图解吧!
因为原文言简意赅,我这里加了一些自己的理解,可能废话,但起码有益于我自己理解~
快速排序采用分而治之的思想,实现步骤是:
- 确定中心元素, 将中心元素与表的第一个元素交换
索引smallIndex初始化为表中第一个元素,指向小于中心元素的lower sublist的最后一个元素(见图解第2步示意)。- 对表中剩余元素
剩余元素指的是除了中心元素、已经被划分到lower sublist和upper sublist之外剩余的元素。
如果当前元素
(index所指向的元素,剩余元素中下标最小的元素,见图解第2步示意)小于中心元素,则需要将它挪到lower sublist这一阵营。操作步骤是:
a.smallIndex加一,挪个位置出来;
b.交换当前元素
和由 smallIndex所指向的数组元素。
因为,smallIndex挪出的位置被upper sublist的第一个元素占用着,这么一交换,upper sublist的第一个元素就成了upper sublist阵营的的最后一个元素,这也难怪说快速排序不稳定。
如果当前元素
大于中心元素,只需将当前元素index向后挪动一位,这个当前元素自然落入upper sublist阵营(见图解第3步示意)。- 交换第一个元素(即中心元素)和由smallIndex指向的数组元素
当所有元素都划分到lower sublist和upper sublist两大阵营,就要将此时居于首位的中心元素放回到它应该在的位置,即两大阵营正中间,让左边的数都比它小,右边的数都比它大(见图解第4步和第5步示意)- 这一轮排序结束了,然后分别针对lower sublist和upper sublist再次进行类似的操作。直到lower和upper被分解为最小粒度——一个元素。
最后再附上这位前辈的代码(真的是前辈,因为是2010年的博客。。):
public class QuickSort {
public static int partition(int arr[], int start, int end) {
int pivot;
int index, smallIndex;
swap(arr, start, (start + end) / 2);
pivot = arr[start];// center element
smallIndex = start;
for (index = start + 1; index <= end; index++) {
if (arr[index] < pivot) {
smallIndex ++ ;
swap(arr, smallIndex, index);
}
}
swap(arr, start, smallIndex);//recover center element’position
return smallIndex;
}
public static void swap(int[] arr, int n1, int n2) {
int temp;
temp = arr[n1];
arr[n1] = arr[n2];
arr[n2] = temp;
}
public static void quickSort(int arr[], int start, int end) {
int pivotLocation;
if (start < end) {
pivotLocation = partition(arr, start, end);
quickSort(arr, start, pivotLocation - 1);//recursion
quickSort(arr, pivotLocation + 1, end);
}
}
}
以上是快速排序涉及的基本的技术点,关于时间复杂度、空间复杂度的分析,以及使用场合、在Android开发中的应用、与其他排序方式的比较,后续再补上。
快排算法的特点:
- 实用性强
很多实际的项目中使用了快排算法。但通常对算法都进行了调整(tuning),比如Java.util.Arrays类中的sort函数就使用了快排算法,但使用了双参考值(Dual-Pivot Quicksort)等一些改进措施。由于快排算法为递归算法,可以用循环代替递归函数调用,改进性能。
- 不需要额外空间
可以将数组中的数据直接交换位置实现排序,所以理论上不需要额外的空间。
- 升序排列
- 不稳定排序
时间复杂度:
- 平均情况:O(nlgn)
- 最坏情况:O(n*n),发生在当数据已经是排序状态时
使用泛型实现快排算法:
- 对任意类型数组进行排序。如果为对象类型数组,则该对象类型必须实现Comparable接口,这样才能使用compareTo函数进行比较。
注:对比了前人的代码实现,发现思想一样,实现都略有不同,涉及到代码的包装、处理对象的多态、边界条件的处理细节等。以后有心得再扩充对比。