C++ 经典排序分析

C++ 经典排序分析
1、复杂度分析
在这里插入图片描述
稳定:如果a原本在b前面,而a=b,排序之后a仍然在b的前面。
不稳定:如果a原本在b的前面,而a=b,排序之后 a 可能会出现在 b 的后面。
时间复杂度:对排序数据的总的操作次数。反映当n变化时,操作次数呈现什么规律。
空间复杂度:是指算法在计算机内执行时所需存储空间的度量,它也是数据规模n的函数。
2、快速排序

void quick(vector<int>& all, int left, int right) {
	int jizhun, i, j;
	if (left > right)return;//不合逻辑
	jizhun = all[left];//找到基准值
	i = left;//左右指针
	j = right;
	while (i != j) {
		while (jizhun <= all[j] && i < j)j--;//从右至左找到小于基准值的
		while (jizhun >= all[i] && i < j)i++;//从左至右找到大于基准值的
		if (i < j)swap(all[i], all[j]);//找到后交换,使基准值左边的值小于他,右边的大于他。
	}
	all[left] = all[i];//把基准值放到适当的位置,符合上面的注释
	all[i] = jizhun;
	quick(all, left, i - 1);//左右分治
	quick(all, i + 1, right);
}
int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	quick(all, 0, n - 1);
	cout << "快排后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;
}

3、冒泡排序
冒泡排序在扫描过程中两两比较相邻记录,如果反序则交换,最终,最大记录就被“沉到”了序列的最后一个位置,第二遍扫描将第二大记录“沉到”了倒数第二个位置,重复上述操作,直到n-1 遍扫描后,整个序列就排好序了。

//冒泡
void Bub(vector<int>& all) {
	if (all.size() <= 1)return;
	for (int i = 0; i < all.size() - 1; i++) {
		for (int j = 0; j < all.size() - 1 - i; j++) {
			if (all[j] > all[j + 1])swap(all[j], all[j + 1]);
		}
	}
}


int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	Bub(all);
	//quick(all, 0, n - 1);
	cout << "排序后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;
}

4、选择排序
选择排序也是一种简单直观的排序算法。它的工作原理很容易理解:初始时在序列中找到最小(大)元素,放到序列的起始位置作为已排序序列;然后,再从剩余未排序元素中继续寻找最小(大)元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

//选择
void Sel(vector<int>& all) {
	if (all.size() <= 1)return;
	int i, j, minind;
	for (i = 0; i < all.size() - 1; i++) {
		minind = i;
		for (j = i + 1; j < all.size(); j++) {
			minind = all[j] < all[minind] ? j : minind;
		}
		swap(all[i], all[minind]);
	}
}

int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	Sel(all);
	//Bub(all);
	//quick(all, 0, n - 1);
	cout << "排序后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;
}

5、插入排序
直接插入排序(straight insertion sort),有时也简称为插入排序(insertion sort),是减治法的一种典型应用。其基本思想如下:
对于一个数组A[0,n]的排序问题,假设认为数组在A[0,n-1]排序的问题已经解决了。考虑A[n]的值,从右向左扫描有序数组A[0,n-1],直到第一个小于等于A[n]的元素,将A[n]插在这个元素的后面。

//插入
void Ins(vector<int>& all) {
	if (all.size() <= 1)return;
	for (int i = 1; i < all.size(); i++) {
		for (int j = i; j > 0; j--) {
			if (all[j] < all[j - 1])swap(all[j], all[j - 1]);
			else break;
		}
	}
}

int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	Ins(all);
	//Sel(all);
	//Bub(all);
	//quick(all, 0, n - 1);
	cout << "排序后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;

6、归并排序
归并排序(MERGE-SORT)是利用归并的思想实现的排序方法,该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解,而治(conquer)的阶段则将分的阶段得到的各答案"修补"在一起,即分而治之)。

//归并
void MMar(vector<int>& all, int left, int mid, int right, vector<int>& temp) {
	if (all.empty())return;
	int i = left, j = mid + 1, k = 0;
	while (i <= mid && j <= right) {
		if (all[i] <= all[j]) {
			temp[k++] = all[i++];
			continue;
		}
		temp[k++] = all[j++];
	}
	while (i <= mid)temp[k++] = all[i++];
	while (j <= right)temp[k++] = all[j++];
	int t = 0;
	int tt = left;
	while (t < k)all[tt++] = temp[t++];
}
void MMst(vector<int>& all, int left, int right, vector<int>& temp) {
	if (left < right) {
		int mid = (left + right) / 2;
		MMst(all, left, mid, temp);
		MMst(all, mid + 1, right, temp);
		MMar(all, left, mid, right, temp);
	}
}
void Mst(vector<int>& all) {
	if (all.size() <= 1)return;
	vector<int>temp(all.size());
	MMst(all, 0, all.size() - 1, temp);
}
int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	Mst(all);
	//Ins(all);
	//Sel(all);
	//Bub(all);
	//quick(all, 0, n - 1);
	cout << "排序后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;
}

7、希尔排序
希尔排序是把记录按下标的一定增量分组,对每组使用直接插入排序算法排序;随着增量逐渐减少,每组包含的关键词越来越多,当增量减至1时,整个文件恰被分成一组,算法便终止。

//希尔排序
void she(vector<int>& all) {
	if (all.size() <= 1)return;
	for (int i = all.size() / 2; i >= 1; i /= 2) {
		for (int k = 0; k < i; k++) {
			for (int ii = i + k; ii < all.size(); ii += i) {
				for (int j = ii; j > k; j -= i) {
					if (all[j] < all[j - i])swap(all[j], all[j - i]);
					else break;
				}
			}
		}
	}
}
int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	she(all);
	//Mst(all);
	//Ins(all);
	//Sel(all);
	//Bub(all);
	//quick(all, 0, n - 1);
	cout << "排序后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;
}

8、堆排序
堆排序实际上是利用堆的性质来进行排序的,要知道堆排序的原理我们首先一定要知道什么是堆。
堆的定义:
堆实际上是一棵完全二叉树。
堆满足两个性质:
1、堆的每一个父节点都大于(或小于)其子节点;
2、堆的每个左子树和右子树也是一个堆。
堆的分类:
堆分为两类:
1、最大堆(大顶堆):堆的每个父节点都大于其孩子节点;
2、最小堆(小顶堆):堆的每个父节点都小于其孩子节点;
可以看出堆的第一个元素要么是最大值(大顶堆),要么是最小值(小顶堆),这样在排序的时候(假设共n个节点),直接将第一个元素和最后一个元素进行交换,然后从第一个元素开始进行向下调整至第n-1个元素。所以,如果需要升序,就建一个大堆,需要降序,就建一个小堆。
堆排序的步骤分为三步:
1、建堆(升序建大堆,降序建小堆);
2、交换数据;
3、向下调整。
堆的存储:
一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。

//堆排序大堆
void adH(vector<int>& all, int node, int len) {
	int ind = node;
	int child = 2 * ind + 1;
	while (child < len) {
		if (child + 1 < len && all[child] < all[child + 1]) {
			child++;
		}
		if (all[ind] >= all[child])break;
		swap(all[ind], all[child]);
		ind = child;
		child = 2 * ind + 1;
	}
}
void makeH(vector<int>& all) {
	for (int i = all.size() / 2; i >= 0; i--) {
		adH(all, i, all.size());
	}
}
void Hst(vector<int>& all) {
	if (all.size() <= 1)return;
	makeH(all);
	for (int i = all.size() - 1; i >= 0; i--) {
		swap(all[i], all[0]);
		adH(all, 0, i);
	}
}

int main() {
	cout << "要排几个数字:";
	int n;
	cin >> n;
	cout << "输入要排的数字:";
	vector<int>all(n);
	for (int i = 0; i < n; i++) {
		cin >> all[i];
	}
	Hst(all);
	//she(all);
	//Mst(all);
	//Ins(all);
	//Sel(all);
	//Bub(all);
	//quick(all, 0, n - 1);
	cout << "排序后的数字:";
	for (auto& a : all)cout << a << " ";
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一步倾川

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值