• 算法导论9.33


    题目:

    假定元素的值不同,说明如何才能使快速排序在最坏情况下以O(nlgn)时间运行

    思考:

    要改善最坏情况的下运行时间,就要从划分入手,保证即使是最坏情况,也要尽量均衡地划分。

    因此,使用SELECT找到中值,再以这个中值为主元进行划分

    代码:

    1.以RANDOMIZED-SELECT作为选择中值的算法

     1 //9.3-3-使用RANDOMIZED-SELECT作为选择中值算法
     2 #include <iostream>
     3 using namespace std;
     4 
     5 //已经出现很多次了,不解释
     6 int Partition(int *A, int p, int r)
     7 {
     8     int x = A[r], i = p-1, j;
     9     for(j = p; j < r; j++)
    10     {
    11         if(A[j] <= x)
    12         {
    13             i++;
    14             swap(A[i], A[j]);
    15         }
    16     }
    17     swap(A[i+1], A[r]);
    18     return i+1;
    19 }
    20 //以f为主元的划分
    21 int Partition2(int *A, int p, int r, int f)
    22 {
    23     int i;
    24     //找到f的位置并让它与A[r]交换
    25     for(i = p; i < r; i++)
    26     {
    27         if(A[i] == f)
    28         {
    29             swap(A[i], A[r]);
    30             break;
    31         }
    32     }
    33     return Partition(A, p, r);
    34 }
    35 int Randomized_Partition(int *A, int p, int r)
    36 {
    37     //随机选择数组中一个数作为主元
    38     int i = rand() % (r-p+1) + p;
    39     swap(A[r], A[i]);
    40     //划分
    41     return Partition(A, p, r);
    42 }
    43 //i是从1开会计数的,不是从p开始
    44 int Randomized_Select(int *A, int p, int r, int i)
    45 {
    46     if(p == r)
    47         return A[p];
    48     //以某个元素为主元,把数组分为两组,A[p..q] <= 主元 < A[q+1..r],返回主元在整个数组中的位置
    49     int q = Randomized_Partition(A, p, r);
    50     //主元是整个数组中的第q个元素,是A[p..r]数组中的第k个元素
    51     int k = q - p + 1;
    52     if(i == k)
    53         return A[q];
    54     else if(i < k)//所求元素<=主元,则在A[p..q-1]中继续寻找
    55         return Randomized_Select(A, p, q-1, i);
    56     else//所求元素>主元,则在A[q+1..r]中继续寻找
    57         return Randomized_Select(A, q+1, r, i-k);
    58 }
    59 
    60 void QuickSort(int *A, int p, int r)
    61 {
    62     if(p >= r)
    63         return ;
    64     //用RANDOMIZED-SELECT作为选择中值的算法选择中值
    65     int i = (r - p + 1) / 2;
    66     int x = Randomized_Select(A, p, r, i);
    67     //以这个中值为主元进行划分
    68     int q = Partition2(A, p, r, x);
    69     //分别对划分后的前后两个部分进行排序
    70     QuickSort(A, p, q-1);
    71     QuickSort(A, q+1, r);
    72 }
    73 int main()
    74 {
    75     int length_A, i;
    76     cin>>length_A;
    77     //生成随机数据
    78     int *A = new int[length_A+1];
    79     for(i = 1; i <= length_A; i++)
    80         A[i] = rand() % 100;
    81     for(i = 1; i <= length_A; i++)
    82         cout<<A[i]<<' ';
    83     cout<<endl;
    84     //排序
    85     QuickSort(A, 1, length_A);
    86     //输出结果
    87     for(i = 1; i <= length_A; i++)
    88         cout<<A[i]<<' ';
    89     cout<<endl;
    90     delete []A;
    91     return 0;
    92 }

    运行结果:

    2.以最坏情况下线性时间作为选择中值的算法

      1 //9.3-3使用最坏情况线性时间算法作为选择中值算法
      2 #include <iostream>
      3 using namespace std;
      4 
      5 //已经出现很多次了,不解释
      6 int Partition(int *A, int p, int r)
      7 {
      8     int x = A[r], i = p-1, j;
      9     for(j = p; j < r; j++)
     10     {
     11         if(A[j] <= x)
     12         {
     13             i++;
     14             swap(A[i], A[j]);
     15         }
     16     }
     17     swap(A[i+1], A[r]);
     18     return i+1;
     19 }
     20 int Select(int *A, int p, int r, int i);
     21 //对每一组从start到end进行插入排序,并返回中值
     22 //插入排序很简单,不解释
     23 int Insert(int *A, int start, int end, int k)
     24 {
     25     int i, j;
     26     for(i = 2; i <= end; i++)
     27     {
     28         int t = A[i];
     29         for(j = i; j >= start; j--)
     30         {
     31             if(j == start)
     32                 A[j] = t;
     33             else if(A[j-1] > t)
     34                 A[j] = A[j-1];
     35             else
     36             {
     37                 A[j] = t;
     38                 break;
     39             }
     40         }
     41     }
     42     return A[start+k-1];
     43 }
     44 //根据文中的算法,找到中值的中值
     45 int Find(int *A, int p, int r)
     46 {
     47     int i, j = 0;
     48     int start, end, len = r - p + 1;
     49     int *B = new int[len/5+1];
     50     //每5个元素一组,长度为start到end,对每一组进行插入排序,并返回中值
     51     for(i = 1; i <= len; i++)
     52     {
     53         if(i % 5 == 1)
     54             start = i+p-1;
     55         if(i % 5 == 0 || i == len)
     56         {
     57             j++;
     58             end = i+p-1;
     59             //对每一组从start到end进行插入排序,并返回中值,如果是最后一组,组中元素个数可能少于5
     60             int ret = Insert(A, start, end, (end-start)/2+1);
     61             //把每一组的中值挑出来形成一个新的数组
     62             B[j] = ret;    
     63         }
     64     }
     65     //对这个数组以递归调用Select()的方式寻找中值
     66     int ret = Select(B, 1, j, (j+1)/2);
     67     //delete []B;
     68     return ret;
     69 }
     70 //以f为主元的划分
     71 int Partition2(int *A, int p, int r, int f)
     72 {
     73     int i;
     74     //找到f的位置并让它与A[r]交换
     75     for(i = p; i < r; i++)
     76     {
     77         if(A[i] == f)
     78         {
     79             swap(A[i], A[r]);
     80             break;
     81         }
     82     }
     83     return Partition(A, p, r);
     84 }
     85 //寻找数组A[p..r]中的第i大的元素,i是从1开始计数,不是从p开始
     86 int Select(int *A, int p, int r, int i)
     87 {
     88     //如果数组中只有一个元素,则直接返回
     89     if(p == r)
     90         return A[p];
     91     //根据文中的算法,找到中值的中值
     92     int f = Find(A, p, r);
     93     //以这个中值为主元的划分,返回中值在整个数组A[1..len]的位置
     94     //因为主元是数组中的某个元素,划分好是这样的,A[p..q-1] <= f < A[q+1..r]
     95     int q = Partition2(A, p, r, f);
     96     //转换为中值在在数组A[p..r]中的位置
     97     int k = q - p + 1;
     98     //与所寻找的元素相比较
     99     if(i == k)
    100         return A[q];
    101     else if(i < k)
    102         return Select(A, p, q-1, i);
    103     else
    104         //如果主元是数组中的某个元素,后面一半要这样写
    105         return Select(A, q+1, r, i-k);
    106         //但是如果主元不是数组中的个某个元素,后面一半要改成Select(A, q, r, i-k+1)
    107 }
    108 
    109 void QuickSort(int *A, int p, int r)
    110 {
    111     if(p >= r)
    112         return ;
    113     //用RANDOMIZED-SELECT作为选择中值的算法选择中值
    114     int i = (r - p + 1) / 2;
    115     int x = Select(A, p, r, i);
    116     //以这个中值为主元进行划分
    117     int q = Partition2(A, p, r, x);
    118     //分别对划分后的前后两个部分进行排序
    119     QuickSort(A, p, q-1);
    120     QuickSort(A, q+1, r);
    121 }
    122 
    123 int main()
    124 {
    125     int length_A, i;
    126     cin>>length_A;
    127     //生成随机数据
    128     int *A = new int[length_A+1];
    129     for(i = 1; i <= length_A; i++)
    130         A[i] = rand() % 100;
    131     for(i = 1; i <= length_A; i++)
    132         cout<<A[i]<<' ';
    133     cout<<endl;
    134     //排序
    135     QuickSort(A, 1, length_A);
    136     //输出结果
    137     for(i = 1; i <= length_A; i++)
    138         cout<<A[i]<<' ';
    139     cout<<endl;
    140     delete []A;
    141     return 0;
    142 }

    运行结果:

  • 相关阅读:
    写给QA/软件测试新人
    互联网产品线上故障管理规范
    爬了世纪佳缘后发现了一个秘密,世纪佳缘找对象靠谱吗?
    网传美团今年应届生年薪 35w+,严重倒挂老员工,为什么互联网大厂校招的薪资一年比一年高?...
    MySQL大表优化方案
    步入AI领域2年连升3级,我只是找对了学习方法而已……
    BZOJ 4008 亚瑟王(概率DP 奥妙重重)
    BZOJ 4318 OSU! (概率DP)
    BZOJ 3812 主旋律 (状压DP+容斥) + NOIP模拟赛 巨神兵(obelisk)(状压DP)
    BZOJ 4145 [AMPPZ2014]The Prices (状压DP)
  • 原文地址:https://www.cnblogs.com/windmissing/p/2560280.html
Copyright © 2020-2023  润新知