算法導論 第八章:線性時間排序

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;
	}
運行結果:



【注:如若有錯誤,請指正~~~】




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章