一些基本排序算法的实现

花了点时间一次性实现了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;
}



一次取随机数的运行结果


  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值