排序算法:冒泡、选择、插入、希尔、堆排、桶排、快排、归并


记录我的码农之路~~~
算法为C++实现。
共包含 冒泡排序选择排序插入排序希尔排序堆排序桶排序快速排序以及 归并排序… …
注:算法是初学自己捋着思路写的,有不足之处还请大家指正一起优化~~~
时间、空间复杂度一览:

排序 平均时间复杂度 最优情况 最坏情况 空间复杂度 稳定性
冒泡排序 O(N^2) O(N) O(N^2) O(1) 稳定
选择排序 O(N^2) O(N^2) O(N^2) O(1) 不稳定
插入排序 O(N^2) O(N) O(N^2) O(1) 稳定
希尔排序 O(N^1.3) O(^1.3) O(N^2) O(1) 不稳定
堆排序 O(N*logN) O(N*logN) O(N*logN) O(1) 不稳定
归并排序 O(N*logN) O(N*logN) O(N*logN) O(N) 稳定
快速排序 O(N*logN) O(N*logN) O(N*logN) O(logN) 不稳定
桶排序 O(N) O(N) O(N) O(N+M) 不稳定

注:桶排序中M指所用桶的数量。

排序

冒泡排序

	template<class T>//冒泡排序
	void BubbleSort(T* vec, int n) {
    
    
		int flag = 0;//标记法判断是否发生 交换
		for (int i = n; i > 1; i--)
		{
    
    //一共i个数进行排序
			for (int j = 0; j < i - 1; j++)
			{
    
    
				if (vec[j] > vec[j + 1])
				{
    
    
					Swap<T>(vec[j], vec[j + 1]);
					flag = 1;  //发生交换才将flag置1
				}
			}
			if (flag == 0) //一整趟下来没发生交换,说明无需继续排序,跳出循环
				break;
		}
	}

时间复杂度O(N^2) 空间复杂度O(1)

选择排序

	template<class T>//选择排序
	void SeleteSort(T* vec, int n)
	{
    
    
		for (int i = n; i > 1; i--)//i表示进行选择排序的数量
		{
    
    
			int indexMax = 0;
			for (int j = 1; j < i; j++)
			{
    
    
				if (vec[j] > vec[indexMax])
				{
    
    
					indexMax = j; //寻找最大值下标
				}
			}
			if (indexMax != i - 1)//如果最大值不是当前的“最后”一个元素就交换位置
				Swap(vec[indexMax], vec[i - 1]);
		}
	}

时间复杂度O(N^2) 空间复杂度O(1)

直接插入排序

	template<class T>//直接插入排序
	void InsertSort(T* vec, int n)
	{
    
    
		for (int i = 1; i < n; i++)
		{
    
    //有序与无序的分界线
			int j = i - 1;
			T tmp = vec[i];
			for (; j >= 0 && tmp < vec[j]; j--)//找第一个比它小的数
			{
    
    
				//移动过程中完成数据迁移
				vec[j + 1] = vec[j];
			}
			vec[j + 1] = tmp;
		}
	}

时间复杂度O(N^2) 空间复杂度O(1)

希尔排序

	template<class T>//希尔插入排序
	void ShellSort(T* vec, int n)
	{
    
    
		for (int gap = n / 2; gap >= 1; gap /= 2)
		{
    
    
			for (int i = 0; i < gap; i++)
				groupSort(vec, n / gap, i, gap);
		}
	}
	
	template<class T>//n代表进行插入排序元素的个数,start为排序首地址,gap为间隙
	void groupSort(T* vec, int n, int start, int gap)//传入数组、起始下标、希尔间隙进行插入排序
	{
    
    
		int i, j;
		for (i = start + gap; i < n; i += gap)
		{
    
    
			T tmp = vec[i];//用变量tmp记录需要插入的元素
			for (j = i - gap; tmp < vec[j] && j >= 0; j -= gap)
				vec[j + gap] = vec[j];
			vec[j + gap] = tmp;
		}
	}

时间复杂度O(N^1.3) 空间复杂度O(1)

堆排序

	template<class T>//堆排序(堆调整)
	void adjustHeap(T* vec, int curindex, int maxindex)
	{
    
    
		int father = curindex;
		int child = 2 * father + 1;//左孩子节点
		while (child <= maxindex)
		{
    
    
			if (child + 1 <= maxindex && vec[child + 1] > vec[child])//说明有右孩子
				child++;//使用右孩子下标(与父节点比较)
			if (vec[child] > vec[father])//若孩子节点大于父节点,则交换
			{
    
    
				Swap(vec[child], vec[father]);
				father = child;  //交换后检测子节点的位置是否是最大堆
				child = 2 * father + 1;
			}
			else
				break;//无交换,跳出循环
		}
	}
	
	template<typename T>//堆排序
	void HeapSort(T* vec, int maxindex)
	{
    
    
		for (int i = (maxindex - 1) / 2; i >= 0; i--)//初始化最大堆结构
			adjustHeap(vec, i, maxindex);
		for (int i = maxindex; i > 0;)
		{
    
    
			Swap(vec[0], vec[i]);//交换首尾元素
			i--;
			for (int j = (i - 1) / 2; j >= 0; j--)//调整堆结构为最大堆
				adjustHeap(vec, j, i);//重新对堆进行排序
		}
	}

时间复杂度O(N*logN) 空间复杂度O(1)

桶排序

	template<class T>//桶排序
	void BuckerSort(T* vec, int n)
	{
    
    
		T max = vec[0];
		for (int i = 1; i < n; i++)
			if (vec[i] > max)
				max = vec[i];
		T* bucket = new T[max + 1]();
		for (int i = 0; i < n; i++)
			bucket[vec[i]]++;
		int start = 0;
		for (T i = 0; i < max + 1; i++)
		{
    
    
			while (bucket[i]--) {
    
    
				vec[start++] = i;
			}
		}
	}

时间复杂度O(N) 空间复杂度O(N)

快速排序

	template<typename T>//荷兰国旗法快速排序
	pair<int, int > HL_NtionalFlag(T* vec, int start, int end)
	{
    
    
		int i = start - 1, j = end + 1, index = start;
		T flag = vec[index];
		while (index < j)
		{
    
    
			if (vec[index] == flag)
				index++;
			else if (vec[index] < flag) {
    
    
				Swap(vec[index++], vec[++i]);
			}
			else {
    
    
				Swap(vec[index], vec[--j]);
			}
		}
		return make_pair(i, j);
	}
	template <typename T>
	
	void RecurQuickSort(T* vec, int start, int end)//递归法赫拉国旗快排
	{
    
    
		if (start >= end)
			return;
		pair<int, int> p = HL_NtionalFlag(vec, start, end);
		RecurQuickSort(vec, start, p.first);//左半部分
		RecurQuickSort(vec, p.second, end);//右半部分
	}
	
	template<class T>
	void Non_recurQuick(T* vec, int start, int end)//start/end均为数字下标
	{
    
    
		stack<pair<int, int>> stk;//定义一个pair类型的栈来存储每次进行荷兰国旗排序的下标值
		stk.push(make_pair(start, end));

		while (!stk.empty())
		{
    
    
			pair<int, int> p = stk.top();//得到上一次排序分界线的两个位置
			stk.pop();//用完将栈区变量弹出
			pair<int, int> part = HL_NtionalFlag(vec, p.first, p.second);
			if (part.first > p.first)//表示这一次左半部分快排有改变
				stk.push(make_pair(p.first, part.first));//上次排序的i值是开始,排序完的i是结束的位置
			if (part.second < p.second)
				stk.push(make_pair(part.second, p.second));//上次的j是结束的位置,排序完是开始id位置
		}
	}

时间复杂度O(N*logN) 空间复杂度O(logN)

归并排序

	template<class T>//归并整合
	void Merge(T* vec, int l, int mid, int r)
	{
    
    
		T* help = new T[r - l + 1];//堆区申请空间
		int index = 0, i = l, j = mid + 1;
		while (i <= mid && j <= r)//两部分数组分别比较
		{
    
    
			if (vec[i] <= vec[j])
				help[index++] = vec[i++];
			else
				help[index++] = vec[j++];
		}
		while (i <= mid)//将两部分中还没放入help数组中元素逐一放进去
		{
    
    
			help[index++] = vec[i++];
		}
		while (j <= r)
		{
    
    
			help[index++] = vec[j++];
		}
		//将元素从help数组重新放入原地
		index = l;//记录原数组最小下标
		for (i = 0; i < r - l + 1; i++)
			vec[index++] = help[i];
		delete[] help;
	}
	
	template<typename T>//归并排序
	void MergeSort(T* vec, int l, int r)
	{
    
    
		int mid = (l + r) / 2;
		if (l >= r)//将数组不断分裂,到单块数组长度为 1 时停止,跳出递归
		{
    
    
			return;
		}
		MergeSort(vec, l, mid); //递归调用
		MergeSort(vec, mid + 1, r);
		//分裂后进行逐层排序组合
		Merge(vec, l, mid, r);
	}

时间复杂度O(N*logN) 空间复杂度O(N)

完整代码

#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <time.h>
#include <stack>
using namespace std;

class Sort {
    
    
public:
	/*************************************************************/
	template<class T>//冒泡排序
	void BubbleSort(T* vec, int n) {
    
    
		int flag = 0;//标记法判断是否发生 交换
		for (int i = n; i > 1; i--)
		{
    
    //一共i个数进行排序
			for (int j = 0; j < i - 1; j++)
			{
    
    
				if (vec[j] > vec[j + 1])
				{
    
    
					Swap<T>(vec[j], vec[j + 1]);
					flag = 1;  //发生交换才将flag置1
				}
			}
			if (flag == 0) //一整趟下来没发生交换,说明无需继续排序,跳出循环
				break;
		}
	}
	/*************************************************************/
	template<class T>//选择排序
	void SeleteSort(T* vec, int n)
	{
    
    
		for (int i = n; i > 1; i--)//i表示进行选择排序的数量
		{
    
    
			int indexMax = 0;
			for (int j = 1; j < i; j++)
			{
    
    
				if (vec[j] > vec[indexMax])
				{
    
    
					indexMax = j; //寻找最大值下标
				}
			}
			if (indexMax != i - 1)//如果最大值不是当前的“最后”一个元素就交换位置
				Swap(vec[indexMax], vec[i - 1]);
		}
	}
	/*************************************************************/
	template<class T>//直接插入排序
	void InsertSort(T* vec, int n)
	{
    
    
		for (int i = 1; i < n; i++)
		{
    
    //有序与无序的分界线
			int j = i - 1;
			T tmp = vec[i];
			for (; j >= 0 && tmp < vec[j]; j--)//找第一个比它小的数
			{
    
    
				//移动过程中完成数据迁移
				vec[j + 1] = vec[j];
			}
			vec[j + 1] = tmp;
		}
	}
	/*************************************************************/
	template<class T>//希尔插入排序
	void ShellSort(T* vec, int n)
	{
    
    
		for (int gap = n / 2; gap >= 1; gap /= 2)
		{
    
    
			for (int i = 0; i < gap; i++)
				groupSort(vec, n / gap, i, gap);
		}
	}
	template<class T>//n代表进行插入排序元素的个数,start为排序首地址,gap为间隙
	void groupSort(T* vec, int n, int start, int gap)//传入数组、起始下标、希尔间隙进行插入排序
	{
    
    
		int i, j;
		for (i = start + gap; i < n ; i += gap)
		{
    
    
			T tmp = vec[i];//用变量tmp记录需要插入的元素
			for (j = i - gap; tmp < vec[j] && j >= 0; j -= gap)
				vec[j + gap] = vec[j];
			vec[j + gap] = tmp;
		}
	}
	/*************************************************************/
	template<class T>//堆排序(堆调整)
	void adjustHeap(T* vec, int curindex, int maxindex)
	{
    
    
		int father = curindex;
		int child = 2 * father + 1;//左孩子节点
		while (child <= maxindex)
		{
    
    
			if (child + 1 <= maxindex && vec[child + 1] > vec[child])//说明有右孩子
				child++;//使用右孩子下标(与父节点比较)
			if (vec[child] > vec[father])//若孩子节点大于父节点,则交换
			{
    
    
				Swap(vec[child], vec[father]);
				father = child;  //交换后检测子节点的位置是否是最大堆
				child = 2 * father + 1;
			}
			else
				break;//无交换,跳出循环
		}
	}
	template<typename T>//堆排序
	void HeapSort(T* vec, int maxindex)
	{
    
    
		for (int i = (maxindex - 1) / 2; i >= 0; i--)//初始化最大堆结构
			adjustHeap(vec, i, maxindex);
		for (int i = maxindex; i > 0;)
		{
    
    
			Swap(vec[0], vec[i]);//交换首尾元素
			i--;
			for (int j = (i - 1) / 2; j >= 0; j--)//调整堆结构为最大堆
				adjustHeap(vec, j, i);//重新对堆进行排序
		}
	}
	/*************************************************************/
	template<class T>//桶排序
	void BuckerSort(T* vec, int n)
	{
    
    
		T max = vec[0];
		for (int i = 1; i < n; i++)
			if (vec[i] > max)
				max = vec[i];
		T* bucket = new T[max + 1]();
		for (int i = 0; i < n; i++)
			bucket[vec[i]]++;
		int start = 0;
		for (T i = 0; i < max + 1; i++)
		{
    
    
			while (bucket[i]--) {
    
    
				vec[start++] = i;
			}
		}

	}
	/*************************************************************/
	template<typename T>//荷兰国旗法快速排序
	pair<int, int > HL_NtionalFlag(T* vec, int start, int end)
	{
    
    
		int i = start - 1, j = end + 1, index = start;
		T flag = vec[index];
		while (index < j)
		{
    
    
			if (vec[index] == flag)
				index++;
			else if (vec[index] < flag) {
    
    
				Swap(vec[index++], vec[++i]);
			}
			else {
    
    
				Swap(vec[index], vec[--j]);
			}
		}
		return make_pair(i, j);
	}
	template <typename T>
	void RecurQuickSort(T* vec, int start, int end)//递归法赫拉国旗快排
	{
    
    
		if (start >= end)
			return;
		pair<int, int> p = HL_NtionalFlag(vec, start, end);
		RecurQuickSort(vec, start, p.first);//左半部分
		RecurQuickSort(vec, p.second, end);//右半部分
	}
	template<class T>
	void Non_recurQuick(T* vec, int start, int end)//start/end均为数字下标
	{
    
    
		stack<pair<int, int>> stk;//定义一个pair类型的栈来存储每次进行荷兰国旗排序的下标值
		stk.push(make_pair(start, end));

		while (!stk.empty())
		{
    
    
			pair<int, int> p = stk.top();//得到上一次排序分界线的两个位置
			stk.pop();//用完将栈区变量弹出
			pair<int, int> part = HL_NtionalFlag(vec, p.first, p.second);
			if (part.first > p.first)//表示这一次左半部分快排有改变
				stk.push(make_pair(p.first, part.first));//上次排序的i值是开始,排序完的i是结束的位置
			if (part.second < p.second)
				stk.push(make_pair(part.second, p.second));//上次的j是结束的位置,排序完是开始id位置
		}
	}
	/*************************************************************/
	template<class T>//归并整合
	void Merge(T* vec, int l,int mid, int r)
	{
    
    	
		T* help = new T[r - l + 1];//堆区申请空间
		int index = 0,i = l,j = mid + 1;
		while (i <= mid && j <= r)//两部分数组分别比较
		{
    
    
			if (vec[i] <= vec[j])
				help[index++] = vec[i++];
			else
				help[index++] = vec[j++];
		}
		while (i <= mid)//将两部分中还没放入help数组中元素逐一放进去
		{
    
    
			help[index++] = vec[i++];
		}
		while (j <= r)
		{
    
    
			help[index++] = vec[j++];
		}
		//将元素从help数组重新放入原地
		index = l;//记录原数组最小下标
		for (i = 0; i < r - l + 1; i++)
			vec[index++] = help[i];
		delete[] help;
	}
	template<typename T>//归并排序
	void MergeSort(T* vec, int l,int r)
	{
    
    
		int mid = (l + r) / 2;
		if (l >= r)//将数组不断分裂,到单块数组长度为 1 时停止,跳出递归
		{
    
    
			return;
		}
		
		MergeSort(vec, l, mid); //递归调用
		MergeSort(vec, mid + 1, r);
		//分裂后进行逐层排序组合
		Merge(vec, l, mid, r);
	}
	/*************************************************************/
	template<class T>//打乱数组
	void Interupt(T* p, int n)//随机打乱数组
	{
    
    
		srand(time(0));
		for (int i = 0; i < 100000; i++)//产生模拟时间差
			for (int j = 0; j < 5000; j++);
		for (int i = 0; i < n; i++)
		{
    
    
			int j = rand() % n;
			Swap<T>(p[i], p[j]);
		}
	}
	/*************************************************************/
	template<class T>//打印数组
	void PrintVec(T* vec, int n)
	{
    
    
		for (int i = 0; i < n; i++)
			cout << vec[i] << "    ";
		cout << endl;
	}
	/************************************************************/
	template<class T>//交换元素
	void Swap(T& a, T& b)
	{
    
    
		T t = a;
		a = b;
		b = t;
	}
};

int main() {
    
    
	Sort s;
	int a[] = {
    
    2,1,3,5,4,6,8,7};
	int n = sizeof(a)/sizeof(int);
	cout << "原数组:" << endl;
	s.PrintVec(a, n);
	cout << endl << "堆排序:" << endl;;
	s.HeapSort(a, n - 1);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "桶排序:" << endl;;
	s.BuckerSort(a, n);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "冒泡排序:" << endl;;
	s.BubbleSort(a, n);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "插入排序:" << endl;;
	s.InsertSort(a, n);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "选择排序:" << endl;;
	s.SeleteSort(a, n);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "希尔排序:" << endl;;
	s.ShellSort(a, n);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "快速排序(递归):" << endl;
	s.RecurQuickSort(a, 0, n - 1);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "快速排序(非递归):" << endl;
	s.Non_recurQuick(a, 0, n - 1);
	s.PrintVec(a, n);
	cout << endl << "打乱后数组:" << endl;
	s.Interupt(a, n);
	s.PrintVec(a, n);
	cout << endl << "归并排序:" << endl;
	s.MergeSort(a, 0, n - 1);
	s.PrintVec(a, n);
	return 0;
}

效果图:
P1
P2
未完待续~~~

猜你喜欢

转载自blog.csdn.net/Genius_bin/article/details/112747869