6:希尔排序(不稳定 时间复杂度O(1.6n1.25) )
#include //希尔排序
using namespace std;
void ShellPass( double *dArr, int account, int increment )
{
int j = 0;
for( int i=increment+1; i<=account; i++)
{
if(dArr[i]0&&dArr[0]1 );
}
int main()
{
double darr[10] = { 0, 1.0, 2.0 ,6.3, 3.5, 8.3, 0.43, 9, 10, 2.2 };
ShellSort(darr, 9);
for( int i=1; i<=9; i++)
{
cout<
1.增量序列的选择
Shell排序的执行时间依赖于增量序列。
好的增量序列的共同特征:
① 最后一个增量必须为1;
② 应该尽量避免序列中的值(尤其是相邻的值)互为倍数的情况。
有人通过大量的实验,给出了目前较好的结果:当n较大时,比较和移动的次数约在nl.25到1.6n1.25之间。
2.Shell排序的时间性能优于直接插入排序
希尔排序的时间性能优于直接插入排序的原因:
①当文件初态基本有序时直接插入排序所需的比较和移动次数均较少。
②当n值较小时,n和n2的差别也较小,即直接插入排序的最好时间复杂度O(n)和最坏时间复杂度0(n2)差别不大。
③在希尔排序开始时增量较大,分组较多,每组的记录数目少,故各组内直接插入较快,后来增量di逐渐缩小,分组数逐渐减少,而各组的记录数目逐渐增多,但由于已经按di-1作为距离排过序,使文件较接近于有序状态,所以新的一趟排序过程也较快。
因此,希尔排序在效率上较直接插人排序有较大的改进。
3.稳定性 希尔排序是不稳定的。参见上述实例,该例中两个相同关键字49在排序前后的相对次序发生了变化。
7:归并排序(稳定 时间复杂度O(nlogn))
#include //归并排序
using namespace std;
void Merge( double *dArr, int plow, int pmid, int phigh)
{
double *dTemp = new double[phigh-plow+1];
int i = 0;
int j = 0;
int p = 0;
int low = plow;
int mid = pmid;
int high = phigh;
i = low;
j = mid+1;
while( i<=mid&&j<=high )
{
if( dArr[i]mid )
{
for( int w=j; w<=high; w++)
{
dTemp[p]=dArr[w];
p++;
}
}
if( j>high )
{
for( int w=i; w<=mid; w++)
{
dTemp[p]=dArr[w];
p++;
}
}
for( int w=low; w<=high; w++)
{
dArr[w]=dTemp[w-low]; //w-low这里出错了 一定要小心
}
}
void MergeSort( double *dArr, int low, int high)
{
int mid = 0;
if( low
设有两个有序(升序)序列存储在同一数组中相邻的位置上,不妨设为A[l..m],A[m+1..h],将它们归并为一个有序数列,并存储在A[l..h]。
8:桶排序(稳定 时间复杂度O(n))
#include
#include
#include
using namespace std; //桶排序
struct StNode {
double key;
struct StNode *next;
};
int main()
{
srand((unsigned)time(NULL));
StNode node[10];
StNode bucket[10];
for( int j=0; j<10; j++)
{
bucket[j].key = 0;
bucket[j].next = NULL;
}
for( int i=0; i<10; i++)
{
node[i].key = rand()%100*0.01;
node[i].next = NULL;
}
for( int w=0; w<10; w++)
{
int num = node[w].key*10/1;
if( bucket[num].next==NULL )
{
bucket[num].next=&node[w];
}
else
{
StNode *temp = NULL; //临时节点的位置信息
StNode *pre = NULL; //保存前一个节点的位置
temp = bucket[num].next;
pre = &bucket[num];
while( node[w].key>temp->key&&temp!=NULL )
{
pre = temp;
temp = temp->next;
}
node[w].next = temp;
pre->next = &node[w];
}
}
for( int t=0; t<10; t++)
{
if( bucket[t].next!=NULL )
{
StNode *temp = NULL;
temp = bucket[t].next;
do{
cout<key<<" ";
temp = temp->next;
}while( temp!=NULL ); //这里出错过 小心!
}
}
cout<
桶排序的平均时间复杂度是线性的,即O(n)。但最坏情况仍有可能是O(n2)。
箱排序只适用于关键字取值范围较小的情况,否则所需箱子的数目m太多导致浪费存储空间和计算时间。
9:基数排序(稳定 时间复杂度O(d(n+radix)))
时间效率:设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix));
#include //基数排序
using namespace std;
int main()
{
int data[10] = {73,22,93,43,55,14,28,65,39,81};
int narr[10][10] = { 0 };
int order[10] = { 0 };
int i = 0;
int j = 0;
int k = 0;
int n = 1;
int lsd = 0;
int temp = 0;
while( n<=10 )
{
for(int i=0; i<10; i++)
{
temp = data[i]/n;
lsd=temp%10;
narr[lsd][order[lsd]]=data[i];
order[lsd]++;
}
for(int j=0; j<10; j++)
{
if(order[j]!=0)
{
for(int h=0; h
10:计数排序(时间复杂度O(n))
#include //计算排序
using namespace std;
void COUNT_SORT( int *A,int countA, int *B, int k)
{
int *C = (int *)malloc(sizeof(int)*k);
int i = 0;
for(i=0; i
我们看到,计数排序算法没有用到元素间的比较,它利用元素的实际值来确定它们在输出数组中的位置。因此,计数排序算法不是一个基于比较的排序算法,从而它的计算时间下界不再是Ω(nlogn)。另一方面,计数排序算法之所以能取得线性计算时间的上界是因为对元素的取值范围作了一定限制,即k=O(n)。如果k=n2,n3,..,就得不到线性时间的上界。我们看到,计数排序算法没有用到元素间的比较,它利用元素的实际值来确定它们在输出数组中的位置。因此,计数排序算法不是一个基于比较的排序算法,从而它的计算时间下界不再是Ω(nlogn)。另一方面,计数排序算法之所以能取得线性计算时间的上界是因为对元素的取值范围作了一定限制,即k=O(n)。如果k=n2,n3,..,就得不到线性时间的上界。