算法导论-9.3-3

题目:

假定元素的值不同,说明如何才能使快速排序在最坏情况下以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 }

 

运行结果:

posted @ 2012-06-24 20:07  windmissing  阅读(451)  评论(0编辑  收藏  举报