zoukankan      html  css  js  c++  java
  • 快速排序算法 Quick sort

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

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

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

    例如对于序列 4 2 3 0 1 5 第一次随机选择轴值为3。那么首先把轴值与第一个数交换。并保存数值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  1  5

        p          q   

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

    1  2  4  0  4  5

            p  q

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

    1  2  0  0  4  5 

           q   p

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

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

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

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

     1 int partation(vector<int> & arr, int l, int r)
     2 {
     3     int p = rand() % (r - l + 1) + l;
     4     int pval = arr[p];
     5     swap(arr[p], arr[l]);
     6     while( l < r )
     7     {
     8         while( l < r && arr[r] >= pval ) r--;
     9         arr[l] = arr[r];
    10         while( l < r && arr[l] < pval ) l++;
    11         arr[r] = arr[l];
    12     }
    13     arr[l] = pval;
    14     return l;
    15 }
    16 
    17 void qs_st(vector<int> & arr, int l, int r)
    18 {
    19     if( l >= r ) return;
    20     stack<pair<int, int> > st;
    21     int m = partation(arr, l, r);
    22     if( m - 1 > l ) st.push(make_pair(l, m - 1));
    23     if( m + 1 < r )st.push(make_pair(m + 1, r));
    24     while( !st.empty() )
    25     {
    26         int l = st.top().first;
    27         int r = st.top().second;
    28         st.pop();
    29         int m = partation(arr, l, r);
    30         if( m - 1 > l ) st.push(make_pair(l, m - 1));
    31         if( m + 1 < r ) st.push(make_pair(m + 1, r));
    32     }
    33 }
    34 
    35 void qs(vector<int> & arr, int l, int r)
    36 {
    37     if(l >= r) return;
    38     int m = partation(arr, l, r);
    39     qs(arr, l, m - 1);
    40     qs(arr, m + 1, r);
    41 }
    quick_sort

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

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

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

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

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

    egin{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(nlog 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)。

  • 相关阅读:
    [LeetCode] Contains Duplicate II
    [LeetCode] House Robber II
    [LeetCode] Permutations II
    [LeetCode] Permutations
    [LeetCode] Next Permutation
    谈谈套接字
    基于Linux系统的Nagios网络管理模块的实现
    Windows/Linux下磁盘使用的图形化工具简介
    利用日志使管理Linux更轻松
    实际感受美丽的Linux(多组视频)
  • 原文地址:https://www.cnblogs.com/jostree/p/4046189.html
Copyright © 2011-2022 走看看