花了点时间一次性实现9个基本排序算法,
其中包括:
【冒泡排序】,【直接选择排序】,【直接插入排序】,
【希尔排序】,【折半插入排序】,【快速排序】,
【堆排序】,【锦标赛排序】,【归并排序】。
储存方式是用数组,元素可以是支持重载运算符的自定义类型,
有在数组中直接复制的,也有在中间过程中用索引记录的,
但最终都结果都保存在原数组中,废话不多说了,直接上代码!
//Sort.h
/*------------------------------------ 【描述】:一些排序算法(Sort.h) Created by Beyond ray, 2014.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; 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, 2014.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]; } //析构函数 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
/*----------------------------------- 【Cpp文件】:main.cpp Created by Beyond ray,2014.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; }
原文地址:http://blog.csdn.net/beyond_ray/article/details/42807687