算法设计分析——分治策略选取第k大元素

1.问题

通过分治策略,选取第k小元素。

2.解析

通过快速排序和分治的思想,每次随机选取主元,判断小于主元的元素的个数,如果个数大于k则递归寻找左半段,如果个数小于k则递归寻找右半段

3.设计

 1 int find_kth(int l, int r, int k) {
 2 
 3     if (l == r)return a[l];//递归边界
 4 
 5     int temp = a[random(l, r)];//随机选取主元
 6 
 7     int cnt = 0;//计比主元大的个数
 8 
 9     int i = l, j = r;
10 
11     while (i <= j) {
12 
13         while (a[i] > temp&& i <= j)i++, cnt++;
14 
15         while (a[j] <= temp && i <= j)j--;
16 
17         if (i < j) {
18 
19             swap(a[i], a[j]);
20 
21             cnt++;
22 
23         }
24 
25         i++, j--;
26 
27     }
28 
29     if (cnt >= k) {//若k<=cnt,就在左半段中递归寻找第k大
30 
31         return find_kth(l, l + cnt - 1, k);
32 
33     }
34 
35     else {//否则在就在右半段中递归寻找第k-cnt大的数
36 
37         return find_kth(l + cnt, r, k - cnt);
38 
39     }
40 
41

4.分析

时间复杂度:O(nlogn)

空间复杂度:O(n)

5.源码

https://github.com/BambooCertain/Algorithm.git

 1 #include<stdio.h>
 2 #include<algorithm>
 3 #include<iostream>
 4 using namespace std;
 5 int a[100010];
 6 void swap(int& x, int& y) {
 7     int temp = x;
 8     x = y;
 9     y = temp;
10 }
11 int random(int l, int r) {//返回一个在[l,r]范围内的随机整数
12     return rand() % (r - l + 1) + l;
13 }
14 int find_kth(int l, int r, int k) {
15     if (l == r)return a[l];//递归边界
16     int temp = a[random(l, r)];//随机选取主元
17     int cnt = 0;//计比主元大的个数
18     int i = l, j = r;
19     while (i <= j) {
20         while (a[i] > temp&& i <= j)i++, cnt++;
21         while (a[j] <= temp && i <= j)j--;
22         if (i < j) {
23             swap(a[i], a[j]);
24             cnt++;
25         }
26         i++, j--;
27     }
28     if (cnt >= k) {//若k<=cnt,就在左半段中递归寻找第k大
29         return find_kth(l, l + cnt - 1, k);
30     }
31     else {//否则在就在右半段中递归寻找第k-cnt大的数
32         return find_kth(l + cnt, r, k - cnt);
33     }
34 }
35 int main() {
36     int n; cin >> n;
37     for (int i = 1; i <= n; i++)cin >> a[i];
38     int k; cin >> k;
39     cout << find_kth(1, n, k) << endl;
40 }
完整代码

猜你喜欢

转载自www.cnblogs.com/DreamACMer/p/12650623.html