时间复杂度为O(n+t)的排序

刚在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年前写的,有些考虑不周,与不规范的地方,现在也没有太多时间去修改,希望看到的朋友批评指正。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值