一道排序的解题过程

飞燕之家上的一道排序题:

题目描述:
某市重点高中很有名气,它在计算录取分数线的时候,
采用以下办法:总人数乘以录取百分比,得到录取人数k后,
从最高分开始数k个人,这个人的中考分数就作为
这所学校的录取分数线了。

输入:
有多个测试点,每个测试点第一行是n和k(k<=n),
n是总人数,总人数不超过1e6,k是录取的人数
第二行就是n个学生的中考分数,由于采用一种
特殊的标准计分方式,分数范围在0至1e8

输出:
对每个测试点输出对应的分数线,一个结果一行

样例输入:
7 3
1 2 3 4 5 6 7

样例输出:
5

最开始用插入,第三组用例超时:

 

 1#include <iostream>
 2using namespace std;
 3int main()
 4{
 5    unsigned int numTotal,numEnroll;
 6    while(EOF!=scanf("%u %u",&numTotal,&numEnroll) && numTotal!=0 && numEnroll!=0)
 7    {
 8        unsigned int * pdataDes=new unsigned int[numEnroll];
 9        unsigned int * pdataSrc=new unsigned int[numTotal];
10        memset(pdataDes,(unsigned int)0,numEnroll*sizeof(unsigned int));
11        for(int i=0;i<numTotal;i++)
12        {
13            scanf("%u",&pdataSrc[i]);
14        }

15        for(int i=0;i<numTotal;i++)
16        {
17            for(int j=0;j<numEnroll;j++)
18            {
19                if(pdataSrc[i]>pdataDes[j])
20                {
21                    for(int k=numEnroll-1;k>j;k--)
22                        pdataDes[k]=pdataDes[k-1];
23                    pdataDes[j]=pdataSrc[i];
24                    break;
25                }

26            }

27        }

28        printf("%u\n",pdataDes[numEnroll-1]);
29        memset(pdataDes,0,numEnroll*sizeof(unsigned int));
30        delete [] pdataDes;
31        delete [] pdataSrc;
32    }

33    return 0;
34}

结果:
Test  1:    Accepted    Time = 0 ms
Test  2:    Accepted    Time = 48 ms
Test  3:    Time Limit Exceed
--------------------------------
Problem ID     ct8_2
Test Result    Time Limit Exceed
Time Limit     5000 ms
Total Memory   5416 Kb / 65000 Kb
Code Length    1066 Bytes

后来改为统计第n大的数,直接输出。。本以为减少了内存读写操作能好些,结果第二组用例居然更慢了。。。

 1#include <iostream>
 2using namespace std;
 3int main()
 4{
 5    unsigned int numEnroll,numTotal,temp,curMax;
 6    while(EOF!=scanf("%u %u",&numTotal,&numEnroll))
 7    {
 8        unsigned int * pdata=new unsigned int[numTotal];
 9        memset(pdata,0,numEnroll*sizeof(unsigned int));
10        unsigned int i;
11        for(i=0;i<numTotal;i++)
12        {
13            scanf("%u",&pdata[i]);
14        }

15        i=0;
16        
17        unsigned int count=1;
18        while(count<=numEnroll)
19        {
20            int flag=0;
21            curMax=0;
22            for(int j=0;j<numTotal;j++)
23            {
24                if(curMax<pdata[j])
25                {
26                    flag=j;
27                    curMax=pdata[j];
28                }

29            }

30            pdata[flag]=0;
31            count++;
32        }

33        printf("%u\n",curMax);
34        delete [] pdata;
35    }

36    return 0;
37}

38

结果:
Test  1:    Accepted    Time = 0 ms
Test  2:    Accepted    Time = 68 ms
Test  3:    Time Limit Exceed
--------------------------------
Problem ID     ct8_2
Test Result    Time Limit Exceed
Time Limit     5000 ms
Total Memory   4000 Kb / 65000 Kb
Code Length    905 Bytes

后来改为快速排序,这回快了一些,但是第四组用例仍然超时:

 1#include <iostream>
 2using namespace std;
 3#define max 1000000
 4int pdata[max]={0};
 5void swap(int *a,int *b)
 6{
 7    int temp=*a;
 8    *a=*b;
 9    *b=temp;
10}

11int partition(int *a,int begin,int end)
12{
13    int i=begin-1;
14    for(int j=begin;j<end;j++)
15    {
16        if(a[j]<=a[end])
17        {
18            i+=1;
19            swap(&a[i],&a[j]);
20        }

21    }

22    swap(&a[i+1],&a[end]);
23    return i+1;
24}

25void myqsort(int *a,int begin,int end)
26{
27    if(begin<end)
28    {
29        int i=partition(a,begin,end);
30        myqsort(a,begin,i-1);
31        myqsort(a,i+1,end);
32    }

33}

34int main()
35{
36    int numTotal,numEnroll;
37    while(EOF!=scanf("%u %u",&numTotal,&numEnroll))
38    {
39        //int *pdata = new int [numTotal];
40        memset(pdata,0,numTotal*sizeof(int));
41        for(int i=0;i<numTotal;i++)
42            scanf("%u",&pdata[i]);
43        myqsort(pdata,0,numTotal-1);
44        printf("%u\n",pdata[numTotal-numEnroll]);
45        //delete [] pdata;
46    }

47    return 0;
48}

结果:

 

Test  1:    Accepted    Time = 0 ms
Test  2:    Accepted    Time = 26 ms
Test  3:    Accepted    Time = 4246 ms
Test  4:    Time Limit Exceed
--------------------------------
Problem ID     ct8_2
Test Result    Time Limit Exceed
Time Limit     5000 ms
Total Memory   4032 Kb / 65000 Kb
Code Length    934 Bytes

由于快速排序导致大量递归浪费时间空间,所以考虑要减少递归次数。由于要找第n大的数,所以没有必要对所有数据都排序,又找到了快速选择算法。。

 

 1#include <iostream>
 2#include <ctime>
 3using namespace std;
 4int pdata[1000000]={0};
 5void swap(int *a, int *b)
 6{
 7    int temp=*a;
 8    *a=*b;
 9    *b=temp;
10}

11int partition(int *a, int begin, int end)
12{
13    swap(&a[rand()%(end-begin+1)],&a[end]);
14    int i=begin-1;
15    for(int j=0;j<end;j++)
16    {
17        if(a[j]<=a[end])
18        {
19            i++;
20            swap(&a[i],&a[j]);
21        }

22    }

23    swap(&a[i+1],&a[end]);
24    return i+1;
25}

26int qksel(int *a, int n, int begin, int end)
27{
28    int temp=partition(a,begin,end);
29    if(n==temp)return a[temp];
30    else if(n<temp) return qksel(a,n,begin,temp-1);
31    else return qksel(a+temp+1,n-temp-1,0,end-temp-1);
32}

33int main()
34{
35    srand((unsigned int)time(NULL));
36    int numTotal,numEnroll;
37    while(EOF!=scanf("%d %d",&numTotal,&numEnroll))
38    {
39        for(int i=0;i<numTotal;i++)
40            scanf("%d",&pdata[i]);
41        int temp=qksel(pdata,numTotal-numEnroll,0,numTotal-1);
42        printf("%d\n",temp);
43    }

44    return 0;
45}

 

 

终于。。。。

Test  1:    Accepted    Time = 0 ms
Test  2:    Accepted    Time = 21 ms
Test  3:    Accepted    Time = 3187 ms
Test  4:    Accepted    Time = 3248 ms
--------------------------------
Problem ID     ct8_2
Test Result    Accepted
Total Time     6456 ms
Total Memory   4032 Kb / 65000 Kb
Code Length    1030 Bytes

后记:这题做了整整两天提交了n多次,没心思再细抠了。。

快速选择算法描述是看老外写的,看得不一定明白。。链接如下

http://www.ics.uci.edu/~eppstein/161/960125.html

也不知道是不是这么回事,

另外看别人提交的答案有个强悍的家伙四组用例一共才用不到1500ms,

我这个排序写得肯定很傻很天真,请高手指出问题,我爱你们 

 

posted on 2009-06-14 07:26  youthlion  阅读(197)  评论(0编辑  收藏  举报

导航