O(n)时间的排序


本文转自:http://zhedahht.blog.163.com/blog/static/25411174201131184017844/


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

分析:排序是面试时经常被提及的一类题目,我们也熟悉其中很多种算法,诸如插入排序、归并排序、冒泡排序,快速排序等等。这些排序的算法,要么是O(n2)的,要么是O(nlogn)的。可是这道题竟然要求是O(n)的,这里面到底有什么玄机呢?

                题目特别强调是对一个公司的员工的年龄作排序。员工的数目虽然有几万人,但这几万员工的年龄却只有几十种可能。上班早的人一般也要等到将近二十岁才上班,一般人再晚到了六七十岁也不得不退休。

                由于年龄总共只有几十种可能,我们可以很方便地统计出每一个年龄里有多少名员工。举个简单的例子,假设总共有5个员工,他们的年龄分别是2524262425。我们统计出他们的年龄,24岁的有两个,25岁的也有两个,26岁的一个。那么我们根据年龄排序的结果就是:2424252526,即在表示年龄的数组里写出两个24、两个25和一个26

#include <iostream>
using namespace std;

//假定工作年龄为0-100,通过调节MAXAGE的大小来控制年龄大小
#define MAXAGE 101

bool invaluedInput = false;

bool HashSort(int ages[],int len)
{
	if(NULL == ages || len<=0)
	{
		invaluedInput = true;
		return false;
	}
	//借助一个临时数组,记录每个年龄的人数
	int tmp[MAXAGE] = {0};
	int i = 0;
	for(i=0 ;i<len; i++)
	{
		//数组元素不合法,退出程序
		if(ages[i]<0 || ages[i]>=MAXAGE)
		{
			cout<<"invaluedInput"<<endl;
			invaluedInput = true;
			return false;
		}

		tmp[ages[i]]++;
	}
	int index = 0;
	
	for(i=0; i<MAXAGE; i++)
	{
		if(tmp[i] != 0)
		{
			while(tmp[i] != 0)
			{
				ages[index++] = i;
				tmp[i]--;
			}
		}
	}

	return true;
}

int main()
{
	int ages[] = {3,5,7,43,3,2,5,8,5,10,4,7,5};
	int len = sizeof(ages)/sizeof(int);
	int i = 0;
	for(i=0; i<len; i++)
		cout<<ages[i]<<" ";
	cout<<endl;
	HashSort(ages,len);
	if(invaluedInput)
		cout<<"invaluedInput"<<endl;
	else
	{
		for(i=0; i<len; i++)
			cout<<ages[i]<<" ";
		cout<<endl;
	}
}

    在上面的代码中,允许的范围是 0 100 岁。数组 tmp中 用来统计每个年龄出现的次数。某个年龄出现了多少次,就在数组 ages 里设置几次该年龄。这样就相当于给数组 ages 排序了。该方法用长度 101 的整数数组辅助空间换来了 O(n) 的时间效率。由于不管对多少人的年龄作排序,辅助数组的长度是固定的 101 个整数,因此它的空间复杂度是个常数,即 O(1)

这道题的巧妙之处在于,要排序的数组元素大小的范围是固定在一个较小的范围内。所以可以对数组中每个元素建立哈希值,进行处理。

转载的博客后面有人评论提出问题:这个题目有一个变种,我之前面过,针对这个问题可以表示成,按照年龄,将所有员工排序,这时候,员工的信息就和他的年龄绑定了,不能简单的只记录每个年龄的人数,大家可以思考下,不过其实只加一点东西就好。

我理解的是:数组中存储的是包含每个人信息的结构体,不在是一个单纯的整型值。那问题是怎么对这个包含结构体的数组进行排序,并符合题目0(n)时间复杂度,O(1)空间复杂度呢?


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值