您的位置:首页 > 其它

算法导论 第八章:线性时间排序

2015-07-14 21:20 681 查看

1.计数排序(Counting sort)

   其基本思想是:对于每一个元素x,确定小于x的元素的个数,然后直接将x放在输出数组的合适位置中。

其伪代码如下:



EG:





每个输入的元素的范围是0~k,k 不能太大,如果太大,分配给C的内存就会很大!当k=O(n)时,该算法的时间复杂度为:Θ(n)。此外计数排序是稳定排序,这一思想在接下来介绍的基数排序中很有用。

计数排序完整代码如下:

#include<iostream>
#include<climits>
using namespace std;

void Print(int *a)
{
int n=a[0];
for(int i=1;i<=n;i++)
cout<<a[i]<<"   ";
cout<<endl;
}
int *Transform(int *a,int n)
{
int *A=new int[n+1];
A[0]=n;
for(int i=0;i<n;i++)
A[i+1]=a[i];
return A;
}
int getMaxNum(int *a)
{
int n=a[0];
int max=INT_MIN;
for(int i=1;i<=n;i++)
if(a[i]>max)
max=a[i];
return max;
}
int *CountingSort(int *A)
{
int n=A[0];
int *B=new int[n+1];
int m=getMaxNum(A);
int *C=new int[m+1];

for(int i=0;i<=m;i++)
C[i]=0;
for(int i=1;i<=n;i++)
C[A[i]]=C[A[i]]+1;
for(int i=1;i<=m;i++)
C[i]=C[i]+C[i-1];
for(int i=n;i>=1;i--)
{
B[C[A[i]]]=A[i];
C[A[i]]--;
}
B[0]=n;
return B;
}
int main()
{
int a[]={2,5,3,3,24,12,5,8};
int n=sizeof(a)/sizeof(int);
int *A=new int[n+1];
int *B=new int[n+1];   //store the sorted result
A=Transform(a,n);  //a[0..n-1]->A[1..n];A[0]=a.length
B=CountingSort(A);
Print(B);
return 0;
}


运行结果:



2.基数排序(Radix sort)

对于每个数位采用计数排序,由于计数排序是稳定的,这将能保证基数排序的准确性。不过必须从最不重要的数位先开始排。

伪代码如下:



EG:



 注意:

1)给定n个d位数字(d-digit),每个数位可能取k中可能的值。基数排序算法总能以Θ(d(n+k))的时间正确对这些数进行排序。当d为常数,k=O(n)时,基数排序有线性运行时间。

2)给定n个b位数(b-bit)和任意的r≤b,基数排序能在Θ((b/r)(n+2^r))时间内正确对这些数进行排序。当b ≤ lgn 时,r=b; 当 b > lg n 时,r=Llgn」,这时的运行时间为Θ(bn/lgn).

基数排序完整代码如下:

#include<iostream>
#include<climits>
using namespace std;

void Print(int *a)
{
int n=a[0];
for(int i=1;i<=n;i++)
cout<<a[i]<<"   ";
cout<<endl;
}
int *Transform(int *a,int n)
{
int *A=new int[n+1];
A[0]=n;
for(int i=0;i<n;i++)
A[i+1]=a[i];
return A;
}
int getMaxNum(int *a)
{
int n=a[0];
int max=INT_MIN;
for(int i=1;i<=n;i++)
if(a[i]>max)
max=a[i];
return max;
}
int *getDigit_d(int *a,int d)
{
int n=a[0];
int pow_d=1;
int temp;
int *dA=new int[n+1];

for(int i=1;i<d;i++)
pow_d*=10;

for(int i=1;i<=n;i++)
{
temp=a[i];
temp=temp/pow_d;
temp=temp%10;
dA[i]=temp;
}
dA[0]=n;
}

int *CountingSort(int *A,int d)
{
int n=A[0];
int m;
int *B,*C;
int *digitA=new int[n+1];
digitA=getDigit_d(A,d);

m=getMaxNum(digitA);
B=new int[n+1];
C=new int[m+1];

for(int i=0;i<=m;i++)
C[i]=0;

for(int i=1;i<=n;i++)
C[digitA[i]]=C[digitA[i]]+1;

for(int i=1;i<=m;i++)
C[i]=C[i]+C[i-1];

for(int i=n;i>=1;i--)
{
B[C[digitA[i]]]=A[i];
C[digitA[i]]--;
}
B[0]=n;
return B;
}

int *RadixSort(int *a)
{
int n=a[0];
int t;
int d=1;    //the digit of number
int max=getMaxNum(a);
t=max;
while(1)
{
if(t>=10)
{
t=t/10;
d++;
}
else
break;
}    //compute d

for(int i=1;i<=d;i++) //sort a by d-digit using Counting Sort
a=CountingSort(a,i);
return a;
}
int main()
{
int a[]={2329,5457,8657,6839,4336,7520,2355};
int n=sizeof(a)/sizeof(int);
int *A=new int[n+1];
int *B=new int[n+1];   //store the sorted result
cout<<"Before sorting:"<<endl;
A=Transform(a,n);  //a[0..n-1]->A[1..n];A[0]=a.length
Print(A);
cout<<"After sorting"<<endl;
B=RadixSort(A);
Print(B);

return 0;
}
运行结果:



3.桶排序(Bucket sort)

   当桶排序的输入符合均匀分布时,即可以线性时间运行。伪代码如下:



EG:



性能分析:

运行时间为:



所以有:



其中,

                


即使输入不均匀时,只要各桶的尺寸的平方和与总元素个数成线性关系,则仍可以以线性时间运行。

桶排序完整代码如下:

#include<iostream>
#include<cstdlib>
#include<ctime>
#include<iomanip>
using namespace std;

struct Node{
double key;
Node *next;
};
void Print(double *a,int n)
{
for(int i=0;i<n;i++)
{
cout<<setw(10)<<a[i];
if((i+1)%10==0)
cout<<endl;
}
cout<<endl;
}
void OutBucketData(Node *b,double *a,int n)
{//rearrange the Bucket into array a
Node *p;
int j=0;
for(int i=0;i<n;i++)
{
p=b[i].next;
if(p==NULL)
continue;
while(p !=NULL)
{
a[j++]=p->key;
p=p->next;
}
}
}
void InsertDataToBucket(Node *bucket,int i,double k)
{//using linked list to insert k into bucket[i] in an ascending.
Node *s,*q;

s=new Node(); //store k into node s
s->key=k;
s->next=NULL;

q=&bucket[i];
while(q->next !=NULL )
{
if(q->key <= s->key && s->key < q->next->key) //insert node s
{
s->next=q->next;
break;
}
q=q->next;
}
q->next=s;
}
void BucketSort(double *a,int n)
{
Node *Bucket =new Node
;
for(int i=0;i<n;i++)
{
Bucket[i].key=(double)i/n;
Bucket[i].next=NULL;
}
for(int i=0;i<n;i++)
{
int bucket_i=a[i]*n;
InsertDataToBucket(Bucket,bucket_i,a[i]);
}
OutBucketData(Bucket,a,n);
}
void getRandNum(double *a,int n)
{
srand(time(NULL));
for(int i=0;i<n;i++)
a[i]=(double)rand()/RAND_MAX;
}
int main()
{
//double a[]={0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.68};
//int n=sizeof(a)/sizeof(double);
int n;
cout<<"Please input the number n
ac7a
:";
cin>>n;
double *a=new double
;
getRandNum(a,n);
cout<<"Before sorting with Bucket sort:"<<endl;
Print(a,n);
BucketSort(a,n);
cout<<"After sorting with Buket sort"<<endl;
Print(a,n);

return 0;
}
运行结果:



【注:如若有错误,请指正~~~】
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息