元旦特辑:Note5---插入排序


目录

前言🪩

1. 排序的概念+运用🟣

1.1 排序的概念🟪

1.2 排序的运用💜

2. 直接插入排序🟢

2.1 基本思想🟩

2.2 思路分析💚

2.3 代码实现✅

2.3.1 sort.h

2.3.2 sort.c

2.3.3 test.c

2.4 特性总结❇️

3. 希尔排序🟠

3.1 基本思想🟧

3.2 思路分析🔶

3.3 预排序实现🧡

3.3.1 sort.h

3.3.2 sort.c

3.3.3 优化

3.3.4 test.c

3.4 完整实现✴️

3.4.1 gap到底设置成多少?

3.4.2 sort.c

3.4.3 test.c

3.5 特性总结🚼

4. 性能对比--test.c🆚

后语🪅


前言🪩

Hey young fella!Welcome to my channel !我们前几篇博客学完了二叉树的一些基本内容,那么今天我们要学什么?没错👍从上次后语中,知道了我们今天要学习的是排序。本篇文章里面主要介绍插入排序的方法哦!话不多说,开始吧!


1. 排序的概念+运用🟣

1.1 排序的概念🟪

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

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

内部排序:数据元素全部放在内存中的排序。

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

下图是我们要学习的常见排序算法:


1.2 排序的运用💜

例如:网购的商品排序呈现、成绩排名、大学综合实力排名......


2. 直接插入排序🟢

2.1 基本思想🟩

把待排序的记录按其关键码值的大小逐个插入到一个已经排好序的有序序列中,直到所有的记录插入完为止,得到一个新的有序序列 。

类似于斗地主中,拿到牌之后给自己的牌插入排序


2.2 思路分析💚


看完可视化的思路之后,相信很多小伙伴已经有了大致的思路。下面,我们来整理一下思路👇

目标:先实现升序
思路:先单趟再多趟,先局部再整体

我们默认一开始前面某一部分是有序的(实际上,我们是不知道哪到哪是有序的),然后再将无序的数据开始插入进去

插入的时候会遇到以下2种情况:
情况1:该值比前面所有的数都大,那么直接接着之前的数据往后排就行
情况2:   该值比前面任意一个数小(这个数据不是前面有序的数据中最大的),前面比该数大的往后挪,腾出一个位置给该数插入

问题:

1. 有序的部分怎么知道?

我们假设0-end是有序的
一开始排序的时候可能只有第一个有序,那就是0-0

注意⚠️

2. 我们还需要tmp来存储end的下一个位置的数据----为什么?

情况1:  直接在end++的位置插入数据就行

情况2:  有一部分数据需要往后移动,end++会被覆盖掉,不保存的话,就不知道原来end++的数据是多少了

3. 循环结束的条件是什么?


2.3 代码实现✅

2.3.1 sort.h

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

//打印
void PrintArray(int* a, int n);
//直接插入排序
void InsertSort(int* a, int n);

2.3.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");
}

//[0,end]  end+1
//直接插入排序
void InsertSort(int* a, int n)
{
	//i<n-1是为了防止end+1造成数组越界
	for (int i = 0; i < n - 1; i++)
	{
		int end=i;
		int tmp = a[end + 1];
		//单趟排序
		while (end >= 0)//最差end走到-1,插入到最前面
		{
			if (tmp < a[end])
			{
				a[end + 1] = a[end];
				end--;
			}
			else
				break;
		}
		a[end + 1] = tmp;
	}
}

2.3.3 test.c


2.4 特性总结❇️

直接插入排序的特性总结:

1. 元素集合越接近有序,直接插入排序算法的时间效率越高

2. 时间复杂度:O(N^2)---最坏情况:逆序

3. 空间复杂度:O(1),它是一种稳定的排序算法

4. 稳定性:稳定

3. 希尔排序🟠

3.1 基本思想🟧

选定一个整数---gap(我们目前还不确定gap是多少),把待排序文件中所有数据分成n/gap个组,所有距离为gap的数据分在同一组内,并对每一组内的数据进行直接插入排序---进行预排序,使其接近有序

然后再次确定gap的值,重复上述分组和排序的工作。当最后gap=1时,(相当于直接插入排序)所有数据在统一组内排好序。


3.2 思路分析🔶


目标:实现升序

思路:先实现单趟排序,然后实现多趟排序

一、预排序:gap>1   接近有序

1. 先确定gap + 分组

2. 实现单趟(一组)排序

3.实现多趟排序 

二、直接插入排序:gap==1   有序

4. 所有数据进行直接插入排序

问题:

可能是后面会遇到的问题,可以和代码结合着看

1. 依据n和gap分组的时候,剩余的数据个数达不到分组的标准,出现数组越界怎么办?


3.3 预排序实现🧡

3.3.1 sort.h

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

//打印
void PrintArray(int* a, int n);
//希尔排序
void ShellSort(int* a, int n);

3.3.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");
}

//希尔排序---一组一组排序
void ShellSort(int* a, int n)
{
	//多趟排序
	int gap = 3;
	for (int j = 0; j < gap; j++)
	{
		//单趟排序
		for (int i = j; i < n - gap; i += gap)//问题1
		{
			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;
		}
	}
}

3.3.3 优化

//希尔排序---多组并排,反复横跳
void ShellSort(int* a, int n)
{
	//单趟排序
	int gap = 3;
	for (int i = 0; i < n - gap; i ++)//问题1
	{
		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;
	}
}

3.3.4 test.c

#include"sort.h"
//希尔排序
void testShellSort()
{
	int a[] = { 3,2,6,8,9,7,5,10,1,4 };
	int n = sizeof(a) / sizeof(int);
	ShellSort(a, n);
	PrintArray(a, n);
}
int main()
{
	//testInsertSort();
    testShellSort();
	return 0;
}


3.4 完整实现✴️

3.4.1 gap到底设置成多少?

预排序:
1. gap过大,分组少,排序速度快,效果不好,比较不接近有序

2. gap过小,分组多,排序速度慢,效果好,比较接近有序

问题来了:gap设置为多少呢?可不能是定值,数据个数不同gap定义是有差异的

注意⚠️

gap定义的前提:我们需要保证多组预排序之后,gap==1,从而进行直接插入排序

其实,到现在并没有确切的说法说gap怎么定义是最优的,所以这里也只是一个参考:

有人觉得gap/2(可以保证最后一次的gap==1),但是还是排序太多次了,所以就提出了gap/3,但是gap/3不能保证最后一次是1(进行直接插入排序)--->gap/3+1就可以保证啦

3.4.2 sort.c

//希尔排序---多组并排,反复横跳
void ShellSort(int* a, int n)
{
	int gap = n;
	//预排序
	while (gap > 1)
	{
		//单趟排序
		gap = gap / 3 + 1;
		for (int i = 0; i < n - gap; i++)//问题1
		{
			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;
		}
	}
	//直接插入排序
	InsertSort(a, n);
}

3.4.3 test.c


3.5 特性总结🚼

​​​​​​​ 1. 希尔排序是 对直接插入排序的优化

2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。这样整体而言,可以达到优化的效果。我们实现后可以进行性能测试的对比。

3. 希尔排序的时间复杂度不好计算,因为gap的取值方法很多,导致很难去计算,因此在好些树中给出的希尔排序的时间复杂度都不固定,导致希尔排序的时间复杂度不是很好算,需要借助数学模型,感兴趣的小伙伴可以自行搜索🔍

这里,就简单说一下平均时间复杂度:O(N^1.25)-O(1.6*N^1.25)

为了方便,我们直接粗略一点:O(N^1.3)​​​​​​​

4. 稳定性:不稳定

4. 性能对比--test.c🆚

// 测试排序的性能对比
// 测试排序的性能对比
void TestOP()
{
	srand(time(0));
	const int N = 100000;
	int* a1 = (int*)malloc(sizeof(int) * N);
	int* a2 = (int*)malloc(sizeof(int) * N);
	int* a3 = (int*)malloc(sizeof(int) * N);
	int* a4 = (int*)malloc(sizeof(int) * N);
	int* a5 = (int*)malloc(sizeof(int) * N);
	int* a6 = (int*)malloc(sizeof(int) * N);
    int* a7 = (int*)malloc(sizeof(int) * N);
	for (int i = 0; i < N; ++i)
	{
		a1[i] = rand()+i;
		a2[i] = a1[i];
		a3[i] = a1[i];
		a4[i] = a1[i];
		a5[i] = a1[i];
		a6[i] = a1[i];
        a7[i] = a1[i];
    }
    int begin1 = clock();
    InsertSort(a1, N);
    int end1 = clock();
    int begin2 = clock();
    ShellSort(a2, N);
    int end2 = clock();
    int begin3 = clock();
    //SelectSort(a3, N);
    int end3 = clock();
    int begin4 = clock();
    //HeapSort(a4, N);
    int end4 = clock();
    int begin5 = clock();
    //QuickSort(a5, 0, N - 1);
    int end5 = clock();
    int begin6 = clock();
    //MergeSort(a6, N);
    int end6 = clock();
    int begin7 = clock();
    //BubbleSort(a7, N);
    int end7 = clock();
    printf("InsertSort:%d\n", end1 - begin1);
    printf("ShellSort:%d\n", end2 - begin2);
    printf("SelectSort:%d\n", end3 - begin3);
    printf("HeapSort:%d\n", end4 - begin4);
    printf("QuickSort1:%d\n", end5 - begin5);
    printf("MergeSort:%d\n", end6 - begin6);
    printf("BulbbleSort:%d\n", end7 - begin7);
    free(a1);
    free(a2);
    free(a3);
    free(a4);
    free(a5);
    free(a6);
    free(a7);
}
int main()
{
	testInsertSort();
    testShellSort();
    TestOP();
	return 0;
}


我们发现,希尔排序排序还是很厉害👍的

后语🪅

今天,我们学习了插入排序的实现和性能对比以及他们的特性总结。希望小伙伴们自己也可以练习一下,加强记忆和理解。

下一篇博客,我们将一起学习选择排序的相关知识点!请大家多多期待🙏


本次的分享到这里就结束了!!!

PS:小江目前只是个新手小白。欢迎大家在评论区讨论哦!有问题也可以讨论的!期待大家的互动!!!

公主/王子殿下,请给我点赞👍+收藏⭐️+关注➕(这对我真的很重要!!!

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

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

相关文章

c语言-指针练习题

目录 前言一、题目一二、题目二总结 前言 为了巩固c语言中关于指针知识点的掌握&#xff0c;本篇文章记录关于指针的练习题。 一、题目一 有n个整数&#xff0c;使前面各数顺序往后移动m个位置&#xff0c;最后m个数变成最前面的m个数 写一函数实现以上功能&#xff0c;在主函…

k8s搭建(五、k8s可视化管理工具Dashboard配置)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

2000-2022年上市公司股票流动性指标数据/股票流动性Amihud(原始数据+计算代码+计算结果)

2000-2022年上市公司股票流动性指标数据/股票流动性Amihud&#xff08;原始数据计算代码计算结果&#xff09; 1、时间&#xff1a;2000-2022年 3、指标&#xff1a;证券代码_没有单位、交易日期_没有单位、日个股交易金额_元、考虑现金红利再投资的日个股回报率_没有单位、交…

杭电新生赛 大雪球 二分

&#x1f468;‍&#x1f3eb; 题目地址 ✨ AC code import java.io.*; import java.util.*;public class Main {static BufferedReader in new BufferedReader(new InputStreamReader(System.in));static BufferedWriter out new BufferedWriter(new OutputStreamWriter(Sy…

二叉树的中序遍历,力扣

目录 题目地址&#xff1a; 题目&#xff1a; 解题方法&#xff1a; 解题分析&#xff1a; 解题思路&#xff1a; 代码实现&#xff1a; 注&#xff1a; 代码实现&#xff08;递归&#xff09;&#xff1a; 代码实现&#xff08;迭代&#xff09;&#xff1a; 题目地址&#xf…

SpringBoot 增量/瘦身部署jar 包

背景 SpringBoot 项目的部署一般采用全量jar 包方式部署相关项目&#xff0c;如果我们对相关的Contrller\Service\Dao\Mapper 层进行相关业务调整就需要重新编译全量jar 包&#xff08;包大小约为200M左右&#xff09;实在太麻烦了。 本文:重点讲解使用SpringBoot 的增量/瘦身…

数字资产学习笔记

附&#xff1a;2023年数据资源入表白皮书下载&#xff1a; 关注WX公众号&#xff1a; commindtech77&#xff0c; 获得数据资产相关白皮书下载地址 1. 回复关键字&#xff1a;数据资源入表白皮书 下载 《2023数据资源入表白皮书》 2. 回复关键字&#xff1a;光大银行 下载 光…

行人重识别(ReID)基础知识入门

这里写目录标题 1、ReID技术概述1.1 基本原理1.2 实现流程1.3 重识别存在的技术挑战 2、训练数据格式介绍 1、ReID技术概述 1.1 基本原理 ReID&#xff0c;全称Re-identification&#xff0c;目的是利用各种智能算法在图像数据库中找到与要搜索的目标相似的对象。ReID是图像检…

探索效率与可扩展性:MinIO图片服 VS FastDFS图片服

目录 1、前言 2、背景知识 2.1 Minio图片服的概述 2.2 FastDFS图片服的概述 3、性能比较 3.1 存储性能比较 3.1.1 对比上传速度和下载速度 3.1.2 比较两者的读写性能 3.2 负载均衡性能比较 4、可扩展性比较 4.1 横向扩展性性能比较 4.2 纵向扩展性性能比较 5、结语…

kubeadm

kubeadm来快速的搭建一个k8s集群 二进制搭建适合大集群&#xff0c;50台以上主机。 kubeadm更适合中小企业的业务集群。 我用过的集群是二进制&#xff0c;搭建过adm master 192.168.233.91 2核4G /4核8G docker kubeadm kubectl flannel node1 192.168…

SpringMVC:Ajax、拦截器、文件上传、文件下载

文章目录 SpringMVC - 06一、Ajax1. 概述2. Ajax 异步加载数据1. 单个数据2. 对象 3. 实践4. 总结 二、拦截器1. 概述2. 实现3. 实践4. 总结 三、文件上传&#xff1a;Upload1. 准备工作2. 步骤3. 效果 四、文件下载&#xff1a;Download1. 步骤2. 效果3. 总结 注意&#xff1a…

青龙面板的安装

一、安装docker 首先&#xff0c;需要在服务器上安装docker。 没有服务器的可以使用虚拟机&#xff0c;或申请一台三丰云的免费云服务器体验一下&#xff0c;独立IP地址&#xff0c;送免备案服务&#xff0c;可以满足基本的使用&#xff0c;三丰云上还有免费虚拟主机等其他免费…

OSG绘制视锥体

最近要来实现一个相机位姿态可视化的需求&#xff0c;不想使用pangolin&#xff0c;不好集成&#xff0c;想用osg来做可视化。以下是demo效果。 代码实现&#xff1a; // Cone_of_vision.cpp : 定义控制台应用程序的入口点。 //#include "stdafx.h" #include <os…

华为hcia之ipv6实验手册

R3: dhcp enable ipv6 dhcpv6 pool test address prefix 2000:23::/64 excluded-address 2000:23::2 dns-server 2000:23::2 interface GigabitEthernet0/0/0 ipv6 enable ipv6 address 2000:12::2/64 ipv6 address auto link-local undo ipv6 nd ra halt //无状态配置 inter…

Vue中的默认插槽详解

Vue中的默认插槽详解 在 Vue 中&#xff0c;插槽&#xff08;Slot&#xff09;是一种非常强大且灵活的机制&#xff0c;用于在组件中插入内容。Vue 提供了两种类型的插槽&#xff1a;默认插槽&#xff08;Default Slot&#xff09;和具名插槽&#xff08;Named Slot&#xff09…

递归详解之青蛙跳台阶和汉诺塔问题

&#x1d649;&#x1d65e;&#x1d658;&#x1d65a;!!&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦&#x1f44f;&#x1f3fb;‧✧̣̥̇‧✦ &#x1f44f;&#x1f3fb;‧✧̣̥̇:Solitary-walk ⸝⋆ ━━━┓ - 个性标签 - &#xff1a;来于“云”的“羽球人”。…

GroundingDINO-根据文本提示检测任意目标

1. 背景介绍 GroundingDINO是一种新的SOTA零样本物体检测模型。在这篇文章中&#xff0c;我们将讨论Grounding DINO模型的优势&#xff0c;分析其具体的模型架构&#xff0c;并提供真实的测试样例。 闲话少说&#xff0c;我们直接开始吧&#xff01; 2.零样本目标检测 大多…

第七课:计算机网络、互联网及万维网(WWW)

第七课&#xff1a;计算机网络、互联网及万维网&#xff08;WWW&#xff09; 第二十八章&#xff1a;计算机网络1、局域网 Local Area Networks - LAN2、媒体访问控制地址 Media Access Control address - MAC3、载波侦听多路访问 Carrier Sense Multiple Access - CSMA4、指数…

海凌科HLK-V2语音识别模块更新词条

简介 HLK-V20 是海凌科的离线语音识别模块, 中英文不同时支持, 只支持中文/英文, 具体识别看每次的SDK更新设置;资料下载 可以在微信公众包搜索海凌科或HI-LINK, 下载资料 感知模块->HLK-V20 模块限制 中英文被限制, 需要根据你在官网设置的SDK信息进行确定;可以仅设置3…

Vue: 事件修饰符, 键盘事件, 鼠标事件,计算属性

目录 事件修饰符 阻止默认事件 阻止冒泡 允许触发一次 捕获模式 self passive 键盘事件 keyup & keydown 按键别名 注意tab 注意系统按键 自定义按键 鼠标事件 简介 鼠标焦点事件 计算属性 差值语法实现 methods实现 computed实现 get() set() 总…