刚在csdn论坛上看到一个“关于1-n自然数排序的华为面试题”的帖子,勾起了我的回忆;我大二时有段时间闲得没事干,想做一个int型的数组排序,达到时间复杂度为O(n)的目的,同学都因为n*log2(n)说这不可能,但自己做完后感觉不错,虽做不到o(n),但自认为时间复杂度为o(n+t),大家鉴别鉴别是不是这样的.我设计的算法是:
1、扫描要排序数组a,找出最大值 t
2、构造二维数组 b[t][2],将其中所有元素置零
3、再扫描数组a,碰到一个元素i:若b[i-1][0]为0, 就将b[i-1][0]置为i,否则将b[i-1][1]加一
4、从后往前扫描数组b,碰到不为0的B[i][0]:若b【i】【1】为0,就将c[j]置为这个数b[i][0]
(j初值为n-1),并将j减一,若b【i】【1】不为0
也将c[j]置为这个数b[i][0] (j初值为n-1),并将j减一再减去B[i][1]的值(说明有几个重复的数字)
5、再从后往前扫描数组C,每碰到0就将其置为其后面紧跟的元素,c 即就是排好序的a数组了。
其代码是:(vs2008上)
#include<iostream>
using namespace std;
void main()
{
int temp=0;
int k=0,n;
int t=0;
cout<<"数组的大小:"<<endl; //要排序数组的大小
cin>>n;
int *a = new int[n];int *c= new int[n]; //动态定义2个一维数组
//int c[20];int a[20];
for(int i=0;i<n;i++){ //循环,让用户输入要排序的每个数字
cout<<"输入数字:"<<endl;
cin>>a[i];
}
for(int i=1;i<n;i++) //找出数组中最大的元素放在a[n-1]
if(a[i-1]>a[i]){
temp=a[i-1];
a[i-1]=a[i];
a[i]=temp;
}
t=a[n-1];
cout<<"数组中最大的数字是:"<<t<<endl;
// int* b = new int[t+1][2]; // 动态定义二维数组b[t][2]
int **b;
b = new int *[t+1];// 动态定义二维数组b[t][2]
for(int m=0;m<t+1;m++)
b[m]=new int [2];
for(int i=0;i<=t;i++) {b[i][0]=0; b[i][1]=0;} //循环使b数组中所有的元素为0(数组中有0可以换为-1)
for(int i=0;i<n;i++)
{ c[i]=0; //将c数组中元素置为0
if(b[a[i]-1][0]==0) //扫描a数组,找出a[i]的大小,比如为100,这时就判断b[99][0]是否为0,如果不为零
b[a[i]-1][0]=a[i]; //则将b[99][0]置为a[i],即b[99][0]=100,否则
else //将b[99][1]中的数字加1,记录的是这个元素重复的次数
b[a[i]-1][1]++;
}
int j ;
j=n-1;
int i=t-1; //i=t-1,这时用循环扫描b数组
while(i>=0){
if(b[i][0]!=0) //如果b数组第一行中某一个元素不为零,则做以下操作
if(b[i][1]==0)
{
c[j]=b[i][0];j--;//如果b数组第二行中这个元素为0,直接将其对应上一行中的数值赋予给c[j],j初值是n-1,做了赋值,就将J减1
}
else //否则,即b 数组第二行中这个元素不为0,也要将其对应上一行中的数值赋予给c[j],
//但此时J减1后还要减去b数组第二行中这个元素的值(因为有这么多个重复的元素)
{
c[j]=b[i][0];
j=j-b[i][1]-1;
}
i--;
} //做完此循环,c数组中有了a数组中的所有元素(小到大排列好了),但每个数字只有一个,有重复的地方是0
i=n-2;
while(i>=0){ //从后往前扫描c数组,如果碰到0就将其换为其后面的那个元素
if(c[i]==0)
c[i]=c[i+1];
i--;
}
cout<<"小到大排序后的结果为:"<<endl;//输出排序好的数组
for(i=0;i<n ;i++)
cout<<c[i]<<" ";
cout<<endl;
for(i=0;i<t+1;i++) //释放空间
delete []b[i];
delete b;
delete []a;
delete []c;
system("pause");
}
说明:以上代码只写了正整数(除0)的排序;如果a中有元素0,只用在初始化b和c的时候将0改为-1即可;如果a数组中有负数,在初始化b和c的时候就要将0改为负无穷大了,并且在开始阶段将a数组分为2个数组,一个只有负数,一个只有正数,然后分别考虑即可。
这样对于数字个数很多,比较集中且不是很大的话,跑得蛮快的。
当然程序是2年前写的,有些考虑不周,与不规范的地方,现在也没有太多时间去修改,希望看到的朋友批评指正。