一些基本排序算法的實現(轉載)

 

一些基本排序算法的實現

分類: C/C++ 算法設計和優化 117人閱讀 評論(1) 收藏 舉報

花了點時間一次性實現了9個基本排序算法,

其中包括

【冒泡排序】,【直接選擇排序】,【直接插入排序】,

【希爾排序】,【折半插入排序】,【快速排序】,

【堆排序】,【錦標賽排序】,【歸併排序】。


儲存方式是用數組,元素可以是支持重載運算符的自定義類型,

有在數組中直接複製元素的,也有在中間過程中用索引數組記錄

索引序列的,但最終結果都保存在原數組中,

好了,廢話不多說了,直接上源代碼!


//Sort.h

  1. /*------------------------------------ 
  2. 【描述】:一些排序算法(Sort.h) 
  3.  Created by Beyond ray, 2015.1 
  4. -------------------------------------*/  
  5. #ifndef H_SORT  
  6. #define H_SORT  
  7.   
  8. #include <cassert>  
  9. #include <functional>  
  10. #include "WinnerTree.h"  
  11.   
  12. /* 
  13. ================================= 
  14.  以下算法排序皆爲從小到大 
  15. ================================= 
  16. */  
  17.   
  18. //-------------------------------  
  19. // Desc:交換元素  
  20. //-------------------------------  
  21. template<typename T>  
  22. void Swap(T& a, T& b)  
  23. {  
  24.     T temp = a;  
  25.     a = b;  
  26.     b = temp;  
  27. }  
  28.   
  29. //------------------------------  
  30. // Desc:冒泡排序,O(n^2)  
  31. //------------------------------  
  32. template<typename T>  
  33. void BubbleSort(T arr[], int left, int right)  
  34. {  
  35.     assert(left >= 0 && right >= left);  
  36.     bool bChanged = false;  
  37.     for (int i = left; i < right; i++)  
  38.     {  
  39.         bChanged = false;  
  40.         for (int j = right; j >=i+1; j--)  
  41.         {  
  42.             if (arr[j] < arr[j - 1])  
  43.             {  
  44.                 Swap(arr[j], arr[j - 1]);  
  45.                 bChanged = true;  
  46.             }  
  47.         }  
  48.         if (!bChanged)break;  
  49.     }  
  50. }  
  51.   
  52. //-------------------------------  
  53. // Desc:直接選擇排序,O(n^2)  
  54. //-------------------------------  
  55. template<typename T>  
  56. void ChooseSort(T arr[], int left, int right)  
  57. {  
  58.     assert(left >= 0 && right >= left);  
  59.     for (int i = left; i < right; i++)  
  60.     {  
  61.         int minIndex = i;  
  62.         for (int j = i + 1; j <= right; j++)  
  63.         {  
  64.             if (arr[j] < arr[minIndex])  
  65.             {  
  66.                 minIndex = j;  
  67.             }  
  68.         }  
  69.         if (minIndex != i)Swap(arr[minIndex], arr[i]);  
  70.     }  
  71. }  
  72.   
  73. //--------------------------------  
  74. // Desc:直接插入排序,O(n^2)  
  75. //--------------------------------  
  76. template<typename T>  
  77. void InsertSort(T arr[], int left, int right)  
  78. {  
  79.     assert(left >= 0 && right >= left);  
  80.     for (int i = left + 1; i <= right; i++)  
  81.     {  
  82.         for (int j = left; j <= i-1; j++)  
  83.         {  
  84.             if (arr[i] < arr[j])  
  85.             {  
  86.                 auto insertEle = arr[i];  
  87.                 for (int k = i; k >= j + 1; k--)  
  88.                 {  
  89.                     arr[k] = arr[k - 1];  
  90.                 }  
  91.                 arr[j] = insertEle;  
  92.                 break;  
  93.             }  
  94.         }  
  95.     }  
  96. }  
  97.   
  98. //-------------------------------------------  
  99. // Desc:希爾排序,O(nlogn)  
  100. //-------------------------------------------  
  101. template<typename T>  
  102. void ShellSort(T arr[], int left, int right, std::function<int(int)>& gapFunc)  
  103. {  
  104.     assert(left >= 0 && right >= left);  
  105.     int gap = right - left + 1;  
  106.     while (gap != 1)  
  107.     {  
  108.         gap = gapFunc(gap);  
  109.         for (int i = left; i <= right - gap; i++)  
  110.         {  
  111.             int iCompareIdx = i + gap;  
  112.             if (arr[i] > arr[iCompareIdx])  
  113.             {  
  114.                 Swap(arr[i], arr[iCompareIdx]);  
  115.             }  
  116.         }  
  117.     }  
  118. }  
  119. //--------------------------------------------  
  120. // Desc:折半插入排序,O(nlogn)  
  121. //--------------------------------------------  
  122. template<typename T>  
  123. void BinaryInsertSort(T arr[], int left, int right)  
  124. {  
  125.     assert(left >= 0 && right >= left);  
  126.     for (int i = left + 1; i <= right; i++)  
  127.     {  
  128.         int iLeft = left, iRight = i - 1, iCenter;  
  129.         while (iLeft <= iRight)  
  130.         {  
  131.             iCenter = (iLeft + iRight) / 2;  
  132.             if (arr[i] < arr[iCenter])iRight = iCenter - 1;  
  133.             else if (arr[i] > arr[iCenter])iLeft = iCenter + 1;  
  134.             else break;  
  135.         }  
  136.         //iLeft記錄的位置爲插入位置  
  137.         if (iLeft <= iRight)iLeft = iCenter + 1;  
  138.   
  139.         //往後移動數據  
  140.         auto insertEle = arr[i];  
  141.         for (int j = i; j >= iLeft + 1; j--)  
  142.         {  
  143.             arr[j] = arr[j - 1];  
  144.         }  
  145.         arr[iLeft] = insertEle;  
  146.     }  
  147. }  
  148. //------------------------------------------------  
  149. // Desc:left,right,center按Min,Max,Mid排列  
  150. //------------------------------------------------  
  151. template<typename T>  
  152. T& ThreeSort_MinMaxMid(T arr[], int left, int right)  
  153. {  
  154.     assert(left >= 0 && right >= left);  
  155.     int iCenter = (left + right) / 2;  
  156.     int minIdx = left;  
  157.     //記錄最小數索引並交換到最左邊  
  158.     if (arr[iCenter] < arr[left])minIdx = iCenter;  
  159.     if (arr[right] < arr[minIdx])minIdx = right;  
  160.     if (minIdx != left)Swap(arr[left], arr[minIdx]);  
  161.     //將中間值交換到右邊  
  162.     if (iCenter != right && arr[iCenter] < arr[right])  
  163.         Swap(arr[iCenter], arr[right]);  
  164.     return arr[right];  
  165. }  
  166.   
  167. //--------------------------------------------  
  168. // Desc:一次快速排序的分區排序  
  169. //--------------------------------------------  
  170. template<typename T>  
  171. int Partition(T arr[], int left, int right)  
  172. {  
  173.     T&Pivot = ThreeSort_MinMaxMid(arr, left, right);  
  174.     int iLeft = left, iRight= right-1;  
  175.     if (iLeft > iRight)return iLeft;  
  176.     while (1)  
  177.     {  
  178.         while (arr[iLeft] <= Pivot) iLeft++;  
  179.         while (arr[iRight] >= Pivot)iRight--;  
  180.         if (iLeft > iRight)break;  
  181.         Swap(arr[iLeft], arr[iRight]);  
  182.     }  
  183.     //將基準交換到中間  
  184.     Swap(arr[iLeft], Pivot);  
  185.     return iLeft;  
  186. }  
  187. //--------------------------------------------  
  188. // Desc:快速排序,O(nlogn)  
  189. //--------------------------------------------  
  190. template<typename T>  
  191. void QuickSort(T arr[], int left, int right)  
  192. {  
  193.     assert(left >= 0 && right >= left);  
  194.     int ipivot = Partition(arr, left, right);  
  195.     if(ipivot-1 > left)QuickSort(arr, left, ipivot - 1);  
  196.     if(ipivot+1 < right)QuickSort(arr, ipivot + 1, right);  
  197. }  
  198.   
  199. //--------------------------------------------  
  200. // Desc:向下過濾  
  201. //--------------------------------------------  
  202. template<typename T>  
  203. T& SiftDown(T arr[], int minIdx, int maxIdx)  
  204. {  
  205.     int iFather = minIdx;  
  206.     int iLChild = 2 * iFather + 1;  
  207.     int iRChild = 2 * iFather + 2;  
  208.     int imaxEleIdx;  
  209.     while (iLChild <= maxIdx)  
  210.     {  
  211.         //取兩個子元素中小者  
  212.         if (iRChild <= maxIdx && arr[iRChild] > arr[iLChild])  
  213.             imaxEleIdx = iRChild;  
  214.         else  
  215.             imaxEleIdx = iLChild;  
  216.         if (arr[iFather] < arr[imaxEleIdx])  
  217.         {  
  218.             Swap(arr[iFather], arr[imaxEleIdx]);  
  219.             iFather = imaxEleIdx;  
  220.             iLChild = 2 * iFather + 1;  
  221.             iRChild = 2 * iFather + 2;  
  222.         }  
  223.         else break;  
  224.     }  
  225.     return arr[minIdx];  
  226. }  
  227. //--------------------------------------------  
  228. // Desc:堆排序,O(nlogn)  
  229. //--------------------------------------------  
  230. template<typename T>  
  231. void HeapSort(T arr[], int maxIdx)  
  232. {  
  233.     assert(maxIdx >= 0);  
  234.     //建立初始最大堆  
  235.     for (int i = (maxIdx - 1) / 2; i >= 0; i--)  
  236.     {  
  237.         SiftDown(arr, i, maxIdx);  
  238.     }  
  239.     //構造排列序列  
  240.     for (int i = maxIdx; i > 0; i--)  
  241.     {  
  242.         Swap(arr[0], arr[i]);  
  243.         SiftDown(arr, 0, i - 1);  
  244.     }  
  245. }  
  246.   
  247. /* 
  248. ============================================== 
  249.  以下排序算法特別考慮了自定義數據類型的比較, 
  250.  爲縮短平均時間,故用索引方式記錄, 
  251.  最後將最終結果複製回數組。 
  252. ============================================== 
  253. */  
  254.   
  255. //------------------------------------------  
  256. // Desc:以索引排序數組對原排序數組再構造  
  257. //------------------------------------------  
  258. template<typename T>  
  259. void idxSort_Make(T arr[], int sortIdxArr[], int maxIdx)  
  260. {  
  261.     assert(maxIdx >= 0);  
  262.     //【原數組循環賦值構造排序序列】  
  263.     T temp; //複製時只花費了一個T額外空間  
  264.     int i = maxIdx, tempIdx,lastSortIdx;  
  265.     bool bCircle = false;  
  266.     while (i > -1)   
  267.     {  
  268.         if (i != sortIdxArr[i] && sortIdxArr[i]!=-1) //數組中該元素有變化  
  269.         {  
  270.             //第一次到循環點,記錄該位置所在值和索引號  
  271.             if (!bCircle)   
  272.             {  
  273.                 temp = arr[i], tempIdx = i;    
  274.                 bCircle = true//在循環中  
  275.             }  
  276.             //循環未結束  
  277.             if (sortIdxArr[i] != tempIdx)   
  278.             {  
  279.                 arr[i] = arr[sortIdxArr[i]];  
  280.                 lastSortIdx = sortIdxArr[i]; sortIdxArr[i] = -1; i = lastSortIdx;  
  281.             }  
  282.             else //循環結束交界  
  283.             {  
  284.                 arr[i] = temp;  
  285.                 bCircle = false;  
  286.                 sortIdxArr[i] = -1;  
  287.                 i = tempIdx;  
  288.                 while (i > 0 && sortIdxArr[--i] == -1);  
  289.             }             
  290.         }  
  291.         else //該位置元素與排序後不變  
  292.         {  
  293.             sortIdxArr[i--] = -1;  
  294.         }  
  295.     }  
  296. }  
  297.   
  298. //------------------------------------------  
  299. // Desc:錦標賽排序,O(nlogn)  
  300. //------------------------------------------  
  301. template<typename T>  
  302. void TournamentSort(T arr[], int maxIdx)  
  303. {  
  304.     assert(maxIdx >= 0);  
  305.     int* sortIdxArr = new int[maxIdx + 1];  
  306.     if (sortIdxArr == nullptr)  
  307.     {   
  308.         cerr << "TournamentSort:索引數組內存分配失敗!"; exit(1);  
  309.     }  
  310.     WinnerTree<T> wTree(maxIdx + 1);  
  311.     sortIdxArr[0] = wTree.init(arr);  
  312.     for (int i = 1; i <= maxIdx; i++)  
  313.     {  
  314.         sortIdxArr[i] = wTree.getNewWinner();  
  315.     }  
  316.     //數組重構及清理  
  317.     idxSort_Make(arr, sortIdxArr, maxIdx);  
  318.     delete []sortIdxArr;   
  319. }  
  320.   
  321. //------------------------------------------  
  322. // Desc:合併兩個子序列  
  323. //------------------------------------------  
  324. template<typename T>  
  325. void TwoMerge(T arr[], int srcIdx[], int destIdx[], int left, int center, int right)  
  326. {  
  327.     int iSrc1Left = left, iSrc2Left = center + 1,iPos = left;  
  328.     //比較並複製小者的索引號到索引數組對應位置  
  329.     while (iSrc1Left <= center && iSrc2Left <= right)  
  330.         destIdx[iPos++] = arr[srcIdx[iSrc1Left]] <= arr[srcIdx[iSrc2Left]]?srcIdx[iSrc1Left++]:srcIdx[iSrc2Left++];  
  331.     //複製剩餘索引號  
  332.     while (iSrc1Left <= center)destIdx[iPos++] = srcIdx[iSrc1Left++];  
  333.     while (iSrc2Left <= right)destIdx[iPos++] = srcIdx[iSrc2Left++];  
  334. }  
  335.   
  336. //------------------------------------------  
  337. // Desc:二路歸併排序,O(nlogn)  
  338. //------------------------------------------  
  339. template<typename T>  
  340. void TwoMerge_Sort(T arr[], int left, int right)  
  341. {  
  342.     assert(left >= 0 && right >= left);  
  343.     //--------------------------  
  344.     // 【索引數組分配及初始化】  
  345.     //--------------------------  
  346.     //分配兩個索引數組  
  347.     int ilen = right - left + 1;  
  348.     int* sortIdx1 = new int[ilen];  
  349.     if (sortIdx1 == nullptr){ cerr << "Merget_Sort:索引數組1內存分配失敗"; exit(1); }  
  350.     int* sortIdx2 = new int[ilen];  
  351.     if (sortIdx2 == nullptr){ cerr << "Merget_Sort:索引數組2內存分配失敗"; exit(1); }  
  352.     //對索引數組初始化  
  353.     for (int i = 0, j = left; i < ilen; i++, j++)  
  354.     {  
  355.         sortIdx1[i] = j;  
  356.         sortIdx2[i] = j;  
  357.     }  
  358.     //--------------------------  
  359.     // 【索引交替歸併記錄】  
  360.     //--------------------------  
  361.     int k = 1, mid, end; //步長k:1,2,4,8,....   
  362.     bool bIdx1To2 = true;   
  363.     int iLOffset = 0, iROffset = right - left;  
  364.     while (k < ilen)  
  365.     {  
  366.         for (int beg = iLOffset; beg < iROffset; beg = end + 1)  
  367.         {  
  368.             mid = beg + k - 1;  
  369.             end = mid + k;  
  370.             if (mid <iROffset && end > iROffset)end = iROffset;  
  371.             if (mid < iROffset)  
  372.             {  
  373.                 if (bIdx1To2)  
  374.                     TwoMerge(arr, sortIdx1, sortIdx2, beg, mid, end);  
  375.                 else  
  376.                     TwoMerge(arr, sortIdx2, sortIdx1, beg, mid, end);  
  377.             }  
  378.         }  
  379.         //數組索引複製反轉  
  380.         bIdx1To2 = !bIdx1To2;  
  381.         k = 2 * k;  
  382.     }  
  383.     //-----------------------------  
  384.     // 【數組重構及索引數組清理】  
  385.     //-----------------------------  
  386.     bIdx1To2 ? idxSort_Make(arr, sortIdx1, iROffset) : idxSort_Make(arr, sortIdx2, iROffset);  
  387.     delete []sortIdx1;  
  388.     delete []sortIdx2;  
  389. }  
  390.   
  391. #endif  

//WinnerTree.h

  1. /*--------------------------------------- 
  2. 【描述】:排序使用的勝者樹(WinnerTree.h) 
  3.  Created by Beyond ray, 2015.1 
  4.  ----------------------------------------*/  
  5.   
  6. #ifndef H_WINNER_TREE  
  7. #define H_WINNER_TREE  
  8.   
  9. template<typename T>  
  10. class WinnerTree  
  11. {  
  12. public:  
  13.     WinnerTree(int sortNums);  
  14.     ~WinnerTree();  
  15.     int init(T arr[]);          //初始化勝者樹(產生第一個冠軍)  
  16.     int getNewWinner();         //得到新勝者(剔除舊勝者)  
  17.     void coutWinnerTree();      //輸出勝者樹(調試用)  
  18. private:  
  19.     T* m_Arr;                   //指向欲排序數組   
  20.     int* m_Winner;              //勝者樹索引數組(索引-1爲剔除)  
  21.     int m_SortNums;             //排序個數(比賽個數)  
  22. };  
  23.   
  24.   
  25. //構造函數  
  26. template<typename T>  
  27. WinnerTree<T>::WinnerTree(int sortNums) :  
  28. m_SortNums(sortNums)  
  29. {  
  30.     assert(m_SortNums > 0);  
  31.     m_Winner = new int[2*m_SortNums - 1];  
  32.     if (!m_Winner){ cerr << "勝者樹索引數組內存分配失敗"; exit(1); }  
  33. }  
  34.   
  35. //析構函數  
  36. template<typename T>  
  37. WinnerTree<T>::~WinnerTree()  
  38. {  
  39.     if (m_Winner)  
  40.     {  
  41.         delete[]m_Winner;  
  42.         m_Winner = NULL;  
  43.     }  
  44. }  
  45.   
  46.   
  47. //-------------------------  
  48. // Desc:初始化勝者樹  
  49. //-------------------------  
  50. template<typename T>  
  51. int WinnerTree<T>::init(T arr[])  
  52. {  
  53.     m_Arr = arr;  
  54.     //初始化參賽者(排序碼)索引序列  
  55.     for (int i = m_SortNums - 1, j = 0; i <= 2 * m_SortNums - 2; i++, j++)  
  56.         m_Winner[i] = j;  
  57.   
  58.     //構造初始化勝者樹  
  59.     int iLChild = 2 * m_SortNums - 3;  
  60.     int iRChild = 2 * m_SortNums - 2;  
  61.     for (int j = m_SortNums - 2; j >= 0; j--)  
  62.     {  
  63.         if (arr[m_Winner[iLChild]] <= arr[m_Winner[iRChild]])  
  64.             m_Winner[j] = m_Winner[iLChild];  
  65.         else  
  66.             m_Winner[j] = m_Winner[iRChild];  
  67.   
  68.         //移動比較索引位  
  69.         iLChild -= 2;  
  70.         iRChild -= 2;  
  71.     }  
  72.     return m_Winner[0];  
  73. }  
  74.   
  75. //--------------------------------------  
  76. // Desc:輸出勝者樹  
  77. //--------------------------------------  
  78. template<typename T>  
  79. void WinnerTree<T>::coutWinnerTree()  
  80. {  
  81.     for (int i = 0; i < m_SortNums-1; i++)  
  82.     {  
  83.         cout << m_Arr[m_Winner[i]] << " ";  
  84.     }  
  85.     cout << endl;  
  86. }  
  87. //--------------------------------------  
  88. // Desc:選取冠軍後,選取新冠軍  
  89. //--------------------------------------  
  90. template<typename T>  
  91. int WinnerTree<T>::getNewWinner()  
  92. {  
  93.     //第一次重寫父節點值  
  94.     int offset = m_SortNums - 1;  
  95.     int lastWinnerIdx = m_Winner[0] + offset;  
  96.     m_Winner[lastWinnerIdx] = -1;     
  97.     int nearIdx = lastWinnerIdx % 2 == 0 ? (lastWinnerIdx - 1) : (lastWinnerIdx + 1);  
  98.     int fatherIdx = (nearIdx - 1) / 2;  
  99.     m_Winner[fatherIdx] = m_Winner[nearIdx];  
  100.   
  101.     //一直遍歷到根節點更新最小勝者  
  102.     while (fatherIdx != 0)  
  103.     {  
  104.         fatherIdx = (fatherIdx - 1) / 2;  
  105.         int iLChild = 2 * fatherIdx + 1;  
  106.         int iRChild = 2 * fatherIdx + 2;  
  107.         if (m_Winner[iLChild] == -1)m_Winner[fatherIdx] = m_Winner[iRChild];  
  108.         else if (m_Winner[iRChild] == -1) m_Winner[fatherIdx] = m_Winner[iLChild];  
  109.         else  
  110.         {  
  111.             if (m_Arr[m_Winner[iLChild]] <= m_Arr[m_Winner[iRChild]])  
  112.                 m_Winner[fatherIdx] = m_Winner[iLChild];  
  113.             else  
  114.                 m_Winner[fatherIdx] = m_Winner[iRChild];  
  115.         }  
  116.     }  
  117.     return m_Winner[0];  
  118. }  
  119. #endif  

//main.cpp

  1. /*----------------------------------- 
  2.  【Cpp文件】:main.cpp 
  3.   Created by Beyond ray,2015.1 
  4.  ----------------------------------*/  
  5. #include "Sort.h"  
  6. #include<iostream>  
  7. using namespace std;  
  8.   
  9. #include<time.h>  
  10.   
  11. const int ARR_NUMS = 15;  
  12. int main(int argc, char* argv[])  
  13. {  
  14.     srand((unsigned int)time(NULL));  
  15.     int a[ARR_NUMS];  
  16.     std::function<int(int)> gapFunc = [](int gap){return (gap / 3 + 1); };  
  17.     for (int count = 0; count < 9; count++)  
  18.     {  
  19.         for (int i = 0; i < ARR_NUMS; i++)  
  20.         {  
  21.             a[i] = rand() % 1000;  
  22.         }  
  23.         switch (count)  
  24.         {  
  25.         case 0: BubbleSort(a, 0, ARR_NUMS - 1); cout << "BubbleSort:"break;  
  26.         case 1: ChooseSort(a, 0, ARR_NUMS - 1); cout << "ChooseSort:"break;  
  27.         case 2: InsertSort(a, 0, ARR_NUMS - 1); cout << "InsertSort:"break;  
  28.         case 3: ShellSort(a, 0, ARR_NUMS - 1, gapFunc); cout << "ShellSort:"break;  
  29.         case 4: BinaryInsertSort(a, 0, ARR_NUMS - 1); cout << "BinaryInsertSort:"break;  
  30.         case 5: QuickSort(a, 0, ARR_NUMS - 1); cout << "QuickSort:"break;  
  31.         case 6: HeapSort(a, ARR_NUMS - 1); cout << "HeapSort:"break;  
  32.         case 7: TournamentSort(a, ARR_NUMS - 1); cout << "TournamentSort:"break;  
  33.         case 8: TwoMerge_Sort(a, 0, ARR_NUMS - 1); cout << "TwoMerge_Sort:"break;  
  34.         }  
  35.         for (int i = 0; i < ARR_NUMS; i++)  
  36.         {  
  37.             cout << a[i] <<" ";  
  38.         }  
  39.         cout << endl;  
  40.     }  
  41.     return 0;  
  42. }  

一次取隨機數的運行結果

發佈了53 篇原創文章 · 獲贊 8 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章