您的位置:首页 > 其它

一些基本排序算法的实现(转载)

2015-01-17 22:46 337 查看


一些基本排序算法的实现

分类: C/C++ 算法设计和优化2015-01-17
19:16 117人阅读 评论(1) 收藏 举报

c++排序算法希尔排序归并排序算法

花了点时间一次性实现了9个基本排序算法,

其中包括:

【冒泡排序】,【直接选择排序】,【直接插入排序】,

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

【堆排序】,【锦标赛排序】,【归并排序】。

储存方式是用数组,元素可以是支持重载运算符的自定义类型,

有在数组中直接复制元素的,也有在中间过程中用索引数组记录

索引序列的,但最终结果都保存在原数组中,

好了,废话不多说了,直接上源代码!

//Sort.h

[cpp] view
plaincopy





/*------------------------------------

【描述】:一些排序算法(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

[cpp] view
plaincopy





/*---------------------------------------

【描述】:排序使用的胜者树(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] view
plaincopy





/*-----------------------------------

【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;

}

一次取随机数的运行结果:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: