【C/C++ 数据结构】-八大排序之 选择排序&&堆排序

作者:学Java的冬瓜
博客主页☀冬瓜的主页🌙
专栏【C/C++数据结构与算法】
分享:理想主义者和玩世不恭的人都觉得对方可怜,可他们实际都很幸运。——刘慈欣《球状闪电》
主要内容:八大排序选择排序中的直接选择排序、堆排序

在这里插入图片描述
在这里插入图片描述

下面图是在螺稷山游玩时拍的:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、直接选择排序

1、思路

思路:最开始范围为0~size-1,先选出最大的和最小的数的下标把最大的和范围内开头begin下标的数交换。最小的和范围内末尾end下标的数交换然后begin++,end–,直到end和begin相遇。

2、复杂度

时间复杂度:O(n^2) ,按照上面的思路,第一次范围时为n,第二次为n-2…直到n-n或者n-1,所以,可以看出复杂度为O(n^2)

3、代码

// 选择排序1(优化版本)
void selectSort(int* arr, int size)
{
	// 1、begin和end控制范围
	int begin = 0;
	int end = size - 1;
	while (begin < end) {
		// 2、每次缩小范围找出范围内maxi和mini
		int maxi = begin;
		int mini = begin;
		for (int i = begin; i <= end; i++) {
			if (arr[maxi] < arr[i]) {
				maxi = i;
			}
			if (arr[mini] > arr[i]) {
				mini = i;
			}
		}
		 
		// 3、交换元素
		Swap(&arr[begin], &arr[mini]);// Swap是自己定义的交换函数
		// 注意:在begin和最小值交换时,如果同时begin是范围内最大值,那就修正maxi为交换后的下标mini
		if (maxi == begin) {
			maxi = mini;
		}
		Swap(&arr[end], &arr[maxi]);

		// 4、缩小范围
		begin++;
		end--;
	}
}
// 选择排序2(排完一趟,只选出一个极端值,放在开头。然后start(开始位置++))
void SelectSort(int* arr, int size)
{
	int cur_min_index = 0;
	for (int i = 0; i < size - 1; i++) {
		cur_min_index = i;
		for (int j = i + 1; j < size; j++) {
			if (arr[j] < arr[cur_min_index]) {
				cur_min_index = j;
			}
		}
		Swap(&arr[i], &arr[cur_min_index]);
	}
}

二、堆排序

1、思路

思路:
先把数组建成一个大堆=》升序,开始时,排序调整范围是0~size-1,此时end=size-1,然后把堆顶和堆尾元素交换,这个交换到末尾的元素就在升序中有序了,排序范围-1。再用向下调整算法,把剩余的范围再调成大堆,再把堆顶和堆尾交换,直到end = 0结束。
总的来看,就是把第一大,次大,再次大的数依次从数组末尾往前放,从而达到排序的效果。

2、复杂度

时间复杂度:O(nlogn) ,向下调整的复杂度尾log(n),最多调整n个元素;建堆的复杂度约为n,所以T(n) = nlog(n) + n => 约等于nlogn。
不清楚向下调整和建堆复杂度可以看以下这篇博客,这里就不再做过多赘述。【建堆和向下调整算法】

3、代码

@ 辅助代码

// 建堆
void heapCreate(int* arr, int size)
{
	for (int parent = (size - 1 - 1) / 2; parent >= 0; parent--) {
		shiftDown(parent, size, arr);
	}
}
// 向下调整算法(建堆时要用到)
void shiftDown(int parent, int size, int* arr)
{
	int child = parent * 2 + 1;
	while (child < size) {
		if (child + 1 < size && arr[child] < arr[child + 1]) {
			child++;
		}

		if (arr[child] > arr[parent]) {
			Swap(&arr[child], &arr[parent]); // Swap函数是自定义的交换函数

			parent = child;
			child = parent * 2 + 1;
		}
		else {
			break;
		}
	}
}

@ 堆排序代码

// 堆排序
void heapSort(int* arr, int size)
{
	// 1、建堆
	heapCreate(arr, size);
	// 2、用end划定范围
	int end = size - 1;
	while (end > 0) {
		// 3、交换堆顶和堆尾元素
		Swap(&arr[0], &arr[end]);

		// 4、把剩下的通过向下调整重新变成堆
		// 注意:此时,end由下标变为有效元素个数
		shiftDown(0, end, arr);

		// 5、范围-1
		end--;
	}
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

学Java的冬瓜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值