今天中午的腾讯的技术面试,考官问我一个文件里有很多QQ号,怎么排序。
我当时就回答内存够就快排,并归,不够的话就多线程多计算机,他说如果电脑好挫,单核单线程怎么办,有没有更快的,我想了一会就说我不知道,考官说没关系,考官人挺好的。面下来不会太紧张。但是不知道能不能过。
今天下午回来就在网上搜比快排还快的算法发现有两个主流算法一个计数排序http://blog.csdn.net/tanyujing/article/details/8534843和桶排序http://blog.csdn.net/houapple/article/details/6480100还有一个在贴吧看到的倍增排序,http://blog.csdn.net/hachirou/article/details/6381642(用pascal写的)
上面那个倍增排序算法写的不错,但代码就感觉有些别扭。(可能是我理解能力差orz)
计数排序要求数集中在一个区间,而桶排序则要求数均匀分布。QQ号从6位(我见过最短的,可能还有更短的吧)到现在10位,区间太大。主要集中在9位,所以我觉得计数和桶排序的效果都不会太好。然后我看到了倍增算法。
下面我来说说我对倍增算法的理解(有错请指出,第一次写blog。。)
先是基于余数进行一次计数排序,再把排序好的结果基于商进行 一次计数排序,就排好了。
计数排序请看我上面的那个连接,写的浅显易懂。
时间复杂度:O(n+maxsqrt(m));(m是所有数里面最大的正整数)
以下是c++代码实现,跟那个pascal是有些不同的(自己敲的,有错请指出):
#include <iostream>
#include<stdlib.h>
#include<ctime>
using namespace std;
const int maxn=1000000;//数组最长的长度
const int maxsqrt=65536;//unsigned maxint是2的32次方-1;sqrt(maxint)
int a[maxn],b[maxn];//输入数组和过渡数组
int output[maxn];//输出数组
int d[maxsqrt],m[maxsqrt];//d[]商 m[]余数
int main()
{
/*int test=65536;
cout<<test%maxsqrt<<endl;
cout<<test/maxsqrt<<endl;
cout<<(test&(maxsqrt-1))<<endl;
cout<<(test>>16)<<endl;*/ //这段代码说明了求商求余可以用位运算加速
int n;
cin>>n;
srand((unsigned)time( NULL ) );//使随机数不同
for (int i=0;i<n;i++)
{
a[i]=rand()%maxn;
//cin>>a[i];
d[a[i]/maxsqrt]++;
m[a[i]%maxsqrt]++;//用于商和余数的计数,可以用位运算加速
}
for (int i=1;i<maxsqrt;i++)
{
d[i]+=d[i-1];
m[i]+=m[i-1];
}//计数排序的第一步,记录计数和
for (int i=n-1;i>=0;i--)
{
b[m[a[i]%maxsqrt]-1]=a[i];
m[a[i]%maxsqrt]--;
}//基于余数进行计数排序,并把结果存到b[]
for (int i=n-1;i>=0;i--)
{
output[d[b[i]/maxsqrt]-1]=b[i];
d[b[i]/maxsqrt]--;
}//对b[]进行基于商的排序,这样就排好序
for (int i=0;i<n;i++)
{
cout<<output[i]<<endl;
}//输出
system("pause");
}