选择第n大的数(分治法和排列实现)

个人心得:在买的书上看到的一个经典分治题,题目意思就是给定一个数组,求第k小的数。

第一反应就是排序,然后返回第k-1位置的数就可以了,这样算法的复杂度是nlongn,在快速排序的基础下还是挺不错的。

不过为了学习分治法还是换种思路,这也是建立在快速排序的方法,因为快排是以第一个作为标准,比他小的数在左边,大的数在右边。

所以此时就有nleft表示左边的个数

1:如果nleft=k-1,那么此时flag必然是第k小的数

2:如果大于,那么就在左边找就好了,问题规模变小了

3:如果小于,去右边,不过此时选择k-nelft-1(解释,本代码自动跳跃flag这个数所以还要减去1)

注意问题的转移和基准的确定。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<iomanip>
 6 #include<algorithm>
 7 using namespace std;
 8 #define maxi 105
 9 int a[maxi];
10 int b[maxi];
11 int n,k;
12 void geta(){
13     for(int i=0;i<n;i++)
14         b[i]=a[i];
15 }
16 int sorta(){
17       sort(b,b+n);
18       return b[k-1];
19 }
20 int quickcheck(int left,int right,int ki)
21 {
22     if(left>=right) return a[left];
23     int i=left;
24     int j=right+1;
25     int flag=a[left];
26     while(true){
27         do
28         {
29             i++;
30         }while(a[i]<flag);
31         do
32         {
33             j--;
34         }while(a[j]>flag);
35         if(i>=j) break;
36         swap(a[i],a[j]);
37     }
38     int nleft=j-left;
39     if(nleft==ki-1) return flag;
40     a[left]=a[j];
41     a[j]=flag;
42     if(nleft<ki-1)
43         return quickcheck(j+1,right,ki-nleft-1);
44     else
45         return quickcheck(left,j-1,ki);
46 }
47 
48 int main()
49 {
50    cin>>n>>k;
51    for(int i=0;i<n;i++) cin>>a[i];
52    geta();
53    cout<<sorta()<<endl<<quickcheck(0,n-1,k)<<endl;
54    return 0;
55 }

 

posted @ 2017-11-12 19:47  余生漫漫浪  阅读(1343)  评论(0编辑  收藏  举报