花了點時間一次性實現了9個基本排序算法,
其中包括:
【冒泡排序】,【直接選擇排序】,【直接插入排序】,
【希爾排序】,【折半插入排序】,【快速排序】,
【堆排序】,【錦標賽排序】,【歸併排序】。
儲存方式是用數組,元素可以是支持重載運算符的自定義類型,
有在數組中直接複製元素的,也有在中間過程中用索引數組記錄
索引序列的,但最終結果都保存在原數組中,
好了,廢話不多說了,直接上源代碼!
//Sort.h
- /*------------------------------------
- 【描述】:一些排序算法(Sort.h)
- Created by Beyond ray, 2015.1
- -------------------------------------*/
- #ifndef H_SORT
- #define H_SORT
- #include <cassert>
- #include <functional>
- #include "WinnerTree.h"
- /*
- =================================
- 以下算法排序皆爲從小到大
- =================================
- */
- //-------------------------------
- // Desc:交換元素
- //-------------------------------
- template<typename T>
- void Swap(T& a, T& b)
- {
- T temp = a;
- a = b;
- b = temp;
- }
- //------------------------------
- // Desc:冒泡排序,O(n^2)
- //------------------------------
- template<typename T>
- void BubbleSort(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- bool bChanged = false;
- for (int i = left; i < right; i++)
- {
- bChanged = false;
- for (int j = right; j >=i+1; j--)
- {
- if (arr[j] < arr[j - 1])
- {
- Swap(arr[j], arr[j - 1]);
- bChanged = true;
- }
- }
- if (!bChanged)break;
- }
- }
- //-------------------------------
- // Desc:直接選擇排序,O(n^2)
- //-------------------------------
- template<typename T>
- void ChooseSort(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- for (int i = left; i < right; i++)
- {
- int minIndex = i;
- for (int j = i + 1; j <= right; j++)
- {
- if (arr[j] < arr[minIndex])
- {
- minIndex = j;
- }
- }
- if (minIndex != i)Swap(arr[minIndex], arr[i]);
- }
- }
- //--------------------------------
- // Desc:直接插入排序,O(n^2)
- //--------------------------------
- template<typename T>
- void InsertSort(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- for (int i = left + 1; i <= right; i++)
- {
- for (int j = left; j <= i-1; j++)
- {
- if (arr[i] < arr[j])
- {
- auto insertEle = arr[i];
- for (int k = i; k >= j + 1; k--)
- {
- arr[k] = arr[k - 1];
- }
- arr[j] = insertEle;
- break;
- }
- }
- }
- }
- //-------------------------------------------
- // Desc:希爾排序,O(nlogn)
- //-------------------------------------------
- template<typename T>
- void ShellSort(T arr[], int left, int right, std::function<int(int)>& gapFunc)
- {
- assert(left >= 0 && right >= left);
- int gap = right - left + 1;
- while (gap != 1)
- {
- gap = gapFunc(gap);
- for (int i = left; i <= right - gap; i++)
- {
- int iCompareIdx = i + gap;
- if (arr[i] > arr[iCompareIdx])
- {
- Swap(arr[i], arr[iCompareIdx]);
- }
- }
- }
- }
- //--------------------------------------------
- // Desc:折半插入排序,O(nlogn)
- //--------------------------------------------
- template<typename T>
- void BinaryInsertSort(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- for (int i = left + 1; i <= right; i++)
- {
- int iLeft = left, iRight = i - 1, iCenter;
- while (iLeft <= iRight)
- {
- iCenter = (iLeft + iRight) / 2;
- if (arr[i] < arr[iCenter])iRight = iCenter - 1;
- else if (arr[i] > arr[iCenter])iLeft = iCenter + 1;
- else break;
- }
- //iLeft記錄的位置爲插入位置
- if (iLeft <= iRight)iLeft = iCenter + 1;
- //往後移動數據
- auto insertEle = arr[i];
- for (int j = i; j >= iLeft + 1; j--)
- {
- arr[j] = arr[j - 1];
- }
- arr[iLeft] = insertEle;
- }
- }
- //------------------------------------------------
- // Desc:left,right,center按Min,Max,Mid排列
- //------------------------------------------------
- template<typename T>
- T& ThreeSort_MinMaxMid(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- int iCenter = (left + right) / 2;
- int minIdx = left;
- //記錄最小數索引並交換到最左邊
- if (arr[iCenter] < arr[left])minIdx = iCenter;
- if (arr[right] < arr[minIdx])minIdx = right;
- if (minIdx != left)Swap(arr[left], arr[minIdx]);
- //將中間值交換到右邊
- if (iCenter != right && arr[iCenter] < arr[right])
- Swap(arr[iCenter], arr[right]);
- return arr[right];
- }
- //--------------------------------------------
- // Desc:一次快速排序的分區排序
- //--------------------------------------------
- template<typename T>
- int Partition(T arr[], int left, int right)
- {
- T&Pivot = ThreeSort_MinMaxMid(arr, left, right);
- int iLeft = left, iRight= right-1;
- if (iLeft > iRight)return iLeft;
- while (1)
- {
- while (arr[iLeft] <= Pivot) iLeft++;
- while (arr[iRight] >= Pivot)iRight--;
- if (iLeft > iRight)break;
- Swap(arr[iLeft], arr[iRight]);
- }
- //將基準交換到中間
- Swap(arr[iLeft], Pivot);
- return iLeft;
- }
- //--------------------------------------------
- // Desc:快速排序,O(nlogn)
- //--------------------------------------------
- template<typename T>
- void QuickSort(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- int ipivot = Partition(arr, left, right);
- if(ipivot-1 > left)QuickSort(arr, left, ipivot - 1);
- if(ipivot+1 < right)QuickSort(arr, ipivot + 1, right);
- }
- //--------------------------------------------
- // Desc:向下過濾
- //--------------------------------------------
- template<typename T>
- T& SiftDown(T arr[], int minIdx, int maxIdx)
- {
- int iFather = minIdx;
- int iLChild = 2 * iFather + 1;
- int iRChild = 2 * iFather + 2;
- int imaxEleIdx;
- while (iLChild <= maxIdx)
- {
- //取兩個子元素中小者
- if (iRChild <= maxIdx && arr[iRChild] > arr[iLChild])
- imaxEleIdx = iRChild;
- else
- imaxEleIdx = iLChild;
- if (arr[iFather] < arr[imaxEleIdx])
- {
- Swap(arr[iFather], arr[imaxEleIdx]);
- iFather = imaxEleIdx;
- iLChild = 2 * iFather + 1;
- iRChild = 2 * iFather + 2;
- }
- else break;
- }
- return arr[minIdx];
- }
- //--------------------------------------------
- // Desc:堆排序,O(nlogn)
- //--------------------------------------------
- template<typename T>
- void HeapSort(T arr[], int maxIdx)
- {
- assert(maxIdx >= 0);
- //建立初始最大堆
- for (int i = (maxIdx - 1) / 2; i >= 0; i--)
- {
- SiftDown(arr, i, maxIdx);
- }
- //構造排列序列
- for (int i = maxIdx; i > 0; i--)
- {
- Swap(arr[0], arr[i]);
- SiftDown(arr, 0, i - 1);
- }
- }
- /*
- ==============================================
- 以下排序算法特別考慮了自定義數據類型的比較,
- 爲縮短平均時間,故用索引方式記錄,
- 最後將最終結果複製回數組。
- ==============================================
- */
- //------------------------------------------
- // Desc:以索引排序數組對原排序數組再構造
- //------------------------------------------
- template<typename T>
- void idxSort_Make(T arr[], int sortIdxArr[], int maxIdx)
- {
- assert(maxIdx >= 0);
- //【原數組循環賦值構造排序序列】
- T temp; //複製時只花費了一個T額外空間
- int i = maxIdx, tempIdx,lastSortIdx;
- bool bCircle = false;
- while (i > -1)
- {
- if (i != sortIdxArr[i] && sortIdxArr[i]!=-1) //數組中該元素有變化
- {
- //第一次到循環點,記錄該位置所在值和索引號
- if (!bCircle)
- {
- temp = arr[i], tempIdx = i;
- bCircle = true; //在循環中
- }
- //循環未結束
- if (sortIdxArr[i] != tempIdx)
- {
- arr[i] = arr[sortIdxArr[i]];
- lastSortIdx = sortIdxArr[i]; sortIdxArr[i] = -1; i = lastSortIdx;
- }
- else //循環結束交界
- {
- arr[i] = temp;
- bCircle = false;
- sortIdxArr[i] = -1;
- i = tempIdx;
- while (i > 0 && sortIdxArr[--i] == -1);
- }
- }
- else //該位置元素與排序後不變
- {
- sortIdxArr[i--] = -1;
- }
- }
- }
- //------------------------------------------
- // Desc:錦標賽排序,O(nlogn)
- //------------------------------------------
- template<typename T>
- void TournamentSort(T arr[], int maxIdx)
- {
- assert(maxIdx >= 0);
- int* sortIdxArr = new int[maxIdx + 1];
- if (sortIdxArr == nullptr)
- {
- cerr << "TournamentSort:索引數組內存分配失敗!"; exit(1);
- }
- WinnerTree<T> wTree(maxIdx + 1);
- sortIdxArr[0] = wTree.init(arr);
- for (int i = 1; i <= maxIdx; i++)
- {
- sortIdxArr[i] = wTree.getNewWinner();
- }
- //數組重構及清理
- idxSort_Make(arr, sortIdxArr, maxIdx);
- delete []sortIdxArr;
- }
- //------------------------------------------
- // Desc:合併兩個子序列
- //------------------------------------------
- template<typename T>
- void TwoMerge(T arr[], int srcIdx[], int destIdx[], int left, int center, int right)
- {
- int iSrc1Left = left, iSrc2Left = center + 1,iPos = left;
- //比較並複製小者的索引號到索引數組對應位置
- while (iSrc1Left <= center && iSrc2Left <= right)
- destIdx[iPos++] = arr[srcIdx[iSrc1Left]] <= arr[srcIdx[iSrc2Left]]?srcIdx[iSrc1Left++]:srcIdx[iSrc2Left++];
- //複製剩餘索引號
- while (iSrc1Left <= center)destIdx[iPos++] = srcIdx[iSrc1Left++];
- while (iSrc2Left <= right)destIdx[iPos++] = srcIdx[iSrc2Left++];
- }
- //------------------------------------------
- // Desc:二路歸併排序,O(nlogn)
- //------------------------------------------
- template<typename T>
- void TwoMerge_Sort(T arr[], int left, int right)
- {
- assert(left >= 0 && right >= left);
- //--------------------------
- // 【索引數組分配及初始化】
- //--------------------------
- //分配兩個索引數組
- int ilen = right - left + 1;
- int* sortIdx1 = new int[ilen];
- if (sortIdx1 == nullptr){ cerr << "Merget_Sort:索引數組1內存分配失敗"; exit(1); }
- int* sortIdx2 = new int[ilen];
- if (sortIdx2 == nullptr){ cerr << "Merget_Sort:索引數組2內存分配失敗"; exit(1); }
- //對索引數組初始化
- for (int i = 0, j = left; i < ilen; i++, j++)
- {
- sortIdx1[i] = j;
- sortIdx2[i] = j;
- }
- //--------------------------
- // 【索引交替歸併記錄】
- //--------------------------
- int k = 1, mid, end; //步長k:1,2,4,8,....
- bool bIdx1To2 = true;
- int iLOffset = 0, iROffset = right - left;
- while (k < ilen)
- {
- for (int beg = iLOffset; beg < iROffset; beg = end + 1)
- {
- mid = beg + k - 1;
- end = mid + k;
- if (mid <iROffset && end > iROffset)end = iROffset;
- if (mid < iROffset)
- {
- if (bIdx1To2)
- TwoMerge(arr, sortIdx1, sortIdx2, beg, mid, end);
- else
- TwoMerge(arr, sortIdx2, sortIdx1, beg, mid, end);
- }
- }
- //數組索引複製反轉
- bIdx1To2 = !bIdx1To2;
- k = 2 * k;
- }
- //-----------------------------
- // 【數組重構及索引數組清理】
- //-----------------------------
- bIdx1To2 ? idxSort_Make(arr, sortIdx1, iROffset) : idxSort_Make(arr, sortIdx2, iROffset);
- delete []sortIdx1;
- delete []sortIdx2;
- }
- #endif
//WinnerTree.h
- /*---------------------------------------
- 【描述】:排序使用的勝者樹(WinnerTree.h)
- Created by Beyond ray, 2015.1
- ----------------------------------------*/
- #ifndef H_WINNER_TREE
- #define H_WINNER_TREE
- template<typename T>
- class WinnerTree
- {
- public:
- WinnerTree(int sortNums);
- ~WinnerTree();
- int init(T arr[]); //初始化勝者樹(產生第一個冠軍)
- int getNewWinner(); //得到新勝者(剔除舊勝者)
- void coutWinnerTree(); //輸出勝者樹(調試用)
- private:
- T* m_Arr; //指向欲排序數組
- int* m_Winner; //勝者樹索引數組(索引-1爲剔除)
- int m_SortNums; //排序個數(比賽個數)
- };
- //構造函數
- template<typename T>
- WinnerTree<T>::WinnerTree(int sortNums) :
- m_SortNums(sortNums)
- {
- assert(m_SortNums > 0);
- m_Winner = new int[2*m_SortNums - 1];
- if (!m_Winner){ cerr << "勝者樹索引數組內存分配失敗"; exit(1); }
- }
- //析構函數
- template<typename T>
- WinnerTree<T>::~WinnerTree()
- {
- if (m_Winner)
- {
- delete[]m_Winner;
- m_Winner = NULL;
- }
- }
- //-------------------------
- // Desc:初始化勝者樹
- //-------------------------
- template<typename T>
- int WinnerTree<T>::init(T arr[])
- {
- m_Arr = arr;
- //初始化參賽者(排序碼)索引序列
- for (int i = m_SortNums - 1, j = 0; i <= 2 * m_SortNums - 2; i++, j++)
- m_Winner[i] = j;
- //構造初始化勝者樹
- int iLChild = 2 * m_SortNums - 3;
- int iRChild = 2 * m_SortNums - 2;
- for (int j = m_SortNums - 2; j >= 0; j--)
- {
- if (arr[m_Winner[iLChild]] <= arr[m_Winner[iRChild]])
- m_Winner[j] = m_Winner[iLChild];
- else
- m_Winner[j] = m_Winner[iRChild];
- //移動比較索引位
- iLChild -= 2;
- iRChild -= 2;
- }
- return m_Winner[0];
- }
- //--------------------------------------
- // Desc:輸出勝者樹
- //--------------------------------------
- template<typename T>
- void WinnerTree<T>::coutWinnerTree()
- {
- for (int i = 0; i < m_SortNums-1; i++)
- {
- cout << m_Arr[m_Winner[i]] << " ";
- }
- cout << endl;
- }
- //--------------------------------------
- // Desc:選取冠軍後,選取新冠軍
- //--------------------------------------
- template<typename T>
- int WinnerTree<T>::getNewWinner()
- {
- //第一次重寫父節點值
- int offset = m_SortNums - 1;
- int lastWinnerIdx = m_Winner[0] + offset;
- m_Winner[lastWinnerIdx] = -1;
- int nearIdx = lastWinnerIdx % 2 == 0 ? (lastWinnerIdx - 1) : (lastWinnerIdx + 1);
- int fatherIdx = (nearIdx - 1) / 2;
- m_Winner[fatherIdx] = m_Winner[nearIdx];
- //一直遍歷到根節點更新最小勝者
- while (fatherIdx != 0)
- {
- fatherIdx = (fatherIdx - 1) / 2;
- int iLChild = 2 * fatherIdx + 1;
- int iRChild = 2 * fatherIdx + 2;
- if (m_Winner[iLChild] == -1)m_Winner[fatherIdx] = m_Winner[iRChild];
- else if (m_Winner[iRChild] == -1) m_Winner[fatherIdx] = m_Winner[iLChild];
- else
- {
- if (m_Arr[m_Winner[iLChild]] <= m_Arr[m_Winner[iRChild]])
- m_Winner[fatherIdx] = m_Winner[iLChild];
- else
- m_Winner[fatherIdx] = m_Winner[iRChild];
- }
- }
- return m_Winner[0];
- }
- #endif
//main.cpp
- /*-----------------------------------
- 【Cpp文件】:main.cpp
- Created by Beyond ray,2015.1
- ----------------------------------*/
- #include "Sort.h"
- #include<iostream>
- using namespace std;
- #include<time.h>
- const int ARR_NUMS = 15;
- int main(int argc, char* argv[])
- {
- srand((unsigned int)time(NULL));
- int a[ARR_NUMS];
- std::function<int(int)> gapFunc = [](int gap){return (gap / 3 + 1); };
- for (int count = 0; count < 9; count++)
- {
- for (int i = 0; i < ARR_NUMS; i++)
- {
- a[i] = rand() % 1000;
- }
- switch (count)
- {
- case 0: BubbleSort(a, 0, ARR_NUMS - 1); cout << "BubbleSort:"; break;
- case 1: ChooseSort(a, 0, ARR_NUMS - 1); cout << "ChooseSort:"; break;
- case 2: InsertSort(a, 0, ARR_NUMS - 1); cout << "InsertSort:"; break;
- case 3: ShellSort(a, 0, ARR_NUMS - 1, gapFunc); cout << "ShellSort:"; break;
- case 4: BinaryInsertSort(a, 0, ARR_NUMS - 1); cout << "BinaryInsertSort:"; break;
- case 5: QuickSort(a, 0, ARR_NUMS - 1); cout << "QuickSort:"; break;
- case 6: HeapSort(a, ARR_NUMS - 1); cout << "HeapSort:"; break;
- case 7: TournamentSort(a, ARR_NUMS - 1); cout << "TournamentSort:"; break;
- case 8: TwoMerge_Sort(a, 0, ARR_NUMS - 1); cout << "TwoMerge_Sort:"; break;
- }
- for (int i = 0; i < ARR_NUMS; i++)
- {
- cout << a[i] <<" ";
- }
- cout << endl;
- }
- return 0;
- }
一次取隨機數的運行結果: