简介
快速排序由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。—–百度百科
其主要原理是每次都能确定一个元素的确定位置。
时间复杂度 好情况(无序) O(nlog2n) 怀情况(有序)O(n^2)
每次Partition O(n^2)
递归方式代码
/** * 快速排序主函数 * @param array */
public static void quickSort(int[] array)
{
//第一次调用快排
Quick(array, 0, array.length-1);
}
/** * 返回基准下标,相当于每次为一个元素找到其位置,将数组分为两部分 * @param array 数组 * @param start 开始下标 * @param end 结束下标 * @return 基准下标 */
public static int partion(int[] array,int low,int hight)
{
//找到一个基准
int temp = array[low];
//遍历直到所有遍历完
while(low<hight)
{
//从右向左找比temp小的
while(low<hight&&array[hight]>=temp)
{
--hight;
}
//如果相遇了,或交错了,直接跳出
if(low>=hight)
{
break;
}
//如果符合条件,将小的放到当前low的位置。
else
{
array[low] = array[hight];
}
//从左向右找比temp大的
while(low<hight&&array[low]<=temp)
{
++low;
}
//如果遍历完了,跳出
if(low>=hight)
{
break;
}
//如果符合条件,将大的放到当前hight位置
else
{
array[hight] = array[low];
}
}
//将基准放入low
array[low] = temp;
//返回low
return low;
}
/** * 快速排序递归 * @param array 数组 * @param start 开始下标 * @param end 结束下标 */
public static void Quick(int[] array,int start,int end)
{ //先找到基准下标
int par = partion(array, start, end);
//判断基准的左边是不是还有1个以上元素,如果是再调用快排
if(par>start+1)
{
Quick(array, start, par-1);
}
//判断基准的右边是不是还有1个以上元素,如果是再调用快排
if(par<end-1)
{
Quick(array, par+1, end);
}
}
测试
public static void main(String[] args) {
int [] a = {1,4,5,2,3,2,456,23,13};
quickSort(a);
System.out.println(Arrays.toString(a));
}
结果[1, 2, 2, 3, 4, 5, 13, 23, 456]
非递归代码
/** * 快速排序非递归 * @param array 目标数组 */
public static void quickSort1(int[] array)
{
LinkStack a = new LinkStack();
int low = 0;
int hight = array.length-1;
int par = partion(array, low, hight);
if(par>low+1)
{
a.push(low);
a.push(par-1);
}
if(par<hight-1)
{
a.push(par+1);
a.push(hight);
}
//出栈
while(!a.isEmpty())
{
hight = a.pop();
low = a.pop();
par = partion(array, low, hight);
if(par>low+1)
{
a.push(low);
a.push(par-1);
}
if(par<hight-1)
{
a.push(par+1);
a.push(hight);
}
}
}
/** * 返回基准下标,相当于每次为一个元素找到其位置,将数组分为两部分 * @param array 数组 * @param start 开始下标 * @param end 结束下标 * @return 基准下标 */
public static int partion(int[] array,int low,int hight)
{
//找到一个基准
int temp = array[low];
//遍历直到所有遍历完
while(low<hight)
{
//从右向左找比temp小的
while(low<hight&&array[hight]>=temp)
{
--hight;
}
//如果相遇了,或交错了,直接跳出
if(low>=hight)
{
break;
}
//如果符合条件,将小的放到当前low的位置。
else
{
array[low] = array[hight];
}
//从左向右找比temp大的
while(low<hight&&array[low]<=temp)
{
++low;
}
//如果遍历完了,跳出
if(low>=hight)
{
break;
}
//如果符合条件,将大的放到当前hight位置
else
{
array[hight] = array[low];
}
}
//将基准放入low
array[low] = temp;
//返回low
return low;
}
测试
public static void main(String[] args) {
int [] a = {1,4,5,2,3,2,456,23,13};
quickSort1(a);
System.out.println(Arrays.toString(a));
}
结果[1, 2, 2, 3, 4, 5, 13, 23, 456]
Partition解析
此方法中最难理解的就是partition,及找基准的过程,此时用6,4,5,8,2【low=0,hight=4】
此数列进行举例分析。
次数 | 操作前数组 | low | hight | temp | 操作 | 操作后数组 |
---|---|---|---|---|---|---|
1 | 6,4,5,8,2 |
0 | 4 | 6 | 从后向前找比6小的,找到2,hight保持不变为4,将2放置于下标0处 | 2,4,5,8,2 |
2 | 2,4,5,8,2 |
0 | 4 | 6 | 从前向后找比6大的,找到8,low变为3,将8放置于下标4处 | 2,4,5,8,8 |
3 | 2,4,5,8,8 |
3 | 4 | 6 | 从后向前找比6小的过程中发现low>hight了,整个循环跳出,将temp6 放置于low下标处 |
2,4,5,6,8 |
这一次partition过后,会发现6之前都是比它小的,6之后都是比它大的。
非递归解析
递归和非递归的其本质区别其实只是:递归所用的是系统的栈,而且所有的现场都是收到保护的。在使用非递归进行快排的时候,其实只需要自己构造一个栈,然后根据需要的数据进行入栈出栈即可。