快速排序

来源:互联网 发布:微信小游戏源码 编辑:程序博客网 时间:2024/06/06 04:43
 1.算法描述
快速排序是一种基于分治技术的排序算法。在一个给定的数列中,选择一个数作为分区的依据进行排序,使得数的左边都小于该数,数的右边都大于该数,然后将该数的左边和右边分别作为一个数列进行排序,一直重复以上操作,直到分区里只有一个数字为止。
上面所说的是快速排序的基本特点,可以简单总结为:确定分区依据,左小右大(或左大右小),划分子区间,重复以上操作,直到子区间只有一个数字。
在具体的实现中,快速排序的实现不止一种。比如如何确定分区的依据,如何排序使得分区数字左边所有数字都小于该数字,右边都大于该数字,这可以有很多不同的实现方式。下面讲到的是一种基于两次扫面子数列的方法。


2.实例
使用快速排序将下列数列按升序排序
6     4     1     19     10     5

第一次扫描,选择6作为分区依据,第一次扫描结束后6的左边都小于6,右边都大于6,因此从左边开始扫描时,如果这个数比6小,则继续扫描,直到找到一个数字比6大,左边停止扫描,右边开始扫描,如果这个数字比6大,则继续扫描,直到找到一个数字比6小,右边停止扫描,然后左右扫描停止的位置互换,然后重新开始左右扫描,直到坐标的索引值大于右边的索引值。根据这些分析,我们开始排序。

第一次扫描
设该数列为int number[6],坐标索引为left,右边索引为right
left=1左边开始扫描,4<6继续扫描;left=2, 1<6继续扫描;left=3,19>6,左边扫描停止;
right=5右边开始扫描,5<6右边扫描停止;左右互换数据后数列为:
6     4     1     5     10     19
left<right,扫描继续。left=4左边开始扫描,10>6坐标扫描停止;
right=4右边开始扫描,10>6,扫描继续;right=3,5<6,右边扫描停止;左右互换数据后数列为:
6     4     1     10     5     19
left>right,第一次扫描技术。扫描结束的条件是left>=right,因此当left>right时,最后一次交换回是错误的,因此扫描结束后,应该还原最后一次互换。left和right再次互换,数列如下:
6     4     1    5     10     19
将6和right的值互换,数列如下:
5     4     1     6     10     19
这样第一次扫描才正真的结束,6的左边的数都小于6,6右边的数都大于6


第二次扫描
分别将number[0..right-1]和number[right+1,5]看做两个数列,进行步骤一的操作。
5     4     1              6               10     19
设number[0..right-1]为number_left[0..right-1],left1=1开始左边扫描,4<5,继续扫描;left1=2,1<5,继续扫描,但是number_left只有三个数字,因此左边扫描结束;
right1=2开始右边扫描,1<5,右边扫描结束。互换left1和right1,数列如下:
5     4     1              6                10       19
left1==right1,number_left的扫描结束,left1和right1互换,5和right1互换位置,数列如下:
1     4     5              6                10       19

第三次扫描
分别对number_left[0..right1-1]和number_left[right1+1..right-1]排序,因为right1+1=3,right-1=2,所以number_left[right1+1..right-1]不存在。
设number_left[0..right1-1]为number_left_left[0..right1-1],left11=1左边开始扫描,4>1左边扫描结束;
right11=1右边扫描开始,4>1扫描继续;right11=0,1==1,右边扫描结束;left11和right11互换后数列如下:
4     1                    5                              6                              10       19
left11>right11,number_left_left扫描结束,left11和right11互换,1和right11互换后数列如下:
1     4                    5                              6                               10      19
到这里6之前的排序都结束了,然后再对number_right也使用上面描述的方法进行排序,这里就不在重复描述了。



3.代码
void quick_sort::quick_sort_with_array(int nums[], int begin_index, int end_index){int index = 0;if(begin_index<end_index){index = partition(nums, begin_index, end_index);quick_sort_with_array(nums, begin_index, index-1);    quick_sort_with_array(nums, index+1,end_index);}}int quick_sort::partition(int nums[],int begin_index, int end_index){int left=begin_index;int right = end_index;int number = nums[begin_index];while(left<right){while(nums[left]<=number && left<end_index)  left++;while(nums[right]>=number && right>0) right--;swap(nums[left],nums[right]);}swap(nums[left],nums[right]);swap(nums[begin_index], nums[right]);return right;}void quick_sort::swap(int& a, int& b){int temp = a;a        = b;b        = temp;}


4.算法分析
在快速排序中,比较和位置替换依然是主要操作。先来看一下比较操作。从上面的代码中我们可以看出,程序采用从左右两端扫描数列的方式,每次扫描结束后,一个数字就会被放到合适的位置,及排除出待排序序列,直到最后所有子数字的个数都是1.
设对一个长度为n的数列进行升序排序,如果给定的已经是一个按升序(或降序)排序的数列,这种情况下比较的次数最多,比较次数为:
                                                             C(n)=(n+1)+n+(n-1)+...+3=(n+1)*(n+2)/2-3
上面讨论的是最坏情况,如果排序的时候,分裂点都是中心位置,则为最优情况,比较次数为:
                                                              C(n)=2*C(n/2)+n         (n>1,C(1)=0,C(2)=2)
设n=2^k,根据上面的公式可推算出:




在平时使用时,上面讨论的两种情况是不经常遇到的,下面我们来讨论一下快速排序在平均情况下的效率:
设有一个长度为n的数列,快速排序的平均键值比较次数为 Cavg(n),假设分区的分裂点s(0<= s<=n-1)位于每个位置的概率是1/n,可以得出下面的公式:
                                         
根据公式推算得:




因为1/(n+1)+1/n+1/(n-1)+...1/2为发散序列,无法算出精确值,只能是大约值,网上找到的是约等于lnn,但证明过程没有找到,证明就暂时到这里,以后再做修改吧。因此快排的平均复杂度为
                                                                
从上面的计算结果可以看出,快排在平均情况仅比最优情况多执行了38%的操作。















0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 鱼刺刺手指肿了怎么办 做小保健射的快怎么办 宝宝被跳骚_咬了怎么办 北京被仙人跳了怎么办 cnc刀库卡住了怎么办 经常熬夜月经不来怎么办 三星a7手机发热严重怎么办 三星s6电池坏了怎么办 苹果7磨砂黑氧化怎么办 索尼z2一直重启怎么办 备份是无限重启怎么办 网上套现被骗了怎么办 魅族手机摔弯了怎么办 手机不带nfc功能怎么办 三星s7后盖脱胶怎么办 小米6听筒声音小怎么办 红米4听筒声音小怎么办 索尼z5太耗电了怎么办 索尼z5密码忘了怎么办 高清线头子坏了怎么办 金立m5开不了机怎么办 旅行箱拉链坏了怎么办 青芒果切开没熟怎么办 拉链头掉了一侧怎么办 新秀丽箱子坏了怎么办 拉杆箱秘密忘了怎么办 双肩包带子太滑怎么办 双肩包背带老掉怎么办 剃须刀刀网坏了怎么办 期望工资说高了怎么办 年龄大的辅警怎么办 夷陵中学老校区怎么办 点我达同城直送怎么办 苏州市民卡b丢了怎么办 医保卡换市民卡怎么办 乐清市民卡丢了怎么办 市民卡b卡丢了怎么办 临海市民卡丢了怎么办 常熟市民卡坏了怎么办 医保卡钱用完了怎么办 医保卡本子丢了怎么办