算法之插入排序及希尔排序(C语言版)

我们来实现上述排序

一.插入排序.

当插入第i(i>=1)个元素时,前面的array[0],array[1],.,array[i-1]已经排好序,此时用array[i的排序码与array[i-1]array[i-2].的排序码顺序进行比较,找到插入位置即将arrayU插入,原来位置上的元素顺序后移.

CSDN这个链接有我之前写的直接插入排序

今天我们来实现广义上的插入排序:

我直接写出来,会在里面写注释

void Insertsort(int* arr, int n)//arr数组,n元素个数
{
	//我们用升序排列
	for (int i = 0; i < n-1; i++)//循环n次
	{
		int end = i;//将i的值赋给end,方便将其数值改变而不影响循环
		int tmp = arr[end + 1];//由于升序,我们要提前保存要排序的数
		//这里默认前i个数是已排好的,即end
		while (end >= 0)
		{
			if (arr[end] > tmp)//arr[end]与arr[end+1]比较
			{
				arr[end + 1] = arr[end];//满足条件赋值
				end--;//继续向前排列
			}
			else
			{
				break;//不满足条件退出循环
			}
		}
		arr[end + 1] = tmp;//将保存的数值赋给留出的位置
	}
}

我们排一个数组试试:
 

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void Insertsort(int* arr, int n)//arr数组,n元素个数
{
	//我们用升序排列
	for (int i = 0; i < n-1; i++)//循环n次
	{
		int end = i;//将i的值赋给end,方便将其数值改变而不影响循环
		int tmp = arr[end + 1];//由于升序,我们要提前保存要排序的数
		//这里默认前i个数是已排好的,即end
		while (end >= 0)
		{
			if (arr[end] > tmp)//arr[end]与arr[end+1]比较
			{
				arr[end + 1] = arr[end];//满足条件赋值
				end--;//继续向前排列
			}
			else
			{
				break;//不满足条件退出循环
			}
		}
		arr[end + 1] = tmp;//将保存的数值赋给留出的位置
	}
}
void Print(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[] = { 2,4,6,8,0,1,3,5,7,9 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Insertsort(arr, sz);
	Print(arr, sz);

}

结果:

当然我们也可以用降序来排:

void Insertsort(int* arr, int n)//arr数组,n元素个数
{
	//我们用升序排列
	for (int i = 0; i < n-1; i++)//循环n次
	{
		int end = i;//将i的值赋给end,方便将其数值改变而不影响循环
		int tmp = arr[end + 1];//由于升序,我们要提前保存要排序的数
		//这里默认前i个数是已排好的,即end
		while (end >= 0)
		{
			if (arr[end] < tmp)//arr[end]与arr[end+1]比较,改变<,>符号即可
			{
				arr[end + 1] = arr[end];//满足条件赋值
				end--;//继续向前排列
			}
			else
			{
				break;//不满足条件退出循环
			}
		}
		arr[end + 1] = tmp;//将保存的数值赋给留出的位置
	}
}

上题数组的结果(用降序排列):

我们接下来看看其时间复杂度:

我们只考虑最坏的情况:

假设 n=1:外层1次,内层1次

        n=2:外层2次,内层最坏2次

        n=3:外层3次,内层最坏3次

        n=n:外层n次,内层最坏n次

因此时间复杂度为:O(N*N)=O(N^2);

二.插入排序进阶----希尔排序.

又叫递减增量排序算法。

思想:先将整个待排元素序列分割成若干个子序列(由相隔某个“增量”的元素组成的)分别进行直接插入排序,然后依次缩减增量再进行排序,待整个序列中的元素基本有序(增量足够小)时,再对全体元素进行一次直接插入排序

希尔排序主要分两步:1.预排序  2.插入排序

预排序:分组排间隔为gap是一组。

假设gap == 5

对组间隔为gap的预排序,gap由大变小,gap越大,大的数可以越快的到后面,小的数可以越快的到前面,gap越大,预排完越不接近有序
gap越小,越接近有序,gap == 1时就是直接插入排序

我们直接实现,在插入排序上改:

void Shellsort(int* arr, int n)
{
	int gap = n;//将n的值赋值一份给gap,便于后续对gap给值划分
	while (gap > 1)
	{
		//法一:gap/2为单位
		gap = gap / 2;//gap的值以二分之一不断划分,最后得到gap=1进行插入排序
		//gap/3为单位
		//gap = gap / 3 + 1;//gap的值以三分之一不断划分,最后加+1得到gap=1进行插入排序
		//gap>1时进行预排序
		//gap=1时进行插入排序
		for (int i = 0; i < n - gap; i++)//i<n-gap:把间隔为gap的多组数据同时排
		{
			//下面操作和插入排序大体相同,但注意不再时加减1;而是以gap为单位!!!
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}

继续实现上面那个数组的排序:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void Shellsort(int* arr, int n)
{
	int gap = n;//将n的值赋值一份给gap,便于后续对gap给值划分
	while (gap > 1)
	{
		//法一:gap/2为单位
		gap = gap / 2;//gap的值以二分之一不断划分,最后得到gap=1进行插入排序
		//gap/3为单位
		//gap = gap / 3 + 1;//gap的值以三分之一不断划分,最后加+1得到gap=1进行插入排序
		//gap>1时进行预排序
		//gap=1时进行插入排序
		for (int i = 0; i < n - gap; i++)//i<n-gap:把间隔为gap的多组数据同时排
		{
			//下面操作和插入排序大体相同,但注意不再时加减1;而是以gap为单位!!!
			int end = i;
			int tmp = arr[end + gap];
			while (end >= 0)
			{
				if (arr[end] > tmp)
				{
					arr[end + gap] = arr[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			arr[end + gap] = tmp;
		}
	}
}
void Print(int* arr, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", arr[i]);
	}
}
int main()
{
	int arr[] = { 2,4,6,8,0,1,3,5,7,9 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	Shellsort(arr, sz);
	Print(arr, sz);

}

结果:

上面这是升序的,相信降序的大家都会了。没错,和插入排序改变之处相同。

接下来我们讨论其时间复杂度:

gap = gap / 2;// logN
//gap = gap / 3 + 1;// 1og3N 以3为底数的对数
for (int i = 0; i < n - gap; i++)
{
	// gap > 1时都是预排序 接近有序
	// gap == 1时就是直接插入排序 有序
	// gap很大时,下面预排序时间复杂度0(N)
	// // gap很小时,数组已经很接近有序了,这时差不多也是(N)
	int end = i;
	int tmp = arr[end + gap];
	while (end >= 0)
	{
		if (arr[end] > tmp)
		{
			arr[end + gap] = arr[end];
			end -= gap;
		}
		else
		{
			break;
		}
	}
	arr[end + gap] = tmp;
}

因此,其时间复杂度为:O(N*logN),平均的时间复杂度是0(N*1.3)

读者可能会想这个希尔排序是三层循环,而插入排序才两层循环,不可能出现其算法更优越啊!

但实际上,确实是希尔排序快,而且快了不止一点。

假设用10万个数据,我们对比发现希尔排序要少排非常多次。

InsertSort:1616ms
ShellSort:12ms

这是一个相同数据检测出来两者的时间差距,可见两者的差距有多大,希尔牛逼!

希尔排序缺点:

希尔排序并不只是相邻元素的比较,有许多跳跃式的比较,难免会出现相同元素之间的相对位置发生变化,所以希尔排序是不稳定的算法。

最后,我会不间断的更新其他排序,希望大家多多支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/196574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【RTP】4: 实例解析:一个SRTP的wireshark抓包:带padding、带扩展

抓取的是视频包。固定的pt是127从头部找到序号,快速找到这个包包大小因为是包括了SRTP的,所以318 个字节,实际RTP包是286个字节。SRTP 包 UDP总共 294个字节,payload部分286 RTP协议 RTP部分: B0 代表有padding、有扩展 从B0开始

【Linux】gcc和g++

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和Linux还有算法 ✈️专栏&#xff1a;Linux &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵&#xff0c;希望大佬指点一二 …

linux shell操作 - 05 进程 与 IO 模型

文章目录 计算机内存分配进程与子进程流IO模型非阻塞IOIO多路复用网络IO模型简单的socket并发的socket 计算机内存分配 一个32位&#xff0c;4G内存的计算机&#xff0c;内存使用分为两部分&#xff1a; 操作系统内核空间&#xff1b;应用程序的用户空间使用的操作系统不同&a…

如何使用低代码平台加速应用开发?

目录 一、背景 二、低代码开发和传统开发的区别 1.低代码开发方式能够实现业务应用的快速交付 2.低代码开发平台还能够降低业务应用的开发成本 三、低代码开发对你有什么帮助&#xff1f; 四、低代码工具的使用者是谁&#xff1f; 五、典型的低代码开发平台有哪些&#xff1f…

02-鸿蒙学习之4.0todoList练习

02-鸿蒙学习之4.0todoList练习 代码 /*** 1:组件必须使用Component装饰* 2.Entry 装饰哪个组件&#xff0c;哪个组件就呈现在页面上* 3.被Entry 装饰的入口组件。build&#xff08;&#xff09;必须有且仅有一个根 ** 容器 ** 组件* 其他的自定义组件&#xff0c;build() 中…

一篇总结 Linux 系统启动的几个汇编指令

学习 Linux 系统启动流程&#xff0c;必须熟悉几个汇编指令&#xff0c;总结给大家。 这里不是最全的&#xff0c;只列出一些最常用的汇编指令。 一&#xff0e;数据处理指令 1.数据传送指令 【MOV指令】 把一个寄存器的值(立即数)赋给另一个寄存器&#xff0c;或者将一个…

spring boot 整合 spring security

项目结构 添加依赖 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.9.RELEASE</version><relativePath/></parent><dependency><grou…

leetcode刷题详解十

188. 买卖股票的最佳时机 IV&#xff08;最多买卖k次&#xff09; 注意事项 这道题和最多买卖两次是一模一样的思路就是把2换成k了但是还是有几个地方需要注意的 给的整数数组可能为0k其实没有很大&#xff0c;可以想一下&#xff0c;最多为n/2(n是数组的长度) int maxProfit…

大型网站系统架构演化(Web)

大型网站系统架构演化 大型网站系统架构演化需要关注的维度涉及的技术演进过程单体架构垂直架构使用缓存改善网站性能缓存与数据库的数据一致性问题缓存技术对比Redis分布式存储方案Redis集群切片的常见方式Redis数据类型Redis 淘汰算法 大型网站系统架构演化 需要关注的维度 …

2024年最受欢迎的项目管理工具盘点

十大项目管理系统包括&#xff1a;1.产品研发项目管理工具&#xff1a;PingCode&#xff1b;2.通用项目协作工具&#xff1a;Worktile&#xff1b;3.开源项目管理系统&#xff1a;Redmine&#xff1b;4.IT/敏捷项目管理系统&#xff1a;Jira&#xff1b;5.免费个人项目管理&…

NX二次开发UF_CURVE_create_arc_point_point_radius 函数介绍

文章作者&#xff1a;里海 来源网站&#xff1a;https://blog.csdn.net/WangPaiFeiXingYuan UF_CURVE_create_arc_point_point_radius Defined in: uf_curve.h int UF_CURVE_create_arc_point_point_radius(tag_t point1, tag_t point2, double radius, UF_CURVE_limit_p_t l…

问答社区运营的核心是什么?

问答社区是用户在平台上获得信息的一种方式&#xff0c;一般问答社区适用于医疗行业&#xff0c;法律行业等专业领域的行业&#xff0c;可以划分为知识型分享社区的一种&#xff0c;用户提供提问&#xff0c;邀请回答&#xff0c;选择最佳回复&#xff0c;设置问题围观&#xf…

字符串逆序问题

写一个函数&#xff0c;可以将任意输入的字符串逆序&#xff08;要可以满足多组输入&#xff09; 这个题有三个点 1.要读入键盘输入的字符串&#xff0c;所以要用到字符串输入函数 2.可以进行多组输入 3.把输入的n组字符串都逆序 #define _CRT_SECURE_NO_WARNINGS 1 #incl…

Portraiture2024最新Photoshop磨皮插件更新啦

Portraiture是一款由Imagenomic公司研发的Photoshop磨皮插件。该插件以其优秀的磨皮效果&#xff0c;成为了众多摄影师和化妆师使用的首选插件。Portraiture主要用于影楼、婚纱、时尚摄影等各个领域。其主要特点是能够轻松地模拟人眼的视觉感受&#xff0c;自然地修饰人像照片。…

【Linux专题】http(s)代理

【赠送】IT技术视频教程&#xff0c;白拿不谢&#xff01;思科、华为、红帽、数据库、云计算等等_厦门微思网络的博客-CSDN博客文章浏览阅读444次。风和日丽&#xff0c;小微给你送福利~如果你是小微的老粉&#xff0c;这里有一份粉丝福利待领取...如果你是新粉关注到了小微&am…

元宇宙的八个关键技术介绍!

人工智能&#xff08;AI&#xff09;、物联网、增强现实、虚拟现实、区块链、NFT、3D建模、空间和边缘计算等技术使最元宇宙开发成为可能。本文对元宇宙的8个关键技术进行了介绍。 人工智能 人工智能技术中的目标分割、目标追踪、姿态估计等是元宇宙场景中感知现实的关键工具&…

【笔记】小白学习电路维修

学习视频&#xff08;b站&#xff09;&#xff1a;从0开始学电路 从0开始学电路维修 p1 黄色长方体元件P2 故障率最高的元件p3带芯铜丝线圈是什么区分电感和变压器接入电路分析&#xff1a; p4 交流和直流分界线整流桥接线整流桥故障判断 带色环的不一定是电阻 p1 黄色长方体元…

51单片机项目(16)——基于51单片机的水箱冷却系统

1.项目背景 汽车水箱又称散热器&#xff0c;是汽车冷却系统中主要机件&#xff1b;其功用是散发热量&#xff0c;冷却水在水套中吸收热量&#xff0c;流到散热器后将热量散去&#xff0c;再回到水套内而循环不断。从而达到散热调温的效果。它还是汽车发动机的重要组成部分。 汽…

解决ssh使用public key远程登录服务器拒绝问题

目录 使用场景windows安装ssh客户端使用powershell ssh登录服务器生成密钥文件ubuntu ssh服务器配置使用vscode远程登录使用Xshell远程登录使用MobaXtem远程登录Server refused our key问题解决方案 使用场景 使用vscode远程ssh登录使用public key不需要输入密码,比较方便. w…

Java 之 lambda 表达式(一)

目录 一. 前言 二. lambda 表达式语法 2.1. 语法1&#xff1a;无参&#xff0c;无返回值 2.2. 语法2&#xff1a;一个参数&#xff0c;无返回值 2.3. 语法3&#xff1a;两个参数&#xff0c;lambda 体中有多条语句 2.4. 语法4&#xff1a;两个以上参数&#xff0c;有返回…