算法思想
快速排序使用了分治思想,即:
分解:数组以一个随机元素K为分割数,被划分为两个部分,左边部分的每一个元素都小于等于K,右边部分的每一个元素都大于等于K。
解决:通过递归调用函数,对左边和右边进行排序。
合并:因为在原空间进行排序,所以不需要合并。
具体来分析数组分解的动作:
以数组arr[] = {6,4,7,2,8};为例,用i和j标记数组的起始位置和末尾位置,即i=0,j=4。选6为分割数,即k=6。然后进行下面步骤:
- 将j往左移动,直到找到小于等于分割数(6)的元素(2),然后将此时i(即6)的位置赋值为2。
- 将i往右移动,直到找到大于等于分割数(6)的元素(7),然后将此时j(即上图红色2)的位置
- 重复1,2步直到i和j重合,此时将分割值(6)放到i的位置,分割值所有左边的元素小于等于它,右边的元素都大于等于它。
算法实现
将上述过程用代码实现:
int partition(int *arr,int lef,int rigt)
{
int i = lef,j = rigt;
int k = arr[i];
while(i < j)
{
while(i<j && arr[j]>=k)
j--;
if(i < j)
arr[i++] = arr[j];
while(i<j && arr[i]<k)
i++;
if(i < j)
arr[j--] = arr[i];
arr[i] = k;
}
return i;
}
再递归排序:
int qksort(int *arr,int lef,int rigt)
{
if(lef < rigt)
{
int n = partition(arr,lef,rigt);
qksort(arr,lef,n-1);//左边排序
qksort(arr,n+1,rigt);//右边排序
//左边和右边排序的另一种写法
//qksort(arr,lef,n);
//lef = n+1;
}
return 0;
}
应用 :
int main()
{
int i;
int arr[5] = {6,4,7,2,8};
qksort(arr,0,4);
for(i=0; i<5; i++)
printf("%d ", arr[i]);
return 0;
}
结果:
算法分析
快速排序在最坏的情况下时间为O(n^2) ,最理想的时间为O(n*lgn),虽然它在最坏的情况下并不理想,但它的平均性能好,并且不需要额外开辟内存空间,所以其应用也很广泛。
算法优化
在运气很差的情况下选到的分割数是最大值或者最小值,其时间为O(n^2),随机选择能够有效的被分割的数据的不平衡。我们还可以设置一个保底机制,即选择三个随机元素,取中间值作为分割数,以保持算法的整体性。