九大排序汇总

最近整理了面试笔试中经常出现的九大排序:冒泡排序(bubble)、选择排序(select)、插入排序(insert)、希尔排序(shell)、堆排序(heap)、快速排序(quick)、合并排序(merge)、基数排序(radix)、桶排序(bucket)。根据是否利用比较的思想进行排序,可将这些排序分为两大类。基于比较的排序:冒泡排序、选择排序、插入排序、希尔排序、堆排序、快速排序、合并排序;不基于比较法排序:基数排序、桶排序。根据是否稳定,可将其分为两大类。稳定排序:冒泡排序、插入排序、合并排序、基数排序、桶排序。不稳定排序:选择排序、希尔排序、堆排序、快速排序。这里的稳定是指:在待排序的文件中,若存在多个关键字相同的记录,经过排序后这些具有相同关键字的记录之间的相对次序保持不变,就称该排序是稳定排序;否则,是不稳定排序。

九大排序时间复杂度和空间复杂度如下表所示:

 

排序类别   时间复杂度     空间复杂度
冒泡排序

最差、平均都是O(n^2),

最好是O(n),

1
插入排序

最差、平均都是O(n^2),

最好是O(n),

1
选择排序最差、平均都是O(n^2),1
希尔排序O(nlogn),1
堆排序O(nlogn),1
快速排序

平均O(nlogn)

最坏(O(n^2))

O(logn)
合并排序O(nlogn),O(n)
基数排序O(dn)(d是数组中最大数的位数)O(n)
桶排序O(n)O(n+m)(m为桶的个数)

九大排序源码如下:

#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;

#define  N 10
struct Bucket
{
 vector<int> data;//桶中数据
};
void Swap(int& a,int &b)//交换函数,排序中经常用到的函数
{
 int tmp=a;
 a=b;
 b=tmp;
}

//*******************************************************(1)快速排序*************************//
int Partion(int* data,int start,int end)
{
 if (data==NULL||start>end||start<0||end<0)
 {
  return -1;
 }
 
 int key=data[start];

  int i=start,j=end;
  while (i<j)
 {
  do i++;while(data[i]<key);
  while(data[j]>key) j--;
  if (i<j) Swap(data[i],data[j]); 
  
 }
  if (start!=j)//这时的j已经发生变化了
  {
   Swap(data[start],data[j]);
  }
 return j;

}
void QuickSort(int *data,int start,int end)
{
 if(start<end)
 {
  int j=Partion(data,start,end);
  QuickSort(data,start,j-1);
  QuickSort(data,j+1,end);
 }
}
void QuickSort(int *data,int len)
{
 if (data==NULL||len<=1)
 {
  return ;
 }
 QuickSort(data,0,len-1);
}
//*******************************************************快速排序*************************//

//***************************************************(2)桶排序**************************//
void Bucket_sort(int *data,int len)
{

 int imax,imin,num,pos;
 int i,j,k;
 imax=imin=data[0];

 for ( i=1;i<len;i++)
 {
  if (data[i]>imax)
  {
   imax=data[i];
  }
  else
   if (data[i]<imin)
   {
    imin=data[i];
   }
 }
 

 num=(imax-imin+1)/N+1;
 vector<Bucket> bk(num);

 for (i=0;i<len;i++)
 {
  k=(data[i]-imin+1)/N;
  bk[k].data.push_back(data[i]);

 }
 pos=0;

 for (i = 0; i < num; i++)
 {  
  int ilen=bk[i].data.size();
  if (ilen>1)
  {
   QuickSort(&bk[i].data[0],ilen);
  }
  
  for (j = 0; j < ilen; j++)
  {  
    data[pos++] = bk[i].data[j];  
   }  
    
 }


}
//***************************************************桶排序**************************//


//**************************************************(3)基数排序*****************************//
//辅助函数:求最大数的位数
int maxbit(int data[],int n)
{
 int d=1;
 int p=10;
 for (int i=0;i<n;i++)
 {
  while(data[i]>=p)
  {
   p*=10;
   ++d;
  }
 }
 return d;
}
//基排序,有点像桶排序
void radixSort(int data[],int n)
{
 int d=maxbit(data,n);//最大数的位数
 int *tmp=new int[n];
 int *count=new int[10];//各个数位上0-9出现的次数
 int i,j,k;

 int radix=1;
 for (i=1;i<=d;i++)
 {
  for (j=0;j<10;j++)
  {
   count[j]=0;
  }
  for (j=0;j<n;j++)//O(n)时间复杂度
  {
   k=(data[j]/radix)%10;//桶的编号,也就是要求的当前位上的数字
   count[k]++;
  }
  for (j=1;j<10;j++)
  {
   count[j]=count[j-1]+count[j];//个数累加
  }
 for (j=n-1;j>=0;j--)//按照选择基数求余的结果进行排序,注意必须是递减次序遍历
  {
   k=(data[j]/radix)%10;
   tmp[count[k]-1]=data[j];//tmp的数据个数跟data是一样的
   count[k]--;
  }
  for (j=0;j<n;j++)
   data[j]=tmp[j];
   
  radix=radix*10;

  for (int i=0;i<10;i++)
  {
   cout<<data[i]<<"\t";
  }
  cout<<endl;
 }
 delete[] tmp;
 delete[] count;
}
//**************************************************基数排序*****************************//


//*******************************(4)堆排序**************************************
void HeapAjust(int array[],int i,int len)
  {
   int nChild;
   int nTemp;
   for (nTemp=array[i];2*i+1<len;i=nChild)
   {
    nChild=2*i+1;
    if (nChild<len-1&&array[nChild+1]>array[nChild])
     ++nChild;
    if (nTemp<array[nChild])
    {
     Swap(array[i],array[nChild]);
    }
    else
       break;   
   }
  }
  void HeapSort(int array[],int len)
  {
   //建立一个最大堆
   for (int i=len/2-1;i>=0;i--)
   {
    HeapAjust(array,i,len);
   }

   //堆调整
   for (int i=len-1;i>0;i--)
   {
    Swap(array[i],array[0]);
    HeapAjust(array,0,i);
   }


  }

//*******************************堆排序**************************************//

//*******************************(5)冒泡排序**************************************
  void Buble_Sort(int data[],int len)
  {
   if (data==NULL||len<=1)
   {
    return;
   }
   for (int i=0;i<len-1;i++)
   {
    for (int j=0;j<len-i-1;j++)
    {
     if (data[j]>data[j+1])
     {
      Swap(data[j],data[j+1]);
     }
    }
   }

  }

 //*******************************冒泡排序**************************************//

//*******************************(6)选择排序**************************************//
  //算法思想:每趟在n-i+1个记录中选择最小的记录作为第i个记录的值
  void Select_Sort(int data[],int len)
  {
   if (data==NULL||len<=1)
   {
    return;
   }

   for (int i=0;i<len-1;i++)
   {
    int key=i;
    for (int j=i+1;j<len;j++)
    {
             if (data[j]<data[key])
             {
     key=j;
             }
    }
    Swap(data[i],data[key]);
   }

  }

//*******************************选择排序**************************************//

//*******************************(7)插入排序**************************************//
  //算法思想:在有序的前i个记录中插入一个值使这i+1个记录仍然有序
void Insert_Sort(int data[],int len)
{
 if (data==NULL||len<=1)
 {
  return;
 }
 for (int i=1;i<len;i++)
 {
  int j=i;
  int key=data[i];
  while(j>=1&&key<data[j-1])
  {
   data[j]=data[j-1];
   j--;
  }
  data[j]=key;
 }

}
//*******************************插入排序**************************************//


//*******************************(8)希尔排序**************************************//
void Shell_Sort(int data[],int len)
{
 if (data==NULL||len<=1)
 {
  return;
 }
 int d;//增量
 
 for (d=len/2;d>=1;d/=2)
 {
  for (int i=d;i<len;i+=d)
  {
           int j=i;
     int key=data[i];
     while(j>=d&&key<data[j-d])
     {
      data[j]=data[j-d];
      j-=d;
     }
     data[j]=key;
  }

 }

}

//*******************************希尔排序**************************************//

//*******************************(9)合并排序**************************************//
void Merge(int data[],int left,int mid,int right)
{
 if (left<0||mid<0||right<0||(!(left<=mid&&mid<=right)))
 {
  return;
 }
 int i,j,k;
 int *tmp=new int[right-left+1];
 i=left;j=mid+1;
  k=0;
 while(i<=mid&&j<=right)
 {
        if (data[i]<data[j])
        {
   tmp[k++]=data[i++];
        }
  else
          tmp[k++]=data[j++];
 }
 while(i<=mid) tmp[k++]=data[i++];
 while(j<=right) tmp[k++]=data[j++];
 for (k=0,i=left;i<=right;i++)
 {
  data[i]=tmp[k++];
 }
 delete[] tmp;
}
void MergeSort(int data[],int left,int right)
{
 if (left<right)
 {
  int mid=left+((right-left)>>1);//注意不要写成:int mid=(left+right)/2;或者int mid=left+(right-left)>>1;
  MergeSort(data,left,mid);
  MergeSort(data,mid+1,right);
  Merge(data,left,mid,right);
 }
}
void Merge_Sort(int data[],int len)
{
 if (data==NULL||len<=1)
 {
  return;
 }
 MergeSort(data,0,len-1);
}

//***********************************合并排序**************************************//


int _tmain(int argc, _TCHAR* argv[])
{
 int data[11]={12,23,9,2,2,7,26,1,1,6,8};
 int len=sizeof(data)/sizeof(int);
 /*Bucket_sort(data,len);
 QuickSort(data,len);
 radixSort(data,len);
 HeapSort(data,len);
 Buble_Sort(data,len);
 Select_Sort(data,len);
 Insert_Sort(data,len);
 Insert_Sort(data,len);*/
 Merge_Sort(data,len);
 for (int i=0;i<len;i++)
 {
  cout<<data[i]<<"\t";
 }
 cout<<endl;
 return 0;
}

排序选择总结:

1.若n较小(如n<=50),可采用插入或选择排序

2.若数据初始状态基本有序,应选用插入、冒泡排序或快速排序;

3若n较大,则选用时间复杂度为线性的排序算法:如快速排序、堆排序、合并排序;其中快速排序是基于比较的内部排序中最好的办法,平均时间最短;堆排序所需辅助空间小于快排;而合并排序则是三者中唯一稳定的排序。

4.基数排序和桶排序往往应用在海量数据的排序上,比如n是几亿甚至几十亿,内存一次储存不了等。

实际应用中,应结合各种排序的优缺点,选择最适合的一个。

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值