快速排序算法

来源:互联网 发布:java中时间格式化 编辑:程序博客网 时间:2024/04/30 20:00

    快速排序(QuickSort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。快速排序采用了基于分治的策略。

主要思想:在数组中选取一个枢轴(或称主元,最基本的就是选第一个元素),把小于主元的元素全部放在左边,大于主元的全部放右边(以上即为partition函数),然后再按此方法对主元左边和主元右边的两部分数据(不包含主元!)分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

    对于partition的实现,有多种版本:

    算法导论上选取最后一个元素做主元,i,j均采用从头到尾单向扫描:j在前面开路,i跟在j后,j只要遇到比主元小的元素,i 就向前前进一步,然后把j找到的比主元小的元素,赋给i,然后,j才再前进。i所经过的每一步,都必须是比主元小的元素,否则,i就不能继续前行。好比j 是先行者,为i开路搭桥,把小的元素作为跳板放到i 跟前,为其铺路前行。

国内教材一般使用双向扫描,为Hoare最初的方法或其变形。一般选第一个元素做主元,i一开始指向第一个元素向后扫描,j指向最后一个向前扫描。从j开始,如果j遇到比主元小的,则将此元素赋值给i所在位置,然后轮到i前进,直到遇到比主元大的赋值给j所在位置…如此j、i轮流扫描直到i>j。

    快速排序的平均时间复杂度为O(nlogn),最坏时间复杂度为O(n2)。当输入数据有序时为最坏情况,需要O(n2)。随机化版本的快排最坏时间复杂度仍为O(n2)!但是最坏情况不依赖输入数据,而是随机函数取值不佳。由于快速排序是递归的,故其空间复杂度即为栈的深度,最好情况下为O(logn),最坏情况为O(n)平均空间复杂度为 O(logn)如果每次选取分区长的部分先入栈,即先处理短的分区可以减少算法的递归深度(但递归次数不变,递归次数与处理顺序无关),可使得最坏情况栈深度为O(logn)。快速排序是平均性能最好的排序算法,是不稳定的算法。

    快排有多种变形:随机化的快排、“三数取中”划分等。随机化的快速就是每次随机选取一个元素作为主元,方法就是每次先用随机函数在left和right之间随机出一个数字rand,然后将第rand个元素和第left个元素交换,此时就可以继续使用原来的partition,因为这时候再取第一个元素做主元时已经是随机后的那个数了。“三数取中”划分就是每次(随机)选出三个元素,取其中间数作为主元。

#include<iostream>using namespace std;int partition(int arr[],int left,int right){int index=arr[left],i=left,j=right;while(i<j){while(arr[j]>=index && i<j) //必须有等号!否则数字相同会死循环 j--;//若大于主元则向前arr[i]=arr[j];while(arr[i]<=index && i<j)i++;//若小于主元则向后arr[j]=arr[i];}arr[i]=index;return i;//返回主元最终位置}void quickSort(int arr[],int left,int right){if(left<right){int mid=partition(arr,left,right);quickSort(arr,left,mid-1);quickSort(arr,mid+1,right); }}int main(){    int a[]={5,9,-2,10,0,-9,23,-11,6,7};   quickSort(a,0,9);   for(int i=0;i<10;++i)   cout<<a[i]<<" ";    return 0;}

    quickSort中的第二次递归调用不是必须的,可以用迭代控制结构来代替它。这种技术称为尾递归。可以改为如下形式:

void quickSort(int arr[],int left,int right){while(left<right)//if需改为while循环{int mid=partition(arr,left,right);quickSort(arr,left,mid-1);left=mid+1; //不再用递归!}}

参考:

《算法导论》

http://blog.csdn.net/v_JULY_v/article/details/6262915

原创粉丝点击