淺談C++之冒泡排序、希爾排序、快速排序、插入排序、堆排序、基數排序性能對比分析(好戲在後面,有圖有真相)

 

  因爲沒考慮到一些狀況,對以上一些算法作了改進和對比!以及昨晚把希爾排序寫錯而誤覺得其效率高過快速排序的糗事,今天一一作了更正和說明,若是你絕得本隨筆不是很妥能夠嘗試看看這http://www.cnblogs.com/maxiaofang/p/3382927.html,有錯誤或不妥歡迎指正!!共同窗習,共同進步!O(∩_∩)O哈哈~html

   推薦一段博友分享的排序視頻很藝術、很形象、很生動哦(http://www.oschina.net/question/561584_65522算法

  最近一段時間去武漢參加了N多筆試,在幾回試題中都出現了排序。恰恰出現了我沒怎麼看的插入排序,弄得我好是糾結。趁回學校的機會把這幾個不是很複雜的排序從新複習了一下,藉此比較了一下他們的效率。讓我有點之外的是在數據量達到1W~10W之間,希爾排序居然比快速排序效率還要高。貼上完整代碼!數組

冒泡排序函數

 1 //冒泡排序
 2 //////////////////////////////////////////////////////////////////////////
 3 void BubleSort(int a[],int n)  4 {  5     int temp;  6     bool flag=false;  7     for (int i=0;i<n;i++)  8  {  9         flag=true; 10         for (int j=0;j<n-i-1;j++) 11  { 12             if(a[j]>a[j+1]) 13  { 14                 temp=a[j]; 15                 a[j]=a[j+1]; 16                 a[j+1]=temp; 17                 flag=false; 18  } 19  } 20         if(flag) break; 21  } 22 }

冒泡排序的時間複雜度爲O(n²),在數據比較小的狀況下各個算法效率差很少。學習

希爾排序:ui

  之前居然沒有發現,希爾排序如此短小精悍的代碼。其效率不少時候並不輸給快速排序其時間複雜度爲O(nlogn)。spa

 

 1 void ShellSort(int array[],int length)
 2 
 3 {
 4     
 5     int d = length/2;   //設置希爾排序的增量
 6     int i ;
 7     int j;
 8     int temp;
 9     while(d>=1)    
10     {
11         for(i=d;i<length;i++)    
12         {    
13             temp=array[i];
14             j=i-d;
15             while(j>=0 && array[j]>temp)    
16             {    
17                 array[j+d]=array[j];    
18                 j=j-d;    
19             }    
20             array[j+d] = temp;    
21         }
22         //Display(array,10);    
23      d= d/2;    //縮小增量    
24     }    
25 }

 

 

 

 

快速排序:操作系統

 1 //快速排序
 2 ///////////////////////////////////////  3 void Swap(int &a,int &b)  4 {  5     int temp;  6     temp=a;  7     a=b;  8     b=temp;  9 } 10 
11 int Partition(int a[],int p,int r) 12 { 13     int i=p; 14     int j=r+1; 15     int x=a[p]; 16     while (true) 17  { 18         while(a[++i]<x&&i<r); 19         while(a[--j]>x); 20         if (i>=j)break; 21  Swap(a[j],a[i]); 22 
23  } 24     a[p]=a[j]; 25     a[j]=x; 26     return j; 27 } 28 
29 void QuickSort(int a[],int p,int r) 30 { 31     if (p<r) 32  { 33         int q=Partition(a,p,r); 34         QuickSort(a,p,q-1); 35         QuickSort(a,q+1,r); 36  } 37 }

  正如其名快速排序,其效率也是比較高的,時間複雜度爲O(nlogn)。其算法思想是每次肯定一個基準值的位置,也就是函數int Partition(int a[],int p,int r)的做用。而後經過遞歸不斷地肯定基準值兩邊的子數組的基準值的位置,直到數組變得有序。難點仍是遞歸的理解!.net

 

  插入排序:3d

  

 1 //插入排序
 2 //////////////////////////////////////////////////////////////////  3 void Insert(int *a,int n)  4 {  5     int i=n-1;  6     int key=a[n];//須要插入的元素
 7     while ((i>=0)&&(key<a[i]))  8  {  9         a[i+1]=a[i];    //比key大的元素日後一個位置,空出插入key的位置
10         i--; 11  } 12     a[i+1]=key;//找到位置插入元素
13     return; 14 } 15 
16 //因爲遞歸的緣由數太大了棧可能會溢出
17 void InsertionSort(int *a,int n) 18 { 19     if (n>0) 20  { 21         InsertionSort(a,n-1); 22  Insert(a,n); 23  } 24     else return; 25 }

  算法效率和冒泡排序相差無幾,時間複雜度爲O(n²)。這裏要注意的問題是因爲不斷地遞歸,棧的不斷開闢若是數據太大可能會致使棧溢出而不能獲得結果。

 

  堆排序:

 1 //堆排序
 2 ////////////////////////////////////////////////////////////////////////////
 3 int Parent(int i)  4 {  5     return i/2;  6 }  7 int Left(int i)  8 {  9     return 2*i; 10 } 11 int Right(int i) 12 { 13     return 2*i+1; 14 } 15 
16 //把以第i個節點給子樹的根的子樹調整爲堆
17 void MaxHeap(int *a,int i,int length) 18 { 19     int L=Left(i); 20     int R=Right(i); 21     int temp; 22     int largest;                  //記錄子樹最大值的下表,值可能爲根節點下標、左子樹下表、右子樹下標
23     if (L<=length&&a[L-1]>a[i-1]) //length是遞歸返回的條件
24  { 25         largest=L; 26  } 27     else largest=i; 28     if (R<=length&&a[R-1]>a[largest-1]) //length是遞歸返回的條件
29         largest=R; 30     if (largest!=i) 31  { 32         temp=a[i-1]; 33         a[i-1]=a[largest-1]; 34         a[largest-1]=temp; 35  MaxHeap(a,largest,length); 36  } 37 } 38 
39 void BuildMaxHeap(int *a,int length) 40 { 41 
42     for (int i=length/2;i>=1;i--) 43  MaxHeap(a,i,length); 44 } 45 
46 void HeapSort(int *a,int length) 47 { 48  BuildMaxHeap(a,length); 49     for (int i=length;i>0;i--) 50  { 51         int temp; 52         temp=a[i-1]; 53         a[i-1]=a[0]; 54         a[0]=temp; 55         length-=1; 56         MaxHeap(a,1,length); 57  } 58 }

  經過使用大根堆來排序,排序過程當中主要的動做就是堆的調整。每次把堆的根節點存入到堆的後面,而後把最後一個節點交換到根節點的位置,而後又調整爲新的堆。這樣不斷重複這個步驟就能把把一個數組排列的有序,時間複雜度爲O(nlogn)。

  最後一種是比較特別的基數排序(屬於分配式排序,前幾種屬於比較性排序)又稱「桶子法」:

  基本思想是經過鍵值的部分信息分配到某些桶中,藉此達到排序的做用,基數排序屬於穩定的排序,其時間複雜度爲O(nlog(r)m),r爲所採起的的基數,m爲堆的個數,在某些狀況下基數排序法的效率比其餘比較性排序效率要高。

  

 1 //基數排序
 2 /////////////////////////////////////////////////
 3 int GetMaxTimes(int *a,int n)  4 {  5     int max=a[0];  6     int count=0;  7     for (int i=1;i<n;i++)  8  {  9         if(a[i]>max) 10             max=a[i]; 11  } 12     while(max) 13  { 14         max=max/10; 15         count++; 16  } 17     return count; 18 } 19 
20 void InitialArray(int *a,int n) 21 { 22     for (int i=0;i<n;i++) 23         a[i]=0; 24 } 25 
26 // void InitialArray1(int a[][],int m,int n) 27 // { 28 // for (int i=0;i<m;i++) 29 // for (int j=0;j<n;j++) 30 // a[i][j]=0; 31 // }
32 
33 void RadixSort(int *a,int n) 34 { 35     int buckets[10][10000]={0}; 36     int times=GetMaxTimes(a,n); 37     int index,temp; 38     int record[10]={0}; 39     for (int i=0;i<times;i++) 40  { 41         int count=0; 42         temp=pow(10,i);//index=(a[j]/temp)%10;用來從低位到高位分離
43         for (int j=0;j<n;j++) 44  { 45             index=(a[j]/temp)%10; 46             buckets[index][record[index]++]=a[j]; 47  } 48         //把桶中的數據按順序還原到原數組中
49         for(int k=0;k<10;k++) 50             for (int m=0;m<100000;m++) 51  { 52                 if(buckets[k][m]==0)break; 53                 else
54  { 55                     a[count++]=buckets[k][m]; 56                     //cout<<buckets[k][m]<<" ";
57  } 58  } 59             //從新初始化桶,否則先後兩次排序之間會有影響 60             //buckets[10][10000]={0}; 61             //record[10]={0}; 62             //InitialArray1(buckets,10,10000);
63             for (k=0;k<10;k++) 64                 for (int m=0;m<100000;m++) 65  { 66                     if(buckets[k][m]==0)break; 67                     else buckets[k][m]=0; 68  } 69             InitialArray(record,10); 70  } 71 }

  在這裏須要注意的是因爲局部變量桶過大可能會致使棧溢出而得不帶結果,好比桶爲int buckets[10][100000]={0};大小=(10*100000*4)/(1024*1024)=3.814M,若是棧的大小隻有1M~3M的話就會溢出,就得不到結果,固然能夠把這個局部變量改爲全局變量。

  下面是從數據量10~80000排序的實驗結果,首先聲明一點。每一個排序算法的數據量是相同的而具體數據都是隨機產生的,也就是每一個排序一組不一樣的隨機數據。這可能對實驗結果有所影響。固然我這只是沒事好奇搞着玩玩,結果僅供參考。你們有興趣的能夠本身試試!

數據量爲10:

數據量爲100:

數據量爲1000:

數據量爲10000:

數據量爲15000:

數據量爲20000:

數據量爲50000:

數據量爲90000:

數據量爲80000:

 

  愈來愈興奮了:

接下來想測一測10億是神馬狀況程序直接掛了,而後測一測5億而後就死機了,而後就木有而後了,我寫了一半的博客!!!!!~~o(>_<)o ~~!!!!!~~o(>_<)o ~~!!!!!~~o(>_<)o ~~

後面測了一下5億!原本錄了一段小視頻的,可是上傳不了。這裏就說出答案吧:5億數據時,快速排序也掛了,只有希爾排序一直在健壯的運行,運行時間大概爲120s左右。

大概分析了一下數據所佔的內存:

首先5億個數據佔多少內存?

(50000000*4)/(pow(1024,3))=1.86G

個人電腦內存爲3G左右,除去操做系統和軟件大約佔了20%3G=0.6G。

3-0.6-1.86=0.54G剩餘

0.54*pow(1024,3)/4=144955146剩餘內存還能夠計算1億多個數據,

因此個人電腦一共能同時排序644955146個數據。這就是爲何排序10億數據時程序崩潰的緣由,由於沒有這麼多內存分配給程序使用。

然而我實際測了一下實際上達不到6億,5.5億就崩潰了,緣由有待後續考察!

 

因爲沒考慮到一些狀況,對以上一些算法作了改進和對比!以及昨晚把希爾排序寫錯而誤覺得其效率高過快速排序的糗事,今天一一作了更正和說明,若是你絕得本隨筆不是很妥能夠嘗試看看這篇http://www.cnblogs.com/maxiaofang/p/3382927.html,有錯誤或不妥歡迎指正!!共同窗習,共同進步!O(∩_∩)O哈哈~

相關文章
相關標籤/搜索