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[n];
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:";
cin>>n;
double *a=new double[n];
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;
}
運行結果:
【注:如若有錯誤,請指正~~~】