IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 【玩转九大排序①】插入排序 + 希尔排序(思想与算法实现) -> 正文阅读

[数据结构与算法]【玩转九大排序①】插入排序 + 希尔排序(思想与算法实现)

一、插入排序基本介绍

①基本思想

?插入排序的核心思想是:维护一个有序的区间。举个生活的例子,我们如何将一副凌乱的扑克牌从大到小有序排列呢?假设我们已经有一个有序区间 [3, 5, 6],现有一张大小为4的牌,显然我们应该插入到[3, 5]之间,但是计算机不能像人脑一样一看就知道,所以需要从大到小与我们手上已经有序的牌一一比较,进而得到我们应当插入的位置。
在这里插入图片描述

②代码呈现
void Insertsort(int* arr, int sz)
{
	for (int i = 1; i < sz; i++)  // (1)
	{
		int end = i;
		int tmp = arr[i];
		while (end)
		{
			if (tmp < arr[end - 1]) 
			{
				arr[end] = arr[end - 1]; //(2)
				end--;
			}
			else
				break;
		}
		arr[end] = tmp;  //(3)
	}
}

【代码细节剖析】

  1. 从i = 0时相当于只有一张牌,自然就是有序的,所以就从 i = 1开始遍历,即从第二张牌开始进行比较插入的过程
  2. arr[end] < arr[end - 1],所以end的位置应该由end - 1的数来占。往后覆盖后留出新的位置 end - 1。继续往后比较,知道找到应当插入的位置。
  3. 跳出循环的时候,即tmp > arr[end - 1],所以不用再往前比,end位置就是tmp要插入的位置。

【时间复杂度分析】
最坏情况为原序列逆序,时间复杂度为 O(N^2)
在这里插入图片描述
【10万数据量测试用时单位(ms)】

③错误代码辨析
void Insertsort(int* arr, int sz)
{
	for (int i = 1; i < sz; i++) 
	{
		int end = i;
		int tmp = arr[i];
		while (end)
		{
			if (tmp < arr[end - 1])
			{
				arr[end] = arr[end - 1];
				end--;
			}
			else
			{
				arr[end] = tmp;
				break;
			}
		}
	}
}

Q:可以将arr[end]的赋值放在while循环里面吗?
?不可以。看下面的有序数列【1, 2, 3】,插入数字0,显然我们要插在头部,但此时end = 0,循环结束,我们也就没有机会插入了。


二、希尔排序基本介绍

①基本思想

?希尔排序的基本思想仍然是插入排序的思想,但是通过一些方式来加快排序的速度。我们先来看这样一组序列 【6, 5, 4, 3, 2, 1】,显然在每一次插入的时候待插入的数据都要比较到头才截止,这可是致命的,如果待排序的数量级比较大,排序的速度就会很慢。所以,我们能不能尽可能的让大的数据更快的往后移动, 小的数据更快的往前移动呢?这就是希尔排序核心的问题。
?为了实现更快速的移动,我们不再是相邻的数据之间进行比较,而是隔位比较,当然交换也是隔位交换。
在这里插入图片描述
显然我们可以得出以下的关系(记间隔大小为gap):

  • gap越大,数据移动越快
  • gap越小, 数据更接近有序

?所以在插入排序的基础之上,我们只需增加 预排序" 的过程即可。即先进行有gap的预排序,使得大数尽快往后移动,小数尽快往前移动,最后再来一次gap为1的排序,实现数组的最终有序即可。
?你可能会有疑问,这样希尔排序的次数更多了,排序时间不会更长吗。我们最后拿测试数据说话。

②代码呈现
void Shellsort(int* arr, int sz)
{
	int gap = sz;
	while (gap > 1)
	{
		gap = gap / 3 + 1;             //(1)
		for (int i = gap; i < sz; i++) //(2)
		{
			int end = i;
			int tmp = arr[end];
			while (end >= gap)         //(3)
			{
				if (tmp < arr[end - gap])
				{
					arr[end] = arr[end - gap];
					end -= gap;
				}
				else
					break;
			}
			arr[end] = tmp;
		}
	}
}

【代码细节剖析】

  1. +1保证了gap = 1的情况一定会出现。gap > 1时进行预排序,gap = 1时进行标准的插入排序。我们就此巧妙的统一了预排序和标准排序的代码。
  2. 这里 i 的增长方式是+1,而不是加gap, 也就不必要写成双重循环了。
  3. 注意别写成while(end)了,这样会存在越界的风险。

【时间复杂度分析】
希尔排序的时间复杂度是最难算的,这里就不做数学推导:
平均时间复杂度:O(Nlog2N)
时间复杂度范围:(O(N^1.3) ~ O(N^2))
在这里插入图片描述
【10万数据量测试时间(单位ms)】
?从上面的数据我们可以看出,虽然希尔排序进行了多次的预排序,但是正是这些预排序使得原数据更加趋近于有序,从而极大的加快了排序的速度。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-04-23 11:02:21  更:2022-04-23 11:02:30 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 7:24:01-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码