「数据结构」八大排序1

🎇个人主页Ice_Sugar_7

🎇所属专栏初阶数据结构

🎇欢迎点赞收藏加关注哦!

文章目录

🍉插入排序

插排就是将一个元素插入一个有序序列中合适的位置,分为直接插入排序希尔排序

🍌直接插入排序

流程如下:
①保存待插入的值:假设某一趟中有序序列最后一个元素下标为end,先保存(end+1)位置的元素,保存到临时变量tmp。

②为a[end+1]找到合适的位置:使用while循环,里面比较a[end]和a[end+1]的大小。
若前者<后者,就退出循环
反之,则将a[end]往后挪一位,覆盖掉a[end+1],end减1,然后让tmp继续往前找,直到找到比它小的元素或者end < 0(end<0说明所有元素都比tmp大,那么就应该把tmp放在a[0]),插到该元素后面。

简而言之就是让tmp向前找比它小的元素,找到就插在它的后面;找不到就是插在第一位

③至此,我们排好了一个数据,现在要排列所有元素,只需在外面套上一层for循环
(假设数组有n个元素,注意循环的终止条件是i < n-1,即i最多只能取到n-2,因为是 i 和 i+1 进行比较)

比如:

c 复制代码
int a[] = {2,7,1,9,6,5,8};

图解如下:

代码如下:

c 复制代码
//n为数组元素个数
void InsertSort(int* a, int n) {
	for (int i = 0; i < n-1; i++) {
		int end = i;  //end为有序序列最后一个元素的下标
		int tmp = a[end + 1];  //tmp保存待插入的数据
		while (end >= 0)
		{
			if (a[end + 1] < a[end]) //待插入的数比end小,那么end就向后移动,给待插入的数据挪出位置
				a[end + 1] = a[end];
			else
				break;
			end--;  //更新end,向前找小 
		}
		//找到小或end == -1
		a[end + 1] = tmp;
	}
}

🥝复杂度及稳定性

时间复杂度:第一趟1次,第二趟2次......由等差数列公式可以推出是O(N^2)
空间复杂度:O(1)
稳定性:稳定


🍌希尔排序

希尔排序是直接插入排序的优化。分两步完成:预排序+直接插入排序
预排序的意义:让大的数更快到后面,小的数更快到前面。使序列趋于有序,降低直接插入排序的成本

🥝预排序

直接插入排序是让相邻的元素进行比较。预排序则是让一个元素和与它相隔几个位置的元素比较

比如:

c 复制代码
int a[] = {9,1,2,5,7,4,8,6,3,5};


9、5、8、5可以分为一组;1、7、6也是一组;2、4、3同理
同一组的元素进行比较,排好序。
预排序后得到:

这样就完成了一次预排序。希尔排序中有多次预排序,每次排完后会缩小间隔、重新分组,然后继续预排序。假设最开始的间隔为gap,那么就一直缩小,gap越小,预排序一次后序列就越趋于有序。直到gap为1,此时就是直接插入排序,这一次排好后序列就有序了

gap每次预排序一般是缩小到上一次的一半,或是1/3(注意gap除以3之后需要+1,保证gap不为0)
代码如下:

c 复制代码
void ShellSort(int* a, int n) {
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;  //+1确保gap至少为1,最后一次循环gap == 1
		//一次预排序
		for (int i = 0; i < n - gap; i++)  //i+gap最多取到n-1
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
					a[end+gap] = a[end];
				else
					break;
				end -= gap;
			}
			a[end + gap] = tmp;
		}
	}
}

🥝复杂度及稳定性

时间复杂度:O(N^1.3)
空间复杂度:O(1)
稳定性:不稳定。因为预排序很容易就把相同的数的相对顺序打乱了


🍉选择排序

排序思路:
●假设序列最左边、右边下标分别为begin、end
●从序列中找出最大、最小值,并分别将它们放到下标为begin、end的地方
●找出第二大和第二小,分别放到begin+1、end-1
●剩下元素也按照这样排列

在"交换位置"这一步有一个很坑的点,如果最小值刚好在end,那就会和最大值交换位置,但是此时我们的mini仍然在end,直接交换a[mini]和a[begin]就会把最大值和begin处的元素交换位置
所以 在最大值和a[end]交换之后检查一下,看mini是否在end处。如果是,就将maxi赋值给mini(因为此时maxi指向的就是最小值)

cpp 复制代码
void SelectSort(int* a, int n) {
	int begin = 0;
	int end = n - 1;
	while (begin < end)
	{
		int mini = begin,maxi = begin;
		for (int i = begin + 1; i <= end; i++)
		{
			if (a[maxi] < a[i])
				maxi = i;
			if (a[mini] > a[i])
				mini = i;
		}
		Swap(&a[maxi], &a[end]);
		if (end == mini)  //让mini重新指向最小值
			mini = maxi;
		Swap(&a[mini], &a[begin]);
		++begin;
		--end;
	}
}

🍌复杂度及稳定性

时间复杂度:第一趟走(n-2)次,第二趟走(n-4)次,第 i 趟走(n-2*i)次......由等差数列公式,可以得出时间复杂度为O(N^2)
空间复杂度:O(1)
稳定性:不稳定。比如1 9 9 4 2 1 3 6,第一趟第一个9就会被换到最后面


🍉堆排序

前面的文章有讲过,升序建大堆,降序建小堆
比如排升序,就建大堆,然后让堆顶元素和堆中最后一个元素交换位置,再进行调整

c 复制代码
void HeapSort(int* a, int k) {  //a为给定数组
	for (int i = (k - 1 - 1) / 2; i >= 0; i--) {   //调整为一个堆
		AdjustDown(a, k, i);
	}

	for (int i = k - 1; i >= 0; i--) {  //采用删除结点的思想,先交换,再调整
		Swap(a[0], a[i]);
		AdjustDown(a, i, 0);
	}
}

🍌复杂度及稳定性

时间复杂度:如果有n个数据,那么堆的深度就是logn,最坏情况下,有(n-1)个数据需要调整,所以近似是(n-1)logn,又因为logn的量级比n logn小,可以忽略,所以时间复杂度就是O(N*logN)
(注意:实际比N * logN略小一些)

上面说"近似"是因为并不是每个数据都要调整logn层,但是由于logn一般不大(参考:2的30次方是10亿多一点,此时logn就是30),它的大小一般就是几十这样子,所以相差这一点对于时间复杂度基本没影响

空间复杂度:O(1)
稳定性:不稳定


🍉写在最后

以上就是本篇文章的全部内容,如果你觉得本文对你有所帮助的话,那不妨点个小小的赞哦!(比心)

相关推荐
LNTON羚通1 小时前
摄像机视频分析软件下载LiteAIServer视频智能分析平台玩手机打电话检测算法技术的实现
算法·目标检测·音视频·监控·视频监控
哭泣的眼泪4082 小时前
解析粗糙度仪在工业制造及材料科学和建筑工程领域的重要性
python·算法·django·virtualenv·pygame
Microsoft Word3 小时前
c++基础语法
开发语言·c++·算法
天才在此3 小时前
汽车加油行驶问题-动态规划算法(已在洛谷AC)
算法·动态规划
莫叫石榴姐4 小时前
数据科学与SQL:组距分组分析 | 区间分布问题
大数据·人工智能·sql·深度学习·算法·机器学习·数据挖掘
茶猫_5 小时前
力扣面试题 - 25 二进制数转字符串
c语言·算法·leetcode·职场和发展
Hera_Yc.H6 小时前
数据结构之一:复杂度
数据结构
肥猪猪爸7 小时前
使用卡尔曼滤波器估计pybullet中的机器人位置
数据结构·人工智能·python·算法·机器人·卡尔曼滤波·pybullet
linux_carlos7 小时前
环形缓冲区
数据结构
readmancynn7 小时前
二分基本实现
数据结构·算法