快速排序
1. 原理分析
-
快速排序在日常编程中是比较常见的一种排序手段。它的实现相比较于冒泡排序来说可能复杂一些,因为他用到了递归的思想,其实只要理解其排序的思想,我们会发现快速排序也没有那么难。
-
在快速排序中,我们使用了分治法,简言之就是分而治之。那么根据什么来分呢?
-
这里我们需要选取一个基准值,给他去个名字叫key吧。基准值我们一般选取数组的第一个元素的值:key = array[0] (当然了, 你可以选取数组中的任意一个值来作为基准值)
然后就是比较环节了,我们拿这个基准值去跟其他的每一值去比较,比基准值大的就放在它的右边,比基准值小的就放在它的左边。这样原来的数组就别分成了基准值的做和右两部分,然后左边部分和右边部分有按照这种办法来继续分区而治。这里就体现了分治法的精髓。再深入思考一下,这个过程是不是很像递归的过程呢(二叉树的遍历过程也和这个很像的)。所以这里也用到了递归的思想。
-
口说无凭,下面来举个例子。
定义一个数组:int a[] = {33,12,8,46,5,88}
-
首先选取一个基准值key(一般选a[0]),key = a[0]
-
然后定义两个下标(用来遍历数组),i,j;分别用来表示数组的第一个元素的下标和最后一个元素的下标。i = 0,j = len-1;
-
33 12 8 46 5 88
i------------------j
开始移动时,j移动到5的位置,此时a[j] < a[i](不满足的话执行j--,即j继续向左移动,直到该条件满足),前面我们已经将a[i]的值保存到key中了,即已经将a[i]的值挖出了,使a[i]=a[j],然后开始移动i,即i++,移动到12位置发现:
46比33大,就将a[j]=a[i],以此比较。当i>=j时,第一轮比较停止,此时a[i]=key;[5 12 8] 33 [46 88]
到此,原来的的数据被分成了两组
继续递归对两边的继续分组
最终,的到正确的排序。
-
二、实现代码讲解
void quick_sort(int a[],int low,int high)
{
int i = 0,j = o,key = 0;
i = low;
j = high;
key = a[low]; //根据用户传入的值选取基准值
while(i < j)
{
//从j开始,找到比key小的数,放在i的位置
while(i < j && a[j] >= key)
{
j--;
}
if(i < j)
{
a[i] = a[j]; //将比a[i]大的值放到a[i]位置
}
while(i < j && a[i] <= key)
{
i++; //i开始向后查找比key大的值
}
if(i < j)
{
a[j] = a[i];
}
}
//循环结束后,a[i]的值没有变,将key放到a[i]
a[i] = key;
//对左右的搬去进行递归快排
qiuck_sort(a,low,i-1); //对左搬去进行块排
qiuck_sort(a,j+1,high); //对右半区进行快排
}
三、总结
- 快速排序中事件复杂度会根据数据的位置不同而有所不同,如选取的基准值在中间,这样这种排序方法的空间复杂度最低为O(nlogn),相反,若每次选取的基准值都是最大最小值的话,那么其空间复杂度为O(n^2),所以该算法是不稳定的。