快速排序的算法思想在大二学习数据结构的时候就有了解,只是一直都不能做到熟练地代码实现,最近一段时间在看基础的排序、查找算法,下面进行总结:
代码思想
1、基本思想是:通过一趟排序将待排元素(一般选择数组存放)分隔成独立的三部分:“中间值”、小于“中间值”的部分、大于“中间值”的部分。之后,分别对小于“中间值”的部分、大于“中间值”的部分,进行相同的排序,直至最终所有的待排序元素都变得有序为止。
2、用到的算法思想:递归
3、实现原理:(大致思路,具体实现时可能略有差异)
[1]循环体内的部分(排序时进行的操作):
(1)在每一次排序时,选择“一个‘中间值’(base),两个指针”:每次进行排序的时候,选择一个数作为排序的参照值base(通常选择目前待排序列的第一个元素);确定两个指针------一个指针 low (指向待排序列的第一个元素),一个指针 high (指向待排序列的最后一个元素)。
(2)让 low 指针在待排序列中从前往后遍历,直至遍历到第一个比 base 值大的元素为止;让 high 指针指向待排序列的最后一个元素,让 high 指针从后向前遍历,直至遍历到第一个比 base 小的元素为止。
(3)如果此时满足: high > low,则交换 high 与 low 位置上对应的元素,直至出现 high < low,结束此次的循环。
[2]循环体外:
(4)结束循环之后,将此时的 base 与 high 交换对应位置上的元素,并将它定为 middle 。
(因为循环结束的时候,实际上也是找到了:low比 base 值大,high比 base 小,所以此时将 base 与 high 指向的元素互换,才可以保证:middle 左侧的元素都小于等于 middle,middle右侧的元素都大于等于 base )。
(5)之后,调用该函数本身,对middle左侧、右侧的元素序列进行排序(就是递归的过程)。
注意的是:此时middle的位置已经确定了,不需要再挪动,所以不需要再参与排序。
代码实现
import java.util.Arrays;
public class QuickSort {
/*
* 交换数组元素值的方法
*/
private static void swap(int[] data,int i,int j) {
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
/*
* 快排的核心方法------递归的部分
*/
private static void subSort(int[] data,int start,int end) {
/*
* 这里的条件是递归的 终止条件
*/
if(start < end ) {
/*
* 这里以序列的 第一个元素作为每次排序的基准
*/
int base = data[start];
/*
* 让low指针指向当前序列的第一个元素
* high指针指向当前序列的最后一个元素+1(最后一个元素后边的位置)
* ------
* 其实,high应该指向当前序列的最后一个元素,
* 但是因为考虑到下边的while循环中,每次从后往前遍历的时候,都是先将high指针自减1,然后才进行判断,
* 所以应该在每次 刚进循环的时候将high的值置为:序列的最后一个元素后边的位置
*
*/
int low = start;
int high = end+1;
/*
* 应该注意的是:在每次查找符合要求的下标值low、high的过程中
* 除了应该保证,low对应的值 > base,high对应的值 < base之外,
* 还应该保证 索引下标“不越界”
* ------“不越界”指的是不越 当前正在进行排序的 序列的下标 对应的范围
*/
while(true) {
/*
* 每次查找的时候,
* 让 low 指针在待排序列中从当前low 指针对应的索引值开始,从前往后遍历,
* 在这个过程中需要保证 下标不越界--------low < end,
* ----即,low指针对应的索引值,最大 也应该小于当前排序序列的最后一个元素对应的索引值,
* --这是因为,即使:序列中的最后一个元素的值 大于当前的base值(所选取的基准元素),也不用进行swap()操作
* 直至遍历到第一个比 base 值大的元素为止
*/
while(low < end && data[++low] - base <= 0);
/*
* 每次查找的时候,
* 让 high 指针在待排序列中从当前high 指针对应的索引值开始,从后往前遍历,
* 在这个过程中需要保证 下标不越界----------high > start,
* ----即,high 指针对应的索引值,最小 也应该大于当前排序序列的最前边一个元素对应的索引值,
* --这是因为,所选取的base值(所选取的基准元素),即为当前序列
* 直至遍历到第一个比 base 值大的元素为止
*/
while(high > start && data[--high] - base >= 0);
if(low < high) {
/*
* 当找出来的符合要求的元素 对应的索引值
* 满足:没有出现交叉重叠
* 交换low、high 上对应的元素
*/
swap (data,low,high);
}else {
/*
* 进行到当前这一步的时候,有一个前提就是:
* 此时 找出来的符合要求的元素 对应的下标值,已经出现了交叉重叠
* 所以------表明当前序列的排序已经进行完毕
* ----------->跳出外层的while循环
*/
break;
}
}
/*
* 交换当前的基准元素(base) 与 退出外层while循环时,
* high指针 对应的元素(middle)
* -------
* 实现“中值归位”
* -------
* 为进一步的递归序列的划分提供依据
*/
swap(data,start,high);
/*
* 对于middle(刚刚确定了 最终位置的“中值”)左边的序列进行递归排序
*/
subSort(data,start,high-1);
/*
* 对于middle(刚刚确定了 最终位置的“中值”)右边的序列进行递归排序
*/
subSort(data,high+1,end);
}
}
public static void quickSort(int[] data) {
/*
* 第一次调用排序
* (快速排序算法的启动)
*/
subSort(data,0,data.length-1);
}
public static void main(String[] args) {
int[] data = new int[]{9,-36,30,23,-30,-49,25,21,30};
System.out.println("输出排序之前的数组:\n" + Arrays.toString(data));
quickSort(data);
System.out.println("排序之后的数组:\n"+Arrays.toString(data));
}
}
代码总结
快速排序的
平均时间复杂度为:O(nlogn)
最坏时间复杂度:O(n^2)