您的位置:首页 > 编程语言 > C语言/C++

浅谈C++之冒泡排序、希尔排序、快速排序、插入排序、堆排序、基数排序性能对比分析(好戏在后面,有图有真相)

2013-11-04 17:40 459 查看
//冒泡排序
//////////////////////////////////////////////////////////////////////////
void BubleSort(int a[],int n)
{
int temp;
bool flag=false;
for (int i=0;i<n;i++)
{
flag=true;
for (int j=0;j<n-i-1;j++)
{
if(a[j]>a[j+1])
{
temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
flag=false;
}
}
if(flag) break;
}
}


冒泡排序的时间复杂度为O(n²),在数据比较小的情况下各个算法效率差不多。

希尔排序:

  以前竟然没有发现,希尔排序如此短小精悍的代码。其效率很多时候并不输给快速排序其时间复杂度为O(nlogn)。

void ShellSort(int array[],int length)

{

int d = length/2;   //设置希尔排序的增量
int i ;
int j;
int temp;
while(d>=1)
{
for(i=d;i<length;i++)
{
temp=array[i];
j=i-d;
while(j>=0 && array[j]>temp)
{
array[j+d]=array[j];
j=j-d;
}
array[j+d] = temp;
}
//Display(array,10);
d= d/2;    //缩小增量
}
}

快速排序:

//快速排序
///////////////////////////////////////
void Swap(int &a,int &b)
{
int temp;
temp=a;
a=b;
b=temp;
}

int Partition(int a[],int p,int r)
{
int i=p;
int j=r+1;
int x=a[p];
while (true)
{
while(a[++i]<x&&i<r);
while(a[--j]>x);
if (i>=j)break;
Swap(a[j],a[i]);

}
a[p]=a[j];
a[j]=x;
return j;
}

void QuickSort(int a[],int p,int r)
{
if (p<r)
{
int q=Partition(a,p,r);
QuickSort(a,p,q-1);
QuickSort(a,q+1,r);
}
}


正如其名快速排序,其效率也是比较高的,时间复杂度为O(nlogn)。其算法思想是每次确定一个基准值的位置,也就是函数int Partition(int a[],int p,int r)的作用。然后通过递归不断地确定基准值两边的子数组的基准值的位置,直到数组变得有序。难点还是递归的理解!

插入排序:

//插入排序

//插入排序
//////////////////////////////////////////////////////////////////
void Insert(int *a,int n)
{
int i=n-1;
int key=a
;//需要插入的元素
while ((i>=0)&&(key<a[i]))
{
a[i+1]=a[i];    //比key大的元素往后一个位置,空出插入key的位置
i--;
}
a[i+1]=key;//找到位置插入元素
return;
}

//由于递归的原因数太大了栈可能会溢出
void InsertionSort(int *a,int n)
{
if (n>0)
{
InsertionSort(a,n-1);
Insert(a,n);
}
else return;
}

算法效率和冒泡排序相差无几,时间复杂度为O(n²)。这里要注意的问题是由于不断地递归,栈的不断开辟如果数据太大可能会导致栈溢出而不能得到结果。

堆排序:

//堆排序
////////////////////////////////////////////////////////////////////////////
int Parent(int i)
{
return i/2;
}
int Left(int i)
{
return 2*i;
}
int Right(int i)
{
return 2*i+1;
}

//把以第i个节点给子树的根的子树调整为堆
void MaxHeap(int *a,int i,int length)
{
int L=Left(i);
int R=Right(i);
int temp;
int largest;                  //记录子树最大值的下表,值可能为根节点下标、左子树下表、右子树下标
if (L<=length&&a[L-1]>a[i-1]) //length是递归返回的条件
{
largest=L;
}
else largest=i;
if (R<=length&&a[R-1]>a[largest-1]) //length是递归返回的条件
largest=R;
if (largest!=i)
{
temp=a[i-1];
a[i-1]=a[largest-1];
a[largest-1]=temp;
MaxHeap(a,largest,length);
}
}

void BuildMaxHeap(int *a,int length)
{

for (int i=length/2;i>=1;i--)
MaxHeap(a,i,length);
}

void HeapSort(int *a,int length)
{
BuildMaxHeap(a,length);
for (int i=length;i>0;i--)
{
int temp;
temp=a[i-1];
a[i-1]=a[0];
a[0]=temp;
length-=1;
MaxHeap(a,1,length);
}
}
通过使用大根堆来排序,排序过程中主要的动作就是堆的调整。每次把堆的根节点存入到堆的后面,然后把最后一个节点交换到根节点的位置,然后又调整为新的堆。这样不断重复这个步骤就能把把一个数组排列的有序,时间复杂度为O(nlogn)。  最后一种是比较特别的基数排序(属于分配式排序,前几种属于比较性排序)又称“桶子法”:
  基本思想是通过键值的部分信息分配到某些桶中,藉此达到排序的作用,基数排序属于稳定的排序,其时间复杂度为O(nlog(r)m),r为所采取的的基数,m为堆的个数,在某些情况下基数排序法的效率比其他比较性排序效率要高。
//基数排序
/////////////////////////////////////////////////
int GetMaxTimes(int *a,int n)
{
int max=a[0];
int count=0;
for (int i=1;i<n;i++)
{
if(a[i]>max)
max=a[i];
}
while(max)
{
max=max/10;
count++;
}
return count;
}

void InitialArray(int *a,int n)
{
for (int i=0;i<n;i++)
a[i]=0;
}

// void InitialArray1(int a[][],int m,int n)
// {
//     for (int i=0;i<m;i++)
//         for (int j=0;j<n;j++)
//             a[i][j]=0;
// }

void RadixSort(int *a,int n)
{
int buckets[10][10000]={0};
int times=GetMaxTimes(a,n);
int index,temp;
int record[10]={0};
for (int i=0;i<times;i++)
{
int count=0;
temp=pow(10,i);//index=(a[j]/temp)%10;用来从低位到高位分离
for (int j=0;j<n;j++)
{
index=(a[j]/temp)%10;
buckets[index][record[index]++]=a[j];
}
//把桶中的数据按顺序还原到原数组中
for(int k=0;k<10;k++)
for (int m=0;m<100000;m++)
{
if(buckets[k][m]==0)break;
else
{
a[count++]=buckets[k][m];
//cout<<buckets[k][m]<<" ";
}
}
//重新初始化桶,不然前后两次排序之间会有影响
//buckets[10][10000]={0};
//record[10]={0};
//InitialArray1(buckets,10,10000);
for (k=0;k<10;k++)
for (int m=0;m<100000;m++)
{
if(buckets[k][m]==0)break;
else buckets[k][m]=0;
}
InitialArray(record,10);
}
}

在这里需要注意的是由于局部变量桶过大可能会导致栈溢出而得不带结果,比如桶为int buckets[10][100000]={0};大小=(10*100000*4)/(1024*1024)=3.814M,如果栈的大小只有1M~3M的话就会溢出,就得不到结果,当然可以把这个局部变量改成全局变量。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐