九大基础排序算法详解,效率对比

九大算法基础简介

排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存。常见的内部排序算法有:插入排序、希尔排序、选择排序、冒泡排序、归并排序、快速排序、堆排序、基数排序等。用一张图概括:在这里插入图片描述
在这里插入图片描述关于时间复杂度

平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。

线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;

O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序

线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。

关于稳定性

稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。

不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。

名词解释:

  • n:数据规模
  • k:"桶"的个数
  • In-place:占用常数内存,不占用额外内存
  • Out-place:占用额外内存
  • 稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同

运行程序后各大算法效率对比

在这里插入图片描述
待排序的100个1到10000的数,排序30000次

各个算法源代码

mian函数:

在这里插入图片描述

冒泡排序

template<class T>
void BubbleSort(vector<T>& x)
{
	bool flag = true;
	for (unsigned i = 0; i < x.size() && flag; i++) {
		flag = false;
		for (unsigned k = 1; k < x.size(); k++) {
			if (x[k] < x[k - 1]) {
				T temp = x[k];
				x[k] = x[k - 1];
				x[k - 1] = temp;
				flag = true;
			}
		}
	}
}

选择排序

template<class T>
void SelectSort(vector<T>& x)
{
	T temp;
	for (unsigned i = 0; i < x.size(); i++) {
		int minNumIndex = i;
		for (unsigned k = i + 1; k < x.size(); k++) {
			if (x[minNumIndex] > x[k]) {
				minNumIndex = k;
			}
		}
		if (minNumIndex != i) {
			temp = x[minNumIndex];
			x[minNumIndex] = x[i];
			x[i] = temp;
		}
	}
}

插入排序

template<class T>
void InsertSort(vector<T>& x)
{
	T temp;
	for (unsigned i = 0; i < x.size(); i++) {
		for (unsigned k = i + 1; k < x.size(); k++) {
			if (x[i] > x[k]) {
				temp = x[k];
				x[k] = x[i];
				unsigned p = i;
				while (x[p] < temp && p>1) {
					x[p] = x[p - 1];
				}
				x[p] = temp;
			}
		}
	}
}

希尔排序

template<class T>
void ShellSort(vector<T>& x)
{
	int Length = x.size();
	for (int gap = Length / 2; gap > 0; gap /= 2) {
		for (int i = gap; i < Length; i++) {
			T inserted = x[i];//此时待插入的数
			int j;
			for (j = i - gap; j >= 0 && inserted < x[j]; j -= gap) {
				x[j + gap] = x[j];//将当前j位置的值移到gap后的位置
			}
			x[j + gap] = inserted;
		}
	}
}

计数排序

template<class T>
void ShellSort(vector<T>& x)
{
	int Length = x.size();
	for (int gap = Length / 2; gap > 0; gap /= 2) {
		for (int i = gap; i < Length; i++) {
			T inserted = x[i];//此时待插入的数
			int j;
			for (j = i - gap; j >= 0 && inserted < x[j]; j -= gap) {
				x[j + gap] = x[j];//将当前j位置的值移到gap后的位置
			}
			x[j + gap] = inserted;
		}
	}
}

基数排序

template<class T>
void RadixSort(vector<T>& x)
{
	int* count = new int[10]; //计数器
	int raidx = 1;
	int k;
	int index = 0;
	vector<vector<T>>xArray;//创建十个容器
	vector<T> xx;
	for (int i = 0; i < 10; i++) {
		xArray.push_back(xx);
	}
	//得到最大位数
	T maxNum = x[0];
	int weishu = 1;
	for (int i = 1; i < x.size(); i++) {
		if (maxNum < x[i]) { maxNum = x[i]; }
	}
	while (maxNum > 10) {
		weishu++;
		maxNum /= 10;
	}
	for (int j = 0; j < weishu; j++) {//进行weishu次排序
		for (unsigned i = 0; i < x.size(); i++) {
			k = (x[i] / raidx) % 10;//统计每个桶中的记录数
			xArray[k].push_back(x[i]);
		}
		for (unsigned i = 0; i < xArray.size(); i++) {
			for (unsigned p = 0; p < xArray[i].size(); p++) {
				x[index] = xArray[i][p];//将是个容器中的值重新整合到 x中
				index++;
			}
		}
		for (unsigned i = 0; i < xArray.size(); i++) {
			xArray[i].clear();
		}
		raidx *= 10;
		index = 0;
	}
}

二叉树排序

template<class T>
void BSTSort(vector<T>& x)
{
	BST<int>bst(x);
	x = bst.sortToVector();
}

二叉树源码:

#pragma once
#include<iostream>
#include<map>
#include <iomanip>
#include<queue>
using namespace std;
template<typename DataType>
class BST
{
private:
	/**********数据成员*********/
	class BinNode {
	public:
		DataType data;
		BinNode* left;
		BinNode* right;
		BinNode() :left(0), right(0) {}//data默认初始化为DataType类型值,两条链为空
		BinNode(DataType item) :data(item), left(0), right(right) {}//data初始化,其他两条链为空
	};
	typedef BinNode* BinNodePointer;
	BinNodePointer myRoot;//根节点
	void inorderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr)const;
	void foreOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr)const;
	void afterOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr)const;
	void deleteAux(const DataType& item, bool& found, BST<DataType>::BinNodePointer& locptr, BST<DataType>::BinNodePointer& parent)const;
	void BSTAux(BST<DataType>::BinNodePointer& ptr);
	void horizontalGraphAux(ostream& out, int indent, BST<DataType>::BinNodePointer subtreeRoot)const;//打印
	void verticalGraghAux(BST<DataType>::BinNodePointer ptr, vector<DataType>& elementVector)const;
	void SortAux(BST<DataType>::BinNodePointer subtreeptr, vector<DataType>& v)const;//排序辅助函数
public:
	/**********成员函数*********/
	BST();
	//构建空的BST
	BST(vector<DataType>v);
	~BST();//析构函数
	bool empty();//判断BST是否为空,空则返回1
	void add(const DataType& item);//节点的添加函数
	void inorder(ostream& out)const;//中序输出
	void foreorder(ostream& out)const;//前序输出
	void afterOrder(ostream& out)const;//前序输出
	void levelorder(ostream& out)const;//层次遍历输出
	void Delete(const DataType& item);//删除节点
	void graphHorizontal(ostream& out)const;//打印
	void graphVertical(ostream& out)const;//打印
	vector<DataType> sortToVector()const;//排序
};

template<typename DataType>
inline BST<DataType>::BST() :myRoot(0) {}

template<typename DataType>
inline BST<DataType>::BST(vector<DataType> v)
{
	for (int i = 0; i < v.size(); i++) {
		this->add(v[i]);
	}

}

template<typename DataType>
inline BST<DataType>::~BST()
{
	if (myRoot != 0) {
		BSTAux(myRoot->left);
		BSTAux(myRoot->right);
		delete myRoot;
	}
}

template<typename DataType>
bool inline BST<DataType>::empty()
{
	return myRoot == 0;
}

template<typename DataType>
inline void BST<DataType>::add(const DataType& item)
{
	BST<DataType>::BinNodePointer ptr = myRoot, parent = 0;
	while (ptr != 0) {
		parent = ptr;
		if (item < ptr->data) {//下降到左子树
			parent = ptr;
			ptr = ptr->left;
		}
		else if (item >= ptr->data) {//下降到右子树
			parent = ptr;
			ptr = ptr->right;
		}
	}
	ptr = new BST<DataType>::BinNode(item);
	if (parent == 0) {
		myRoot = ptr;
	}
	else if (item < parent->data) {
		parent->left = ptr;
	}
	else {
		parent->right = ptr;
	}
}


template<typename DataType>
inline void BST<DataType>::inorder(ostream& out) const
{
	cout << "中序遍历:  ";
	inorderAux(out, myRoot);
	cout << endl;
}

template<typename DataType>
inline void BST<DataType>::foreorder(ostream& out) const
{
	cout << "前序遍历:  ";
	foreOrderAux(out, myRoot);
	cout << endl;
}

template<typename DataType>
inline void BST<DataType>::afterOrder(ostream& out) const
{
	cout << "后序遍历:  ";
	afterOrderAux(out, myRoot);
	cout << endl;
}

template<typename DataType>
inline void BST<DataType>::levelorder(ostream& out) const
{
	queue<BST<DataType>::BinNodePointer>QueueOut;
	queue<BST<DataType>::BinNodePointer>QueueStore;
	QueueOut.push(myRoot);
	QueueStore.push(myRoot);
	while (!QueueStore.empty()) {
		BST<DataType>::BinNodePointer localItem = QueueStore.front();
		QueueStore.pop();
		if (localItem->left != 0) {
			QueueOut.push(localItem->left);
			QueueStore.push(localItem->left);
		}
		if (localItem->right != 0) {
			QueueOut.push(localItem->right);
			QueueStore.push(localItem->right);
		}

	}
	out << "层次遍历:  ";
	unsigned QueueOutSize = QueueOut.size();
	for (unsigned i = 0; i < QueueOutSize; i++) {
		out << QueueOut.front()->data << " ";
		QueueOut.pop();
	}
	out << endl;
}


template<typename DataType>
inline void BST<DataType>::Delete(const DataType& item)
{
	BST<DataType>::BinNodePointer parent, x = new BinNode();
	bool found;
	deleteAux(item, found, x, parent);//进行x 和 parent的赋值
	if (!found) {
		cout << "该节点没有被找到." << endl;
		return;
	}
	else {
		cout << "待删除的数: " << item << endl;

	}
	//节点有两个子女
	if (x->left != 0 && x->right != 0) {
		//查找x的中序后继 及双亲节点(右子树的最左节点)
		BST<DataType>::BinNodePointer xSucc = x->right;
		parent = x;
		while (xSucc->left != 0) {
			parent = xSucc;
			xSucc = xSucc->left;
		}
		x->data = xSucc->data;//将xSucc中的内容移动到x中,修改x为指向被删除的后继
		x = xSucc;
	}
	//处理只有一个节点或者没有结点的情况
	BST<DataType>::BinNodePointer subtree = x->left;//指向x的子树的指针		
	if (subtree == 0) {//如果指针为空说明x的左子为空 subtree指向x的右子
		subtree = x->right;
	}
	if (parent == 0) { myRoot = subtree; }
	else if (parent->left == x) { parent->left = subtree; }
	else { parent->right = subtree; }
	delete x;
}

template<typename DataType>
inline void BST<DataType>::inorderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr) const
{
	if (subtreeptr != 0) {
		inorderAux(out, subtreeptr->left);
		out << subtreeptr->data << " ";
		inorderAux(out, subtreeptr->right);
	}
}

template<typename DataType>
inline void BST<DataType>::foreOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr) const
{
	if (subtreeptr != 0) {
		out << subtreeptr->data << " ";
		foreOrderAux(out, subtreeptr->left);
		foreOrderAux(out, subtreeptr->right);
	}
}

template<typename DataType>
inline void BST<DataType>::afterOrderAux(ostream& out, BST<DataType>::BinNodePointer subtreeptr) const
{
	if (subtreeptr != 0) {
		afterOrderAux(out, subtreeptr->left);
		afterOrderAux(out, subtreeptr->right);
		out << subtreeptr->data << " ";
	}
}

template<typename DataType>
inline void BST<DataType>::deleteAux(const DataType& item, bool& found, BST<DataType>::BinNodePointer& locptr, BST<DataType>::BinNodePointer& parent) const
{
	locptr = myRoot;
	parent = 0;
	found = false;
	while (!found && locptr != 0) {
		if (item < locptr->data) {
			parent = locptr;
			locptr = locptr->left;
		}
		else if (item > locptr->data) {
			parent = locptr;
			locptr = locptr->right;
		}
		else {
			found = true;
		}
	}
}

template<typename DataType>
inline void BST<DataType>::BSTAux(BST<DataType>::BinNodePointer& ptr)
{
	if (ptr != 0) {
		BSTAux(ptr->left);
		BSTAux(ptr->right);
		delete ptr;
	}
}

template<typename DataType>
inline void BST<DataType>::graphHorizontal(ostream& out) const
{
	horizontalGraphAux(out, 0, myRoot);
}

template<typename DataType>
inline void BST<DataType>::horizontalGraphAux(ostream& out, int indent, BST<DataType>::BinNodePointer subtreeRoot) const
{
	if (subtreeRoot != 0) {
		horizontalGraphAux(out, indent + 8, subtreeRoot->right);
		out << setw(indent) << " " << subtreeRoot->data << endl;
		//setw当后面紧跟着的输出字段长度小于 n 的时候,在该字段前面用空格补齐,当输出字段长度大于 n 时,全部整体输出。
		horizontalGraphAux(out, indent + 8, subtreeRoot->left);
	}
}

template<typename DataType>
inline void BST<DataType>::verticalGraghAux(BST<DataType>::BinNodePointer ptr, vector<DataType>& elementVector)const
{
	if (ptr != 0) {
		verticalGraghAux(ptr->left, elementVector);
		elementVector.push_back(ptr->data);
		verticalGraghAux(ptr->right, elementVector);
	}
}

template<typename DataType>
inline void BST<DataType>::SortAux(BST<DataType>::BinNodePointer subtreeptr, vector<DataType>& v) const
{
	if (subtreeptr != 0) {
		SortAux(subtreeptr->left, v);
		v.push_back(subtreeptr->data);
		SortAux(subtreeptr->right, v);
	}
}

template<typename DataType>
inline void BST<DataType>::graphVertical(ostream& out) const
{
	vector<DataType> v;
	verticalGraghAux(myRoot, v);
	queue<BST<DataType>::BinNodePointer> q;
	q.push(myRoot);
	while (!q.empty()) {
		vector<BST<DataType>::BinNodePointer> cache;
		//把处在同一行的节点拉出来
		while (!q.empty()) { cache.push_back(q.front()); q.pop(); }
		map<DataType, int> elementMap;
		for (auto p : cache) {
			if (p) {
				//找当前节点中序遍历位置
				typename vector<DataType>::iterator iter;
				iter = find(v.begin(), v.end(), p->data);
				int index = iter - v.begin();
				elementMap.insert(pair<DataType, int>(p->data, index));
				//孩子节点入队
				if (p->left) q.push(p->left);
				if (p->right) q.push(p->right);
			}
		}
		typename map<DataType, int>::iterator iter;
		int gap = 0;
		for (iter = elementMap.begin(); iter != elementMap.end(); iter++)
		{
			for (int i = 0; i < iter->second - gap; i++) {
				out << " ";
			}
			cout << iter->first;
			gap = iter->second;
		}
		out << endl;
	}

}
template<typename DataType>
inline vector<DataType> BST<DataType>::sortToVector() const
{
	vector<DataType> v1;
	SortAux(myRoot, v1);
	return v1;
}
#pragma once

快排

template<class T>
void QuickSort(vector<T>& x, int first, int last)
{
	int pos = 0;
	if (first < last) {
		pos = split(x, first, last);
		QuickSort(x, first, pos - 1);
		QuickSort(x, pos + 1, last);
	}
}
template<class T>
int split(vector<T>& x, int first, int last)
{
	T pivot = x[first];
	int left = first,//序列开始头部
		right = last;//序列开始尾部
	while (left < right) {//结束条件为标记头和标记尾碰到一起
		while (pivot < x[right]) {
			//从从右往左开始,为何?
			//因为如果从左往右 该序列有序且服从从小到大,则left会一直++,直至越界报错
			right--;
		}
		while (left < right && (x[left] <= pivot)) {
			//如果做标记没有碰到右标记,且当前左标记所在的值小于pivot
			left++;
		}
		if (left < right) {//交换左标记点和右标记点的值
			int temp = x[left];
			x[left] = x[right];
			x[right] = temp;
		}
	}
	//左标记点和有标记点碰到一起,交换pivot和左右标记点所在点的值
	int pos = right;
	x[first] = x[pos];
	x[pos] = pivot;
	return pos;//返回当前界值
}

堆排序

template<class T>
void HeapSort(vector<T>& x)
{
	int count = 0;
	makeHeapify(x);//进行建堆,x[i]必大于x[i*2]和x[i*2+1]
	for (int i = x.size() - 1; i >= 2; i--) {
		//进行根叶交换
		T temp = x[i];
		x[i] = x[1];
		x[1] = temp;
		//进行下调
		percolate_down(1, i - 1, x);
	}
}

//建堆算法
template<class T>
void makeHeapify(vector<T>& x) {
	int n = x.size() - 1;
	for (int i = n / 2; i >= 1; i--) {
		percolate_down(i, n, x);//对i为根的子树进行下调算法
	}

}
//下调算法(只有x[index]中的值不满足堆次序条件,把这个近似堆调整成堆)
template<class T>
void percolate_down(int index, int last, vector<T>& x) {
	int c = index * 2;
	int n = last;
	bool flag = false;
	while (c <= n && !flag) {//c是左子节点的位置
		if (c < n && x[c] < x[c + 1]) {//如果index有两个子节点并且右子节点比较大
			c++;
		}
		if (x[index] < x[c]) {//双亲节点不满足堆次排序
			T temp = x[index];
			x[index] = x[c];
			x[c] = temp;

			index = c;//可能弄乱了以c为根的二叉树,检查其下的二叉树
			c = 2 * c;
		}
		else {
			flag = true;//条件满足,结束循环
		}
	}
}
//上调算法,在其中添加一个元素,并使得排序仍然满足是一个堆
template<class T>
void percolate_up(vector<T>& x, T item) {
	x.push_back(item);
	bool flag = false;
	int itemLocation = x.size() - 1;
	int parentLocation = itemLocation / 2;
	while (parentLocation >= 1 && !flag) {
		if (x[parentLocation] < x[itemLocation]) {
			T temp = x[parentLocation];
			x[parentLocation] = x[itemLocation];
			x[itemLocation] = temp;
			itemLocation = parentLocation;
			parentLocation /= 2;
		}
		else { flag = true; }
	}
}

运行结果

在这里插入图片描述

本系列算法开篇内容整理自:https://www.runoob.com/w3cnote/ten-sorting-algorithm.html
其余内容为数据结构相关内容自行编程
排序算法是《数据结构与算法》中最基本的算法之一。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值