【数据结构】排序之插入排序

news2024/11/26 1:27:31

排序目录

  • 1.前言
  • 2. 排序的概念及其运用
    • 2.1 排序的概念
    • 2.2 排序的运用
    • 2.3 常见的排序算法
  • 3. 插入排序
    • 3.1 基本思想
    • 3.2 直接插入排序
      • 3.2.1 直接插入排序实现
        • 3.2.1.1 分析
        • 3.2.1.2 代码实现
    • 3.3 希尔排序
      • 3.3.1 希尔排序实现
        • 3.3.1.1 分析
        • 3.3.1.2 代码实现
  • 4. 附代码
    • 4.1 sort.h
    • 4.2 sort.c
    • 4.3 test.c

1.前言

在生活中处处可见排序,当我们打开京东或者其它购物平台时,搜索物品,它会有一定的排序。
这次就来分享的博客与排序有关。
正文开始。

2. 排序的概念及其运用

2.1 排序的概念

排序:所谓排序,就是使一串记录,按照其中的某个或某些关键字的大小,递增或递减的排列起来的操作。

稳定性:假定在待排序的记录序列中,存在多个具有相同的关键字的记录,若经过排序,这些记录的相对次序保持不变,即在原序列中,r[i]=r[j],且r[i]在r[j]之前,而在排序后的序列中,r[i]仍在r[j]之前,则称这种排序算法是稳定的;否则称为不稳定的。

内部排序:数据元素全部放在内存中的排序。
外部排序:数据元素太多不能同时放在内存中,根据排序过程的要求不能在内外存之间移动数据的排序。

2.2 排序的运用

举个例子:
在京东上平板的统合排名:
在这里插入图片描述
来看看高校的排名:
在这里插入图片描述
可能每个人搜出来的不一样。

2.3 常见的排序算法

在这里插入图片描述

3. 插入排序

3.1 基本思想

直接插入排序是一种简单的插入排序法,其基本思想是:把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。
就像是在玩扑克牌时候,对刚拿的牌来进行一个插入。
在这里插入图片描述

3.2 直接插入排序

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

直接看动图:
在这里插入图片描述
直接插入排序的特性总结:

  1. 元素集合越接近有序,直接插入排序算法的时间效率越高
  2. 时间复杂度:O(N^2)
  3. 空间复杂度:O(1),它是一种稳定的排序算法
  4. 稳定性:稳定

3.2.1 直接插入排序实现

以升序为例子

3.2.1.1 分析

就是把没排好的数插入到已经排好的数中,实现有序。
实现排序,先实现单趟。
假设在一个已经排好序的区间[0,end],然后把end+1位置的值插入进去,那怎么插入呢?
从后往前,依次比较,如果比end+1大,那就往后挪,把位置空出来,再把值放进去。为了记录插入的数据,用一个临时变量tmp存储 end+1的值,避免被覆盖。

在这里插入图片描述
假设前面的已经[0,end],也就是3,4,9已经排好。这时要插入6,先记录一下tmp=6,然后依次往前比较,如果比tmp大,那就往后挪。
在这里插入图片描述
还有一种情况:
一直往走,往后挪数据,当end<0时结束。
在这里插入图片描述
所以这里循环的条件就是while (end >= 0)
如果tmp < a[end],就实现a[end + 1] = a[end],然后end1--
循环结束就有两种情况:一种是tmp>=end,tmp就得放在end后面。另一种是:在while条件结束,出现end<0。
在这里插入图片描述
单趟的已经实现,那怎么实现整体?
while循环外面再套一层循环。
第一个数据就是[0,0],再往下是[0,1],2位置的往前插入。那么它的结束位置就是n-1,不能是n,因为如果到n,那么tmp位置访问n+1,已经越界了。

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

		a[end + 1] = tmp;
	}
}

来看看结果:
在这里插入图片描述

3.3 希尔排序

希尔排序法又称缩小增量法。希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,取,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
在这里插入图片描述
希尔排序的特性总结:

  1. 希尔排序是对直接插入排序的优化。
  2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。
  3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些书中给出的希尔排序的时间复杂度都不固定:
  4. 稳定性:不稳定

3.3.1 希尔排序实现

希尔排序分为两部分:第一部分是预排序,第二部分是直接插入排序。

3.3.1.1 分析

预排序的目的是让数组基本有序,这样直接插入就很快。
举个例子:gap=3
将间隔为3的分为一组,那么总的就分为了三组。红的一组,蓝的一组,绿的一组。
在这里插入图片描述
那么它的预排序怎么实现呢?
就是将分的这三组,分别进行插入排序。
首先将9当成已经排好的数据,那么下一个不是8,而是间隔为3的6,把6往前插入,然后继续找下一个就是4,继续往前面插入。
最后就是这样;
在这里插入图片描述
剩下的两组也是一样的,最终排出来就是
在这里插入图片描述
这里只是接近有序。

就是把上面的直接插入排序的tmp换成end + gap位置的就行。
在这里插入图片描述
假设先对红色这组经行排序,那就是:
在这里插入图片描述
注意循环的条件如果是i<n,那么就会访问越界,注意看图上,发现结束的位置就是n-gap。
如果排实现的两组,那么就直接再套一层,循环gap=3次就排完了。
在这里插入图片描述
这里套了三层排序,也只是预排序,j为0就是红色的一组,j为1就是蓝色那组,j为2就是绿色那一组。
在这里插入图片描述
优化一下,实现多组并排,之间是一组一组往后排,现在是直接在gap组之间来回跳,第一次排红色,第二次排蓝色,第三次排绿色。
少一层循环。
在这里插入图片描述
gap怎么选择:
在这里插入图片描述

《数据结构(C语言版)》— 严蔚敏
在这里插入图片描述

《数据结构-用面相对象方法与C++描述》— 殷人昆
在这里插入图片描述

在这里插入图片描述
所以这里实现希尔排序,就是将gap不断变小,
gap > 1时是预排序,目的让他接近有序,而gap == 1是直接插入排序,目的是让他有序。
那么这里gap怎么选择呢?
如果gap = gap / 2,这里跳跃就比较小,所以选择gap = gap / 3 ,但为了保证最后一次为1,这里就得加1,也就是gap = gap / 3 + 1。
在这里插入图片描述
来看看结果:
在这里插入图片描述

3.3.1.2 代码实现
void ShellSort(int* a, int n)
{
	int gap = n;
	// gap > 1时是预排序,目的让他接近有序
	// gap == 1是直接插入排序,目的是让他有序
	while (gap > 1)
	{
		//gap = gap / 2;
		gap = gap / 3 + 1;

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

4. 附代码

4.1 sort.h

#pragma once
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>

void PrintArray(int* a, int n);
void InsertSort(int* a, int n);
void ShellSort(int* a, int n);

4.2 sort.c

#include"Sort.h"

void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}

// 时间复杂度:O(N^2) 逆序
// 最好的情况:O(N)  顺序有序
void InsertSort(int* a, int n)
{
	// [0, end] end+1
	for (int i = 0; i < n - 1; ++i)
	{
		int end =i;
		int tmp = a[end + 1];
		while (end >= 0)
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				--end;
			}
			else
			{
				break;
			}
		}

		a[end + 1] = tmp;
	}
}


// 平均O(N^1.3)
void ShellSort(int* a, int n)
{
	int gap = n;

	// gap > 1时是预排序,目的让他接近有序
	// gap == 1是直接插入排序,目的是让他有序
	while (gap > 1)
	{
		//gap = gap / 2;
		gap = gap / 3 + 1;

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


	/*for (int j = 0; j < gap; ++j)
	{
		for (int i = j; i < n-gap; i += gap)
		{
			int end = i;
			int tmp = a[end + gap];
			while (end >= 0)
			{
				if (tmp < a[end])
				{
					a[end + gap] = a[end];
					end -= gap;
				}
				else
				{
					break;
				}
			}
			a[end + gap] = tmp;
		}
	}*/
}

4.3 test.c

#include"Sort.h"

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

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

在之后的博客中会继续分享与排序有关的内容,请多多关注。
有问题请指出,大家一起进步!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【第七在线】为什么智能商品管理是对传统商品管理模式的颠覆?

智能商品管理确实在一定程度上颠覆了传统的商品管理模式。传统商品管理通常依赖于人工的经验和决策&#xff0c;而智能商品管理则利用人工智能和相关技术来提供更智能化和高效化的解决方案。 智能商品管理通过数据分析和预测能力&#xff0c;可以更准确地预测市场需求和销售趋…

AI智能分析网关V4区域人数超员算法模型的应用原理及使用场景

视频AI智能分析技术已经深入到人类生活的各个角落&#xff0c;与社会发展的方方面面紧密相连。从日常生活中的各种场景&#xff0c;如人脸识别、车牌识别&#xff0c;到工业生产中的安全监控&#xff0c;如工厂园区的翻越围栏识别、入侵识别、工地的安全帽识别、车间流水线产品…

医院绩效考核系统源码,java源码,商业级医院绩效核算系统源码

医院绩效定义&#xff1a; “医院工作量绩效方案”是一套以工作量&#xff08;RBRVS&#xff0c;相对价值比率&#xff09;为核算基础&#xff0c;以工作岗位、技术含量、风险程度、服务数量等业绩为主要依据&#xff0c;以工作效率和效益、工作质量、患者满意度等指标为综合考…

D9741 PWM控制器电路,定时闩锁、短路保护电路,输出基准电压(2.5V) 采用SOP16封装

D9741是一块脉宽调制方三用于也收路像机和笔记本电的等设备上的直流转换器。在便携式的仪器设备上。 主要特点&#xff1a;● 高精度基准电路 ● 定时闩锁、短路保护电路 ● 低电压输入时误操作保护电路 ● 输出基准电…

MAC运行Windows专用软件 CrossOver v23.7.1中文版 macOS

CrossOver v23.7.1中文版是一款系统兼容软件&#xff0c;让您可以在 Mac 和 Linux 系统上运行 Windows 应用&#xff0c;不必购买 Windows 授权&#xff0c;不必重启系统&#xff0c;不必使用虚拟机。通过 CrossOver&#xff0c; 您可以从 dock 直接启动 Windows 应用&#xff…

WEB 3D技术 three.js 色彩空间讲解

上文 WEB 3D技术 three.js 设置环境贴图 高光贴图 场景设置 光照贴图 我们讲了基础材质的各种纹理 但是 我们的图片 到了界面场景中 好像绿的程度有点不太一样了 这里的话 涉及到我们的色彩空间 他有两种 一种是线性的 一种是 sRGB类型的 线性呢 就是根据光照强度 去均匀分…

nodejs+vue+ElementUi农产品团购销售系统zto2c

目标是为了完成小区团购平台的设计和实现&#xff0c;在疫情当下的环境&#xff0c;方便小区业主购入生活所需&#xff0c;减小居民的生活压力 采用B/S模式架构系统&#xff0c;开发简单&#xff0c;只需要连接网络即可登录本系统&#xff0c;不需要安装任何客户端。开发工具采…

OrientDB使用教程:全面了解图数据库

图数据库在当今数据处理领域中扮演着越来越重要的角色&#xff0c;而OrientDB作为一种多模型的数据库&#xff0c;具有图数据库、文档数据库和对象数据库的特性&#xff0c;为应对不同场景提供了灵活的解决方案。本教程将简要介绍OrientDB的使用&#xff0c;包括基本概念、安装…

3-链表-删除链表的倒数第 N 个结点

这是链表的第三篇算法&#xff0c;力扣链接。 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]示例 2&#xff1a; 输入&#xff1a;head [1],…

为什么TCP会粘包

硬核图解|tcp为什么会粘包&#xff1f;背后的原因让人暖心 数据包报文格式&#xff08;IP包、TCP报头、UDP报头&#xff09; TCP&#xff0c;Transmission Control Protocol。传输控制协议&#xff0c;是一种面向连接的、可靠的、基于字节流的传输层通信协议。 TCP粘包是指发…

vue2中使用百度地图BMapGL

1、npm 命令安装 npm install vue-bmap-gl --save2、main.js 中文件引入 import VueBMap from vue-bmap-gl import vue-bmap-gl/dist/style.css VueBMap.initBMapApiLoader({// 百度的keyak:*********,// 这个密钥请使用自己注册的 }) Vue.use(VueBMap)3、页面调用 <temp…

一篇文章带你入门PHP魔术方法

PHP魔术方法 PHP 中的"魔术方法"是一组特殊的方法&#xff0c;它们在特定情况下自动被调用。这些方法的名称都是以两个下划线&#xff08;__&#xff09;开头。魔术方法提供了一种方式来执行各种高级编程技巧&#xff0c;使得对象的行为可以更加灵活和强大。以下是一…

SourceTree的安装和使用

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、安装&#xff1a;二、使用步骤1.获取地址2.放入sourceTree 3.点击推送 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 简单讲解一…

F12开发者工具如何找到对应接口

Web问题定位 1、进入 NetWork页面2、点击Fetch/XHR&#xff0c;这里可以看到页面发起的接口3、找到出问题的接口4、NetWork页面怎么看接口详情5、问题定位 最常用的定位前后端问题的方法。即&#xff1a;一般用来查看是后端返回给前端的数据有误&#xff0c;还是前端显示有误。…

【27.5K⭐】Spacedrive:功能强大且便捷的跨平台文件管理器

【27.5K⭐】Spacedrive&#xff1a;功能强大且便捷的跨平台文件管理器 在日常生活和工作中&#xff0c;我们经常需要使用不同的设备和云存储服务来存储和管理我们的文件。然而&#xff0c;这样做往往会导致文件的分散、重复和混乱&#xff0c;给我们带来不便和困扰。那么&…

免费在线客服软件推荐:经济实用的客户沟通解决方案

好用的在线客服软件是企业是必不可少的工具&#xff0c;他让企业流程更流畅高效&#xff0c;让客户服务更完善优质。市场上的在线客服软件有很多&#xff0c;说着免费使用的软件也不在少数。今天小编就来推荐一款免费在线客服软件。 不过&#xff0c;我们选择免费在线客服软件…

如何让python在手机上运行,python程序在手机上运行

大家好&#xff0c;给大家分享一下python怎么在手机上运行爱心代码&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01; 1. 写在前面的话 天天都在PC端运行Python代码的我&#xff0c;今天突然灵光一现&#xff0c;想着是不是能够在移动端运行P…

R503S指纹识别模块的指令系统(一)

1.采集指纹图像 GetImage&#xff08;0x01&#xff09; 功能说明&#xff1a;探测手指&#xff0c;探测到后录入指纹图像存于 ImageBuffer&#xff0c;并返回录入成功确认码&#xff1b;若探测不到手指&#xff0c;直接返回无手指确认码(模块对于每一条指令都快速反应&#xf…

day3双指针

输入一字符串&#xff0c;然后将该字符串中的单词分割开来 #include <iostream> #include <string.h> using namespace std; int main() {char str[1000];gets(str);int nstrlen(str);for(int i0;i<n;i){int ji;while(str[j]! &&j<n) j;for(int ki;k…

从零开始部署CTF题目环境(docker容器)

本教程将教会大家如何安装一台可以部署docker容器形式的CTF题目的CentOS服务器。 操作步骤 1-下载操作系统镜像文件 虚拟操作系统&#xff1a;CentOS 8 &#xff08;CentOS 9 毛病多&#xff0c;先不装&#xff09; 镜像文件下载地址&#xff0c;点击X86_64即可 CentOS St…