作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4046189.html

首先随机选择一个轴,并调整数组内各个数字,使得比轴值大的数在轴的右边,比轴小的数在抽的左边。然后在递归的对左边和右边进行快速排序。

在调整的过程中,可以使用交替填坑的算法。

例如对于序列 4 2 3 0 1 5 第一次随机选择轴值为3。那么首先把轴值与第一个数交换。并保存数值3,得到序列:

2  4  0  1  5

p                 q

现在取两个指针p,q分别指向序列的第一个数和最后一个数。即p指向3,q指向5。现在p指向的数字为坑,可以被替换掉,那么另q指向第一个比轴值小且在p后面的数,即1。那么把1覆盖掉p指向的坑。并且另p++,现在序列变为:

1  2  4  0    5

p          q

现在q指向的1为坑,现在另p找到第一个比轴值3大的且在q之前的数,即4。那么把4填入q指向的坑中。q--,序列变为:

1  2    0  4  5

p  q

现在p指向的4为坑,把第一个比轴值3小且在p后面的数为0,那么把0填入坑中,p++,序列变为:

1  2  0    4  5

q   p

现在p指向的0为坑,发现p>q,那么把轴值填入坑中,即完成了partition的过程。最终序列为:

1  2  0    4  5  轴值为3,其左侧的数都比3小,右侧的数都比3大。

然后对序列1 2 3和4 5,递归的调用快速排序算法就可以了。

代码如下,分别实现了递归和非递归的快排。

 int partation(vector<int> & arr, int l, int r)
{
int p = rand() % (r - l + ) + l;
int pval = arr[p];
swap(arr[p], arr[l]);
while( l < r )
{
while( l < r && arr[r] >= pval ) r--;
arr[l] = arr[r];
while( l < r && arr[l] < pval ) l++;
arr[r] = arr[l];
}
arr[l] = pval;
return l;
} void qs_st(vector<int> & arr, int l, int r)
{
if( l >= r ) return;
stack<pair<int, int> > st;
int m = partation(arr, l, r);
if( m - > l ) st.push(make_pair(l, m - ));
if( m + < r )st.push(make_pair(m + , r));
while( !st.empty() )
{
int l = st.top().first;
int r = st.top().second;
st.pop();
int m = partation(arr, l, r);
if( m - > l ) st.push(make_pair(l, m - ));
if( m + < r ) st.push(make_pair(m + , r));
}
} void qs(vector<int> & arr, int l, int r)
{
if(l >= r) return;
int m = partation(arr, l, r);
qs(arr, l, m - );
qs(arr, m + , r);
}

quick_sort

对于快速排序算法的复杂度我们可以进行如下的计算:

对于一个长度为$n$的序列,我们定义指数函数$I(i,j)$:在快速排序算法中如果第$i$个元素和第$j$个元素比较过就为1否则为0。

那么总的比较次数$X$为:

\begin{equation} X = \sum_{i=1}^{n}\sum_{j=i+1}^{n}I(i,j) \end{equation}

我们可以得到$X$的期望为:

\begin{eqnarray} E(X) &=& E(\sum_{i=1}^{n}\sum_{j=i+1}^{n}I(i,j))\\ &=&  \sum_{i=1}^{n}\sum_{j=i+1}^{n}E(I(i,j))\\ &=&\sum_{i=1}^{n}\sum_{j=i+1}^{n}P(\mbox{i is compared with j})\\ &\leq& \sum_{i=1}^{n}\sum_{j=i+1}^{n} \frac{2}{j-i+1}\\ &=&\sum_{i=1}^{n}\sum_{k=1}^{n-i} \frac{2}{k+1}\\ &<& \sum_{i=1}^{n}\sum_{k=1}^{n} \frac{2}{k+1}\\ &=& O(n\log n) \end{eqnarray}

其中第5步,i和j比较的概率,可以这么计算,不妨设i和j分别为排完序后的位置且i<j,那么如果i和j之间的数当过轴,那么i和j在后面的过程中就绝对不会在进行比较。

因此i和j比较过只有可能小于i或大于j的数当做轴,那么在下面的递归过程中,最终会形成一个由i到j组成的序列,i为序列的第一个,j为序列的最后一个,那么i和j比较过只有可能i为轴或j为轴。

其中i为轴的概率为在j-i+1个数中选择1个即1/(j-i+1),同理j被选作为轴的概率也为1/(j-i+1),即i和j被比较过的概率为2/(j-i+1)。

快速排序算法 Quick sort的更多相关文章

  1. 快速排序算法 quick sort的理解

    最近做了一下算法的一些练习,感觉基础薄弱了,只是用一些已经有的东西来完成练习如quickSort(c++使用的时候是sort(起始位置,终止位置,比较函数),这个需要加头文件),但是不知道怎么推出来, ...

  2. [算法]——快速排序(Quick Sort)

    顾名思义,快速排序(quick sort)速度十分快,时间复杂度为O(nlogn).虽然从此角度讲,也有很多排序算法如归并排序.堆排序甚至希尔排序等,都能达到如此快速,但是快速排序使用更加广泛,以至于 ...

  3. 排序算法—快速排序(Quick Sort)

    快速排序(Quick Sort) 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序. ...

  4. 【算法】快速排序(Quick Sort)(六)

    快速排序(Quick Sort) 快速排序的基本思想:通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序. ...

  5. 快速排序(Quick Sort)的C语言实现

    快速排序(Quick Sort)的基本思想是通过一趟排序将待排记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对着两部分记录继续进行排序,以达到整个序列有序,具体步骤 ...

  6. 交换排序—快速排序(Quick Sort)原理以及Java实现

    交换排序—快速排序(Quick Sort) 基本思想: 1)选择一个基准元素,通常选择第一个元素或者最后一个元素, 2)通过一趟排序讲待排序的记录分割成独立的两部分,其中一部分记录的元素值均比基准元素 ...

  7. 快速排序(Quick Sort)

    快速排序是初学者比较难理解的几个算法之一,这里尽可简单化地讲解,希望能帮到大家. 快速排序基本步骤: 从数列中挑出一个元素,称为"基准"(pivot). 重新排序数列,所有元素比基 ...

  8. 算法 quick sort

    // ------------------------------------------------------------------------------------------------- ...

  9. 快速排序(Quick Sort)及优化

    原理介绍 通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成 ...

随机推荐

  1. 【24】若所有参数皆需类型转换,请为此采用non-members函数

    1.令class支持隐式类型转换,往往是个糟糕的主意.但有些情况是合理的,比如数值类型.考虑,有理数Rational有分子,分母两个字段,缺省参数值为0,1.Ration a = 2;我们期望构造一个 ...

  2. Android 如何修改默认的searchable items。

    前言          欢迎大家我分享和推荐好用的代码段~~ 声明          欢迎转载,但请保留文章原始出处:          CSDN:http://www.csdn.net        ...

  3. nginx 调优

    般来说nginx配置文件中对优化比较有作用的为以下几项:worker_processes 8;1 nginx进程数,建议按照cpu数目来指定,一般为它的倍数.worker_cpu_affinity 0 ...

  4. Vs 2008 解决方案的目录结构设置和管理(转)

    http://blog.csdn.net/lcj_cjfykx/article/details/8632459 MS的这个IDE,实在庞杂得恐怖.从大学开始,我就一直用VC的各个版本写程序至今,细细想 ...

  5. careercup-C和C++ 13.4

    13.4 深拷贝和浅拷贝有什么区别,如何使用? 解答 浅拷贝并不复制数据,只复制指向数据的指针,因此是多个指针指向同一份数据. 深拷贝会复制原始数据,每个指针指向一份独立的数据.通过下面的代码, 可以 ...

  6. 关于Java基本数据类型

    Java的基本数据类型分为两大类:boolean类型和数字类型.而数值类型又分为整数类型和浮点类型.而整数类型中的字符类型也可以被单独对待. 总共是4类8种. byte类型整数在内存里占8位. -12 ...

  7. 我终于理解了LISP『代码即数据|数据即代码』的含义

    以前我一直不能理解LISP里引用的作用,感觉引用和字符串没什么区别.比如:> (define (func)     'ok) > (func) 'ok 这里把引用ok当做了函数func的返 ...

  8. CentOS下安装福昕PDF软件

    官方下载地址:http://www.foxitsoftware.cn/downloads/ tar -jxvf foxreader.tar.bz2问题:下载官方包以后解压,双击不能打开,也没有任何提示 ...

  9. 陷阱~SQL全表扫描与聚集索引扫描

    SqlServer中在查询时,我们为了优化性能,通常会为where条件的字段建立索引,如果条件比较固定还会建立组合索引,接下来,我们来看一下索引与查询的相关知识及相关陷阱. SQL表自动为主键加聚集索 ...

  10. OpenID说明

    OpenID使用手册 摘要: OpenID是一种开放.离散式的用于用户数字标识的开源框架.在网络应用日益充斥的今天,作为终端用户的我们不得不在每个网站上设置帐号,并管理众多的帐号.而采用OpenID技 ...