zoukankan      html  css  js  c++  java
  • 算法导论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 }

    运行结果:

  • 相关阅读:
    Core Animation 文档翻译—附录C(KVC扩展)
    Core Animation 文档翻译—附录B(可动画的属性)
    Core Animation 文档翻译—附录A(Layer样貌相关属性动画)
    Core Animation 文档翻译 (第八篇)—提高动画的性能
    Core Animation 文档翻译 (第七篇)—改变Layer的默认动画
    Core Animation 文档翻译 (第六篇)—高级动画技巧
    Core Animation 文档翻译 (第五篇)—构建Layer的层次结构
    用Markdown快速排版一片文章
    Core Animation 文档翻译 (第四篇)—让Layer的content动画起来
    Core Animation 文档翻译(第三篇)—设置Layer对象
  • 原文地址:https://www.cnblogs.com/windmissing/p/2560280.html
Copyright © 2011-2022 走看看