算法导论 第八章:线性时间排序
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;
}
运行结果:
【注:如若有错误,请指正~~~】
相关文章推荐
- python算法学习之计数排序实例
- python计数排序和基数排序算法实例
- 经典算法:基数排序的小例子
- java算法导论之FloydWarshall算法实现代码
- python简单实现基数排序算法
- Red-Black Tree 的Java实现
- 逆序对
- 算法导论之堆
- LCS 最长公共子序列
- 使用Java完成《算法导论》习题2.2-2
- 使用Java完成《算法导论》习题2.3-2
- 使用Java完成《算法导论》习题2.3-4
- 使用Java完成《算法导论》习题2.3-5
- 使用Java完成《算法导论》习题2.3-6
- 使用Java完成《算法导论》习题2.3-7
- 快速排序个人理解
- 笔记一(算法基础)
- Chapter2 Getting Started
- Chapter3 Growth of Functions
- 计数排序