一些基本排序算法的实现

来源:互联网 发布:滴滴大数据平台 编辑:程序博客网 时间:2024/06/05 20:22

花了点时间一次性实现了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++){for(int j = i; j >= left;j-= gap){if(arr[j] > arr[j + gap])Swap(arr[j], arr[j + gap]);elsebreak;}}}}//--------------------------------------------// 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;elseimaxEleIdx = 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);elseTwoMerge(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_TREEtemplate<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];elsem_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];elsem_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;const int END_IDX = ARR_NUMS - 1;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 <= END_IDX; i++){a[i] = rand() % 1000;}switch (count){case 0:BubbleSort(a, 0,END_IDX); cout << "BubbleSort:"; break;case 1:ChooseSort(a, 0, END_IDX); cout << "ChooseSort:"; break;case 2:InsertSort(a, 0, END_IDX); cout << "InsertSort:"; break;case 3:ShellSort(a, 0, END_IDX, gapFunc); cout << "ShellSort:"; break;case 4:BinaryInsertSort(a, 0, END_IDX); cout << "BinaryInsertSort:"; break;case 5:QuickSort(a, 0, END_IDX); cout << "QuickSort:"; break;case 6:HeapSort(a, END_IDX); cout << "HeapSort:"; break;case 7:TournamentSort(a, END_IDX); cout << "TournamentSort:"; break;case 8:TwoMerge_Sort(a, 0, END_IDX); cout << "TwoMerge_Sort:"; break;}for (int i = 0; i <= END_IDX; i++){cout << a[i] <<" ";}cout << endl;}system("pause");return 0;}



一次取随机数的运行结果


4 0
原创粉丝点击