时间为O(n)排序——计数排序

【题 目】某公司有几万名员工,请完成一个时间复杂度为O(n)的算法对该公司员工的年龄进行排序,可以使用O(1)的辅助空间。

 

【思 路】在数据结构和算法的学习中,排序肯定是重中之重,然而仔细回想我们学习过的排序算法,无论是冒泡排序,归并排序,插入排序,希尔排序,甚至著名的快速排序,时间复杂度都达不到O(n),这些算法的时间复杂度要么为O(n2),要么为O(nlogn),然而这道题却要求我们用O(n)的时间复杂度排序,到底是什么原因呢?

  通过简单的思考,我们发现,员工虽然有几万名,但是要排序的年龄却不是只有几万种,我们考虑一个人正常的工作年龄22——60岁,再发到范围也不过0——99岁(夸张了点),那也只有100个数字,换句话说,我们要排序不是几万个数字,而只是几万个重复出现在区间『0,100』的数字。这样,我们容易想到,我们用一个年龄的计数器数组来记录没一个年龄出现了多少次,age[24]表示年龄为24的员工人数。对全部员工做完如此的统计工作后,我们就可以按照这个数组来进行简单的“数数”工作就行了。

  具体的代码如下:

复制代码
 1 #include<iostream>
 2 #include<string>
 3 #include<ctime>
 4 #include<cstdlib>
 5 #define random(x) (rand()%x)
 6 using namespace std;
 7 
 8 void SortAges(int employeeAge[],int length)
 9 {
10     //无效输入
11     if(employeeAge == NULL || length < 0)
12         return;
13 
14     //计数器数字age[],定义,初始化
15     const int maxAge = 99;
16     int age[maxAge + 1];
17     for(int i = 0;i <= maxAge;++i)
18     {
19         age[i] = 0;
20     }
21 
22     //计算器数组统计每个年龄出现的次数
23     for(int j = 0;j < length;++j)
24     {
25         int tempage = employeeAge[j];
26         if(tempage < 0 || tempage > maxAge)
27         {
28             cout<<"ERROR:the age is not in the valid range!"<<endl;
29         }
30 
31         age[tempage]++;
32     }
33 
34     //根据计数器数组重新排列“员工年龄”数组的顺序
35     int index = 0;
36     for(i = 0;i <= maxAge;++i)
37     {
38         for(int j = 0;j < age[i];++j)
39         {
40             employeeAge[index] = i;
41             index++;
42         }
43     }
44 }
45 
46 int main()
47 {
48     //定义员工年龄数组,随机赋值[0.99]
49     int empAge[100];
50     srand((int)time(0));
51     for(int i = 0;i < 100;++i)
52     {
53         empAge[i] = random(100);
54     }
55 
56     cout<<"the original age list is:"<<endl;
57     for(i = 0;i < 100;++i)
58     {
59         cout<<empAge[i]<<"\t";
60         //if((i + 1) % 20 == 0)
61 //cout<<endl;
62     }
63     
64     SortAges(empAge,100);
65 
66 
67     cout<<"******************************************************************************"<<endl;
68     cout<<"the sorted age list is:"<<endl;
69     for(i = 0;i < 100;++i)
70     {
71         cout<<empAge[i]<<"\t";
72         //if((i + 1) % 20 == 0)
73 //cout<<endl;
74     }
75 
76     return 0;
77 
78 }
复制代码

  为简便起见,笔者设公司只有100个员工,每个员工的年龄取[0,99]之间的随机数,得到程序的运行情况如下:

  反思:该算法用长度为100的定长度作为“过渡”,首相将要排序的数组进行统计,统计结果用定长数组(即前面提到的计数器数组)存储,然后对定长数组“数数”,然后将结果写入原来需要排序的数组,由于不管员工的数量N为多大(几万,十几万),所需要的数组长度都为100,因为年龄的是受限范围为[0,99]获得了时间复杂度为O(n)的排序算法,也算是用空间换取时间了。

 


Reference:

时间为O(n)的排序:http://zhedahht.blog.163.com/blog/static/25411174201131184017844/

注:

1)本博客所有的代码环境编译均为win7+VC6。所有代码均经过博主上机调试。

2)博主python27对本博客文章享有版权,网络转载请注明出处http://www.cnblogs.com/python27/。对解题思路有任何建议,欢迎在评论中告知。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值