相关使用的工具类与接口
运行效率
/**
* 这是一个快速排序
* 数组长度[2000] 值范围[1-2000] 消耗的时间为[1]毫秒
* 数组长度[4000] 值范围[1-4000] 消耗的时间为[1]毫秒
* 数组长度[8000] 值范围[1-8000] 消耗的时间为[1]毫秒
* 数组长度[16000] 值范围[1-16000] 消耗的时间为[1]毫秒
* 数组长度[32000] 值范围[1-32000] 消耗的时间为[1]毫秒
* 数组长度[64000] 值范围[1-64000] 消耗的时间为[3]毫秒
* 数组长度[128000] 值范围[1-128000] 消耗的时间为[6]毫秒
* 数组长度[256000] 值范围[1-256000] 消耗的时间为[16]毫秒
* 数组长度[512000] 值范围[1-512000] 消耗的时间为[35]毫秒
* 数组长度[1024000] 值范围[1-1024000] 消耗的时间为[71]毫秒
* 数组长度[2048000] 值范围[1-2048000] 消耗的时间为[153]毫秒
* 数组长度[4096000] 值范围[1-4096000] 消耗的时间为[325]毫秒
* 数组长度[8192000] 值范围[1-8192000] 消耗的时间为[675]毫秒
* 数组长度[16384000] 值范围[1-16384000] 消耗的时间为[1397]毫秒
* 数组长度[32768000] 值范围[1-32768000] 消耗的时间为[2890]毫秒
* 数组长度[65536000] 值范围[1-65536000] 消耗的时间为[6031]毫秒
* 数组长度[131072000] 值范围[1-131072000] 消耗的时间为[12727]毫秒
* 数组长度[262144000] 值范围[1-262144000] 消耗的时间为[25993]毫秒
* <p>
* Process finished with exit code 0
*/
@Test
public void quickSortTest() {
ArraysSort arraysSort = new QuickSortMethod();
SortHelper.arraySort(arraysSort, 2000, 20);
}
实现代码
public static final Random RANDOM = new Random();
@Override
public String getSortName() {
return "这是一个快速排序";
}
@Override
public int[] arraySortMethod(int[] ints) {
sort(ints, 0, ints.length - 1);
return ints;
}
/**
* 最初的快排算法逻辑
*
* @param ints 整个数组
* @param l 当前最小索引
* @param r 当前最大索引
*/
private int quickSort(int[] ints, int l, int r) {
//这里以每个l记录进行比较
//但是这里有个问题
//在快速排序处理近乎有序的数组时 如果默认选取的是最左侧索引节点
//这样会造成左分块除了l近乎没有,右分块又会出现很多
//以此循环会造成递归树非常深 递归树的深度可能就无限接近于n长度
//如果是这样的话 该排序的时间效率就无限接近n^2
//每次随机选取l-r一个索引 与l 索引进行交换就解决了该问题
SortHelper.swap(ints, l, RANDOM.nextInt(r - l + 1) + l);
int v = ints[l];
//初始化开始记录比v小和比v大的中间索引点
//j理论上记录的是比v小的最大索引
int j = l;
for (int i = l + 1; i <= r; i++) {
//如果出现比v小的情况
//就需要做交换 移动j的索引后移一格
if (ints[i] < v) {
//每次j+1=比v大一边的第一个索引
//让大一边第一个索引和当前循环到的这个索引做交换
//以上交换后j+1=比v小一边的最后一个索引
//之前比v大一边的第一个索引就跑到i索引下 也是当时大一边的最后一个索引
SortHelper.swap(ints, ++j, i);
}
}
//到这里j记录的就是比v小一边的最大索引
//以上循环完成后就可以确定l索引在ints数组中排序的位置
SortHelper.swap(ints, j, l);
//返回l在ints中排好序确定的索引位置 并以j分割继续递归排序
return j;
}
/**
* 最初的快排算法逻辑
*
* @param ints
* @param l
* @param r
*/
public void sort(int[] ints, int l, int r) {
//在出现左索引等于右索引的时候
//它们都是指向同一索引所以没有相比的必要
//这里直接返回
// if (l >= r) {
// return;
// }
//在数据量较小的时候使用插入排序
//这是因为经过了r-l>15的快速排序后 小一边和大一边的模糊排序后
//在r-l<=15 的时候之间的最大差已经很小了
//在最大差越小的情况下顺序可能是越有序的
//说不定已经近乎有序的了 优化的快速排序对近乎有序的排序效率非常高
//优化后的插入排序对近乎有序的数组进行效率相对较高
//插入排序相对归并排序减少了数组交换的过程
if (r - l <= 15) {
InsertSortMethod.insertSortMethod(ints, l, r);
return;
}
//个人理解快排核心
//每次遍历排序对l-r之间的数组进行区分
//好处1.每次遍历可以定位一个p索引在ints数组中确定的位置
//好处2.因为每次排序都对l-r之间的数据进行大小划分做了一次模糊的排序
//保证下次排序l-r排序之间最大差越来越小
//所以下次遍历都比上次排序更加有序效率相对更快
int p = quickSort(ints, l, r);
//以p中心点-1和+1为界限继续递归快速排序
sort(ints, l, p - 1);
sort(ints, p + 1, r);
}