花了点时间一次性实现了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]);
else
break;
}
}
}
}
//--------------------------------------------
// 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;
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;
}
一次取随机数的运行结果: