深入了解数据结构第四弹——排序(1)——插入排序和希尔排序

这篇具有很好参考价值的文章主要介绍了深入了解数据结构第四弹——排序(1)——插入排序和希尔排序。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

从本篇开始,我们就开始进入排序的学习,在结束完二叉树的学习之后,相信我们对数据在内存中的存储结构有了新的认识,今天开始,我们将进入排序的学习,今天来学习第一篇——插入排序

目录

什么是插入排序?

一、直接插入排序

1、直接插入排序的实现

2、直接插入排序的时间复杂度

二、希尔排序

1、希尔排序的实现

2、希尔排序的时间复杂度

三、直接插入排序和希尔排序时间复杂度的比较

四、总结


首先,我们先来了解一下几种排序算法都有什么,方便我们后期学习,今天,我们先来讲解插入排序

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

什么是插入排序?

插入排序其实挺有意思,这种排序方法在我们生活中也挺常见,例如,当我们在打扑克的时候,当我们再次摸牌时,我们会将新牌按照大小顺序插入到旧牌中

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

插入排序实际上就是将一个数字按照大小顺序插入到已知的序列中去

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

一、直接插入排序

1、直接插入排序的实现

插入排序是从后往前比较的,例如

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

当我们对这样一个数组进行插入排序时,我们先将1放进去,然后再放进去2与1比较,再放进去4与前面的1和2比较,以此类推,每放进去一个数字与前面数字比较,所以插入排序的过程是需要遍历数组的,我们首先可以给一个end变量标记现在排好序的数组的末端位置,再给出一个tmp变量来表示要排序的数字

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

插入排序的代码如下:(降序)

void InsertSort(int* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		int end = i - 1;
		int tmp=a[i];
		while (end>=0)
		{
			if (tmp > a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

通过这段代码我们就可以看出插入排序的规则:当插入数据大于end位置的数据时,让end位置的数据向后移动一位,同时让end位置存放新插入的数据;当插入数据小于end位置数据时,那就直接让插入数据存放在end加1的位置就行

我们建立一个完整的代码示例并打印结果,给大家看看效果


//插入排序
void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
void InsertSort(int* a, int n)
{
	for (int i = 1; i < n; i++)
	{
		int end = i - 1;
		int tmp = a[i];
		while (end >= 0)
		{
			if (tmp > a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
			{
				break;
			}
		}
		a[end + 1] = tmp;
	}
}

void TestInsertSort()
{
	int a[] = { 1,2,4,7,8,2,5,3 };
	PrintArray(a, sizeof(a) / sizeof(a[0]));
	InsertSort(a, sizeof(a) / sizeof(a[0]));
	PrintArray(a, sizeof(a) / sizeof(a[0]));
}
int main()
{
	TestInsertSort();
	return 0;
}

运行结果:

第一行是排序前,第二行是排序后

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

2、直接插入排序的时间复杂度

时间复杂度最坏O(N^2)
时间复杂度最好O(N)

如图所示:

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

不同的两组数据在用直接插入排序降序时,左边时间复杂度明显小于右边

综上,其实综合来说直接插入排序的时间复杂度是介于O(N)O(N^2)之间的

二、希尔排序

1、希尔排序的实现

希尔排序是插入排序的改进,它通过将待排序的数据分割成若干个子序列来提高插入排序的效率。希尔排序的基本思想是:先将整个待排序的序列分割成若干个子序列,然后对这些子序列分别进行插入排序,最后再对整个序列进行一次插入排序。

希尔排序的具体步骤如下:

  1. 选择一个增量序列,通常是按照一定规则递减的序列,最常用的是取增量序列为n/2,n/4,n/8...1,后来经过改进,一般选择n/3+1来确保程序的稳定性
  2. 根据增量序列的值,将待排序序列分割成若干个子序列,对每个子序列进行插入排序。
  3. 逐渐缩小增量,重复第2步,直到增量为1。
  4. 最后对整个序列进行一次插入排序

例如:对于{9,8,7,6,5,4,3,2,1,0}这样一组数据,用希尔排序排升序的步骤如下:

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

实现上图功能的代码如下:

void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;    //+1可以保证最后一次一定为1
		
		for (int i = 0; i < n - gap; i++)      //每组插入排序
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}

这个过程跟插入排序相似度很高,可以将两者放在一起比较体会一下

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

希尔排序的完整代码示例:

void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
void ShellSort(int* a, int n)
{
	int gap = n;
	while (gap > 1)
	{
		gap = gap / 3 + 1;    //+1可以保证最后一次一定为1
		for (int i = 0; i < n - gap; i++)      //每组插入排序
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (a[end] > tmp)
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}
}
void TestShell()
{
	int a[] = { 9,8,7,6,5,4,3,2,1,0 };
	printf("排序前:");
	PrintArray(a, sizeof(a) / sizeof(0));
	ShellSort(a, sizeof(a) / sizeof(0));
	printf("排序后:");
	PrintArray(a, sizeof(a) / sizeof(0));
}
int main()
{
	TestShell();
	return 0;
}

运行结果:

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

2、希尔排序的时间复杂度

希尔排序的时间复杂度取决于增量序列的选择,一般情况下,希尔排序的时间复杂度为O(n log n)到O(n^2)之间。希尔排序是不稳定的排序算法,因为在排序过程中会改变相同元素之间的相对位置,所以希尔排序的时间复杂度其实并不能真正的计算出来,但希尔排序仍然要比直接排序要高效的多,我们可以通过一些方式来检验这种高效性

三、直接插入排序和希尔排序时间复杂度的比较

我们可以通过clock()函数来检验他们两个的时间复杂度

void TestOP()
{
	srand(time(0));
	const int N = 10000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);
	for (int i = 0; i < N; i++)       //让这两个算法都处理一万组数据,比较他们两个用时长短
	{
		a1[i] = rand();
		a2[i] = a1[i];
		a3[i] = a1[i];
	}
	int begin1 = clock();  
	InsertSort(a1, N);
	int end1 = clock();

	int begin2 = clock();
	ShellSort(a2, N);
	int end2 = clock();

	printf("InsertSort:%d\n", end1 - begin1);  //直接插入排序所用时间
	printf("ShellSort:%d\n", end2 - begin2);   //希尔排序所用时间
}

运行结果:

深入了解数据结构第四弹——排序(1)——插入排序和希尔排序,数据结构,算法,排序算法

四、总结

通过运行结果我们可以明显的观察到,在处理相同大小的一组数据时,希尔排序比直接插入排序要高效的多,且随着数据的增多,这种差异会愈加明显

以上就是插入排序的全部内容,鉴于篇幅问题,本篇文章讲解的有些粗糙,如果有不理解的地方,欢迎与我私信交流或者在评论区中指出!!!

感谢观看,创作不易,还请各位大佬点赞支持!!!文章来源地址https://www.toymoban.com/news/detail-848026.html

到了这里,关于深入了解数据结构第四弹——排序(1)——插入排序和希尔排序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数据结构】一文带你全面了解排序(下)——冒泡排序、快速排序、归并排序、计数排序

      目录 一、常见排序算法的实现   1.1 交换排序 1.1.1 基本思想 1.1.2 冒泡排序  1.1.3 快速排序 1.2 归并排序 1.3 非比较排序 二、排序算法复杂度及稳定性分析  人总得为过去的懒惰而付出点代价! 1.1.1 基本思想 基本思想:所谓交换,就是根据序列中两个记录键值的比较结

    2024年02月16日
    浏览(51)
  • 深入理解数据结构第六弹——排序(3)——归并排序

    排序1:深入了解数据结构第四弹——排序(1)——插入排序和希尔排序-CSDN博客 排序2:深入理解数据结构第五弹——排序(2)——快速排序-CSDN博客 前言: 在前面,我们已经学习了插入排序、堆排序、快速排序等一系列排序,今天我们来讲解一下另一个很高效的排序方法

    2024年04月17日
    浏览(61)
  • 深入理解数据结构第五弹——排序(2)——快速排序

    排序(1): 深入了解数据结构第四弹——排序(1)——插入排序和希尔排序-CSDN博客 前言: 在前面我们已经讲过了几种排序方式,他们的效率有快有慢,今天我们来学习一种非常高效的排序方式——快速排序 目录 一、快速排序的思想 二、快速排序的递归实现 2.1 霍尔法

    2024年04月15日
    浏览(48)
  • 【数据结构】一文带你全面了解排序(上)——直接插入排序、希尔排序、选择排序、堆排序

    目录 一、排序的概念及其运用 1.1 排序的概念 1.2 常见的算法排序 二、常见排序算法的实现 2.1 插入排序 2.1.1 思想 2.1.2 直接插入排序 2.1.3 希尔排序(缩小增量排序)  2.2 选择排序 2.2.1 基本思想 2.2.2 直接选择排序 2.2.3 堆排序  没有坚持的努力实质上并没有太大的意义

    2024年02月16日
    浏览(55)
  • 深入了解队列:探索FIFO数据结构及队列

    之前介绍了栈:探索栈数据结构:深入了解其实用与实现(c语言实现栈) 那就快马加鞭来进行队列内容的梳理。队列和栈有着截然不同的工作方式,队列遵循先进先出(FIFO)的原则,在许多场景下都表现出强大的效率和实用性 源码可以来我的github进行查找:Nerosts/just-a-tr

    2024年02月03日
    浏览(42)
  • [数据结构 -- 手撕排序第二篇] 一篇带你详细了解希尔排序

    目录 1、常见排序算法 1.1 插入排序基本思想 2、希尔排序 2.1 希尔排序( 缩小增量排序 ) 2.1.1 预排序阶段 2.1.2 插入排序阶段 2.2 单趟希尔排序 2.2.1 思路分析 2.2.2 代码实现 3、希尔排序代码实现 4、希尔排序时间复杂度 5、希尔排序与插入排序效率对比 6、希尔排序特性总结 直接

    2024年02月13日
    浏览(59)
  • 数据结构--》深入了解栈和队列,让算法更加高效

            本文将带你深入了解数据结构栈和队列,这两种基础的线性数据结构在算法中的重要性不言而喻。我们将会详细介绍栈和队列的概念、分类、实现以及应用场景,在理解栈和队列的基础上,还将探讨如何通过栈和队列来高效地解决算法问题。         无论你是

    2024年02月10日
    浏览(40)
  • 【数据结构】---堆排序+TOP-K问题(了解游戏排行底层原理)

    👧个人主页:@小沈熬夜秃头中୧⍤⃝❅ 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:数据结构 🔑本章内容:堆排序+TOP-K问题 送给各位💌:日落跌入昭昭星野 人间忽晚 山河以秋 记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~ 提示:以下是本篇文章正文内容,下面

    2024年02月06日
    浏览(48)
  • C/C++数据结构之深入了解树与二叉树:概念、存储结构和遍历

    树是一种常见的数据结构,它在计算机科学和数学中都有广泛的应用。树结构的最简单形式是二叉树,本文将深入探讨树和二叉树的概念、存储结构以及二叉树的遍历,并提供一些实际的代码示例来帮助理解这些概念。 树 (Tree) 树是一种层次性数据结构,由节点(或称为顶点

    2024年02月06日
    浏览(51)
  • 数据结构第十四弹---链式二叉树基本操作(下)

    如何翻转一颗二叉树?首先我们可以先观察一下翻转前后的变化。如下图。 画图分析 通过观察,可以发现:翻转后,根的左右子树的位置交换了;根的孩子的左右子树的位置也交换了;根的孩子的孩子的左右子树的位置也交换了… 思路: 1、翻转左子树 2、翻转右子树 3、交

    2024年01月20日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包