今天偶然看到一篇快速排序算法的帖子,顺带学习了一下算法源码。
快速排序算法(QuickSort)主要采用分治法策略。它的基本思路是选择一个“基准”元素,通过一趟排序将待排序序列分成两部分,其中一部分的所有元素都比基准元素小,另一部分的所有元素都比基准元素大,然后递归地对这两部分进行排序。
这里把算法源码贴出来,有兴趣的同学可以去看一下:
public class QuickSortExample {
public static void main(String[] args) {
int[] arr = {18, 27, 8, 12, 1, 9, 15, 23};
int n = arr.length;
System.out.println("排序前:");
printArray(arr);
quickSort(arr, 0, n - 1);
System.out.println("排序后:");
printArray(arr);
}
/**
* 快速排序主方法
*/
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
// 获取分区索引
int pi = partition(arr, low, high);
// 递归排序左子数组
quickSort(arr, low, pi - 1);
// 递归排序右子数组
quickSort(arr, pi + 1, high);
}
}
/**
* 分区
*/
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high]; // 选择最后一个元素作为基准
int i = low - 1; // i是小于基准的元素的索引
for (int j = low; j < high; j++) {
// 如果当前元素小于或等于基准
if (arr[j] <= pivot) {
i++;
// 交换arr[i]和arr[j]
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
// 交换arr[i+1]和基准元素
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1; // 返回分区索引
}
// 打印数组
private static void printArray(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}
看完之后我就在想,平时工作中遇到有排序需求的时候直接就用Stream写完了,那叫一个顺畅。这个快速排序算法对于基本功不怎么样的同学来说理解起来确实有难度,那它相对于Stream的排序提升有多大呢。越想越觉得有趣,不如干脆测试一下。
思路很简单,生成随机数数组,喂给两种方式排序,分别记录开始时间和结束时间,相减得到一组结果。由于是在认真工(mo)作(yu)期间,数据组不敢测试多了,就每组测了三次,取均值保留两位小数得到以下结果:
public class QuickSortExample {
/**
* 排序PK:每组3次取平局值,保留两位
* 1.测试1w条数据,stream耗时:45.66毫秒,快速排序算法耗时:0毫秒
* 2.测试10w条数据,stream耗时:74.33毫秒,快速排序算法耗时:5.33毫秒
* 3.测试100w条数据,stream耗时:185.33毫秒,快速排序算法耗时:78.66毫秒
* 4.测试1000w条数据,stream耗时:1050.66毫秒,快速排序算法耗时:897毫秒
*/
public static void main(String[] args) {
int size = 10000000;
// 生成数组
int[] arr = generateArray(size);
int[] quickSortArray = arr.clone();
// stream排序耗时
long streamStart = System.currentTimeMillis();
int[] streamResult = Arrays.stream(arr).sorted().toArray();
long streamEnd = System.currentTimeMillis();
System.out.println(size + "条数据,stream排序耗时:" + (streamEnd - streamStart) + "ms");
// 快速排序算法耗时统计:
long quickSortStart = System.currentTimeMillis();
quickSort(quickSortArray, 0, quickSortArray.length - 1);
long quickSortEnd = System.currentTimeMillis();
System.out.println(size + "条数据,快速排序算法耗时:" + (quickSortEnd - quickSortStart) + "ms");
}
}
结果自然是快速排序算法全部都快于Stream API的方式。仔细观察数据结果发现,数组比较小的时候快速排序算法是“大幅领先”Stream API的,但是差距也就那几十来毫秒,数组数据量增大时,差距反而在缩小,这就很有意思了。
对于这个测试结果我也是很意外,原本认为快速排序算法能大幅领先Stream API,但实际上并不是的。问了一下AI:
在大多数情况下,快速排序和Stream排序都能提供O(n log n)的时间复杂度。然而,在具体应用中,选择哪种排序方式取决于多个因素,包括数组规模、内存使用限制、代码可读性和灵活性等。如果需要高性能排序且对内存使用有严格要求,快速排序可能是一个更好的选择。而如果需要简洁代码和声明式编程风格,或者需要与其他流式处理操作结合使用,那么Stream排序则更为合适。
大家可以参考AI的推荐使用哪种算法来排序。平时工作遇到的那点排序需求还是直接Stream淦就完事了,至于这个快速排序算法就作为面试时的谈资罢了。