排序学习笔记(2) - 快速排序

  学习排序,参考代码、测试程序:
http://tech.ddvip.com/2006-12/116513859112852.html
表示一下感谢~~

 

交换排序。包括冒泡排序和快速排序,一般说来冒泡是不能给别人说的:怕丢脸,呵呵。所以我们就默认交换排序==快速排序。

1. 思想

a)它采用的是分而治之的策略(divide and conque)。基本思想是:任取待排序列的某个记录(这句话就包含了优化的可能)作为基准,按照该关键码大小,将整个序列分成两个序列——--左侧的所有记录的关键码都比基准小(或者等),右侧的都比基准大,基准则放在两个子序列之间,显然这时基准放在了最后应该放置的位置(这个找pivot的方法,有很多,但是基本上都不对性能产生大的影响。但是好的pivot会很好的避免最坏情况的出现)。分别对左右子序列重复上面的过程,直到最后所有的记录都放在相应的位置(就是递归了,没什么好办法)。

 

b)整体上说,他的性能是所有排序里面最好的,而且消耗的辅助空间比较小。但是,最大的问题就是:递归,数据量大的时候会把stack爆掉。

 

c)不稳定排序,性能:O(n*lg(n));

 

d)当输入源是已经排序好的数据,这时候快速排序会得到最差的性能:每次新的比较都只是比上次少一个元素;

 

2. 版本

1)经典快速排序(严版)
寻找pivot的过程是整个算法的关键:是while嵌套两个小while:首先把最left元素作为pivot,从右向左,遇到小的放到left;从左向右,遇到大的,放到right;-->中间碰头,把pivot放到对应位置上。找完所有元素结束。

《代码》

  1. template <class T>
  2. int Partition2(T a[], int left, int right)
  3. {
  4.     T pivot = a[left];
  5.     while ( (left < right) )
  6.     {
  7.         while ( (pivot <= a[right]) && (left < right) )
  8.             right--;
  9.         a[left] = a[right];
  10.         
  11.         while ( (pivot >= a[left]) && (left < right) )
  12.             left++;
  13.         a[right] = a[left]; 
  14.     }
  15.     
  16.     a[left] = pivot; 
  17.     return left;
  18. }

这个方法还有一个变形,就是:从左到右,遇到小的停;从右向左,遇到大的停;互换;碰头的时候,把pivot放到对应位置上(通过交换得到)。和这个区别不大

 

2)简化pivot版(殷版)
实际上寻找pivot不必要那么费劲,从这边到那边,很难记住。殷版的比较实用,好记:在for循环中,让pivot从左到右比较,遇到一个小的,就把pivotpos++(pivotpos从left取值开始),然后pivotpos和当前第i个元素值进行交换。等循环结束之后,pivot与所有的值都进行了一次比较,pivotpos也记录下了这样一个位置:左边的值都小,右边的之都大,然后把pivot值放到这里;OK。

《代码》

  1. template <class T>
  2. int Partition(T a[], int left, int right)
  3. {
  4.     int pivotpos = left; 
  5.     T pivot = a[left];
  6.     for (int i = left + 1; i <= right; i++)
  7.     {
  8.         if (a[i] < pivot && ++pivotpos != i)
  9.         { 
  10.             swap(a[i], a[pivotpos]); 
  11.         }
  12.     }
  13.     swap(a[left], a[pivotpos]);
  14.     return pivotpos;
  15. }

3)对整个快速排序的性能优化
a)当数据个数为5->25的时候,才能直接插入法的效率比qsort快至少10%。所以,在递归过程中,待排数据个数小于M的时候,使用直接插入法;
b)基本同上,个数小于M的时候,直接忽略。完成之后,得到一个总体上大致已经排好序的序列,然后对整体使用直接插入法
c)对于pivot的选择,除了上述的两种基本方法外,可以提高。当每次划分得到的两个子序列的个数非常接近的时候,效果是最好的;所以我们希望得到一个最接近中值的pivot,至少不能弄成最差情况。所以,可以把pivot的值等于:right、left和中点这三

个值的中间值(参见文章“三个数字的中间值“);
d)综合运用前三种方案,可以把qsort的效率提高20->25%。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值