插入排序--直接插入排序,折半插入排序,希尔排序

news2024/11/12 13:17:13

插入排序是一种简单直观的排序方法,其基本思想是每次将一个待排序的记录按其关键词大小插入前面已经排好的子序列,直到全部记录插入完成。

一,直接插入排序:从小到大排序

数组序号01234567
待排序列4938659776132749
第一轮3849659776132749
第二轮3849659776132749

第一轮,数组序号为1开始与前面元素进行比较,38 <49,所以将38与49交换位置

第二轮:数组序号为3开始与前面的元素进行比较,49,38都小于65,故位置不变

代码展示:

//直接插入排序,从小到大进行排列
void InsertSort(Str &L)
{
	for(int i = 1; i < L.length; ++i)//最开始从第二个元素和前面元素相比
	{
		if(L.data[i] < L.data[i-1])//如果后面的元素比前面的元素小,执行后续操作
		{	
		  int temp = L.data[i];//先将元素存储在一个定义的元素中,防止被覆盖
		  int j;
		  for(j = i-1; j >= 0 && L.data[j] > temp; --j)//从i-1的那个元素开始前面的元素都和temp的元素进行比较,如果比temp元素大,就依次往后移动
		  {
			  L.data[j+1] = L.data[j];//如果比temp元素大,就依次往后移动
		  }
		  L.data[j+1] = temp;//加入说前面元素都是比temp中元素大,那么最后当j = -1是不满足循环条件,所以j应该加1,其他位置也是同样的逻辑

		}
	}
}

结果:

 

 

二,折半插入排序

将待排序元素前面已经排序好的元素进行折半查找,找到位置后,将元素逐个往后移动,然后再将待排序元素赋值到该位置上

以下面为例讲解:13是待排元素

数组序号012345678
待排序列133849657697132749
第一次lowmidhigh
第二次

low

mid

high
第三次highlow
后移133838496576972749
1338496576972749

第一次的时候:low = 1, high = 5, mid = (low+high)/2 = 3,对应元素65>13,进行第二次

第二次的时候:low = 1, high = mid-1 = 2, mid = (low+high)/2 = 1,向下取整;mid对应元素为38>13,进行第三次

第三次的时候:low = 1; high = mid-1 = 0;此时low>high,结束

然后将元素比13大的元素全部后移,最后将数组序号为0的元素赋值到序号为low的位置

代码展示:

//折半插入排序
void Binary_InsertSort(Str &L)
{
  int i,j,low,high,mid;
  for(i = 2; i <= L.length; ++i)//从第二个元素开始,依次向后
  {
	  L.data[0] = L.data[i];//将需要和前面元素进行比较的元素放在L.data[0]中,防止被覆盖
	  low = 1;//折半插入排序中折半过程是对前面已经排序好的元素进行折半,所以最开low = 1
	  high = i-1;//i前面的元素是已经排序好的,所以high = i-1;
	  while(low <= high)//循环条件
	  {
	    mid = (low+high)/2;//中间值,向下取整
		if(L.data[mid] > L.data[0])//查找左半子表
			high = mid-1;
		else
			low = mid+1;//查找右半子表,当等于的时候也是将low = mid+1,这样就可以使数组稳定
	  }
	  for(j = i-1; j >= low; --j)
	  {
		  L.data[j+1] = L.data[j];//统一后移元素,空出插入位置
	  }
	  L.data[low] = L.data[0];//将元素插入空出来的位置
  }
}

结果:

 三,希尔排序

将待排序列分割若干的”特殊“子表,即把相隔某个”增量“(缩小增量)的记录组成一个子表,对各个子表分别进行直接插入排序,当整个表中的元素以呈”基本有序“时,再对全体记录进行一次直接插入排序。

每次将增量缩小一半,最开始为:8/2 = 4;考试中可能遇到各种增量

数组序号012345678
待排序列4938659776132749
子表14976
子表23813
子表36527
子表49749
第一趟排序结果4913274976386597

增量变为:4/2 = 2

数组序号012345678
待排序列4913274976386597
子表1

49

277665
子表213493897
排序后子表127496576
排序后1子表213384997
第二趟排序结果2713493865497697

后续增量变为:2/2 =1,变成直接插入排序

代码展示:

//希尔排序
void ShellSort(Str &L)
{
  int dk,i,j;
  for(dk = L.length/2; dk >= 1; dk = dk/2)//最开始令缩小增量dk为待排序列元素个数的一半,当dk = 1变成直接插入排序
  {
    for(i = 1; i < dk+1; ++i)//每次使用缩小变量组成子表的个数为dk,每个子表的第一个元素是从1到dk
	{
		for(j = i+dk; j <= L.length; j = j+dk)//从子表的第二个元素开始,循环
		{
			L.data[0] = L.data[j];//先将待排序元素存储到数组序号为0的位置上,以免移动时元素被覆盖无法找到
			if(L.data[j-dk] > L.data[0])//如果子表中以排序元素大于待排序元素
			{
				for(j; j > i && L.data[j-dk] > L.data[0]; j = j-dk)//j为待排序元素序号,如果已排序元素的序号大于子表第一个元素序号并且大于待排序元素,循环,从后往前,依次访问
				{
					L.data[j] = L.data[j-dk];//满足条件之后从后往前将元素依次往后移动
				}
				L.data[j] = L.data[0];//最后将数组序号为0中的元素赋值到腾出的位置,从前面可以分析出,如果子表第一个满足条件,执行循环语句之后,j就成为子表第一个元素所在序号,所以L.data[j] = L.data[0]
			}
		}
	}
  }
}

结果: 

 

 

课本上的希尔排序代码如下:

相当于几个子表循环进行元素比较移动

//课本希尔排序代码
void ShellSort(ElemType A[],int n)
{
  //A[0]只是暂存单位,不是哨兵,当j <= 0时,插入位置已到
	int dk,i,j;
	for(dk = n/2; dk >=1; dk = dk/2)
	{
	  for(i = dk+1; i <= n; ++i)
	  {
	    if(A[i] < A[i-dk])
		{
		  A[0] = A[i];
		  for(j = i-dk; j > 0 && A[0] < A[j]; j -= dk)
		  {
		    A[j+dk] = A[j];
		  }
		  A[j+dk] = A[0];
		}
	  }
	}
}
插入排序空间复杂度时间复杂度稳定性适用性
直接插入排序O(1)O(n^{2})稳定顺序存储和链式存储
折半插入排序O(1)O(n^{2})稳定顺序存储
希尔排序O(1)O(n^{2})稳定顺序存储

稳定性:待排序中有相同的元素,在进行某种算法的排序之后,若是这些相同元素的相对位置不发生改变的话,就称这种排序算法是稳定的

算法是否稳定不能够衡量一个算法的优劣,它主要对算法的性质进行描述。

完整代码:

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define Size 8

//定义动态分配内存数组
typedef struct
{
  int *data;
  int length;
}Str;

//函数说明
void CreatString(Str &L);
void CreatString1(Str &L);
void InsertSort(Str &L);
void StrPrint(Str L);
void StrPrint1(Str L);
void Binary_InsertSort(Str &L);
void ShellSort(Str &L);

int main(void)
{
  Str L;
  CreatString(L);
  printf("数组元素为:\n");
  StrPrint(L);
  InsertSort(L);
  printf("直接插入排序之后数组元素为:\n");
  StrPrint(L);
  Str L1;
  CreatString1(L1);
  printf("折半插入排序之后数组元素为:\n");
  Binary_InsertSort(L1);
  StrPrint1(L1);
  Str L2;
  CreatString1(L2);
  printf("希尔排序之后数组元素为:\n");
  ShellSort(L2);
  StrPrint1(L2);
  return 0;
}

void CreatString(Str &L)
{
	L.data = (int *)malloc(sizeof(int)*Size);
	L.length = Size;
	int val;
	for(int i = 0; i < L.length; ++i)
	{
	  printf("请输入数组第%d个值:",i+1);
	  scanf_s("%d",&val);
	  L.data[i] = val;
	}
}

void CreatString1(Str &L)
{
	L.data = (int *)malloc(sizeof(int)*Size+1);
	L.length = Size;
	int val;
	for(int i = 1; i <= L.length; ++i)
	{
	  printf("请输入数组第%d个值:",i);
	  scanf_s("%d",&val);
	  L.data[i] = val;
	}
}

//直接插入排序,从小到大进行排列
void InsertSort(Str &L)
{
	for(int i = 1; i < L.length; ++i)//最开始从第二个元素和前面元素相比
	{
		if(L.data[i] < L.data[i-1])//如果后面的元素比前面的元素小,执行后续操作
		{	
		  int temp = L.data[i];//先将元素存储在一个定义的元素中,防止被覆盖
		  int j;
		  for(j = i-1; j >= 0 && L.data[j] > temp; --j)//从i-1的那个元素开始前面的元素都和temp的元素进行比较,如果比temp元素大,就依次往后移动
		  {
			  L.data[j+1] = L.data[j];//如果比temp元素大,就依次往后移动
		  }
		  L.data[j+1] = temp;//加入说前面元素都是比temp中元素大,那么最后当j = -1是不满足循环条件,所以j应该加1,其他位置也是同样的逻辑

		}
	}
}

//遍历输出
void StrPrint(Str L)
{
	for(int i = 0; i < L.length; ++i)
	{
		printf("%d ",L.data[i]);
	}
	printf("\n");
}

void StrPrint1(Str L)
{
	for(int i = 1; i <= L.length; ++i)
	{
		printf("%d ",L.data[i]);
	}
	printf("\n");
}



//折半插入排序
void Binary_InsertSort(Str &L)
{
  int i,j,low,high,mid;
  for(i = 2; i <= L.length; ++i)//从第二个元素开始,依次向后
  {
	  L.data[0] = L.data[i];//将需要和前面元素进行比较的元素放在L.data[0]中,防止被覆盖
	  low = 1;//折半插入排序中折半过程是对前面已经排序好的元素进行折半,所以最开low = 1
	  high = i-1;//i前面的元素是已经排序好的,所以high = i-1;
	  while(low <= high)//循环条件
	  {
	    mid = (low+high)/2;//中间值,向下取整
		if(L.data[mid] > L.data[0])//查找左半子表
			high = mid-1;
		else
			low = mid+1;//查找右半子表,当等于的时候也是将low = mid+1,这样就可以使数组稳定
	  }
	  for(j = i-1; j >= low; --j)
	  {
		  L.data[j+1] = L.data[j];//统一后移元素,空出插入位置
	  }
	  L.data[low] = L.data[0];//将元素插入空出来的位置
  }
}

//希尔排序
void ShellSort(Str &L)
{
  int dk,i,j;
  for(dk = L.length/2; dk >= 1; dk = dk/2)//最开始令缩小增量dk为待排序列元素个数的一半,当dk = 1变成直接插入排序
  {
    for(i = 1; i < dk+1; ++i)//每次使用缩小变量组成子表的个数为dk,每个子表的第一个元素是从1到dk
	{
		for(j = i+dk; j <= L.length; j = j+dk)//从子表的第二个元素开始,循环
		{
			L.data[0] = L.data[j];//先将待排序元素存储到数组序号为0的位置上,以免移动时元素被覆盖无法找到
			if(L.data[j-dk] > L.data[0])//如果子表中以排序元素大于待排序元素
			{
				for(j; j > i && L.data[j-dk] > L.data[0]; j = j-dk)//j为待排序元素序号,如果已排序元素的序号大于子表第一个元素序号并且大于待排序元素,循环,从后往前,依次访问
				{
					L.data[j] = L.data[j-dk];//满足条件之后从后往前将元素依次往后移动
				}
				L.data[j] = L.data[0];//最后将数组序号为0中的元素赋值到腾出的位置,从前面可以分析出,如果子表第一个满足条件,执行循环语句之后,j就成为子表第一个元素所在序号,所以L.data[j] = L.data[0]
			}
		}
	}
  }
}

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

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

相关文章

【数据算法与结构】用按层次顺序遍历二叉树的方法,统计树中具有度为1的结点数目

题目&#xff1a; Qestion: 用按层次顺序遍历二叉树的方法&#xff0c;统计树中具有度为1的结点数目。 数据结构定义 typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right; } TreeNode;样例二叉树的形状 核心代码 // 统计具有度为1的节点数目的…

解决idea默认配置maven仓库地址的问题

我的maven配置地址 一直没注意 jar包什么的全部都是C盘默认的路径&#xff0c;导入项目更改后&#xff0c;再次导入项目 路径还是会变成C盘的路径&#xff1b; 上网搜索找到了解决的办法&#xff1b; 一、File——>New Projects Setup ———>Settings for New Projects…

React hooks之useCallback的使用与性能分析

使用useCallback优化代码 useCallback是对传过来的回调函数优化&#xff0c;返回的是一个函数&#xff1b;useMemo返回值可以是任何&#xff0c;函数&#xff0c;对象等都可以。 简单来说就是返回一个函数&#xff0c;只有在依赖项发生变化的时候才会更新&#xff08;返回一个…

vue项目打包后如何本都部署访问

npm run build生成dist项目后&#xff0c;在windows部署访问。 方式一&#xff1a; 1、新建一个文件夹 进入目录后打开cmd 输入npm init -y 2、输入 npm i express -s 是用于在 Node.js 项目中安装 Express 框架的命令 3、.将项目打包好的dist文件放入其中以及新建一个app.js文…

C++ 二叉搜索树

1. 内容安排说明 二叉树在前面 C 数据结构阶段已经讲过&#xff0c;本节取名二叉树进阶是因为&#xff1a; 1. map 和 set 特性需要 先铺垫二叉搜索树&#xff0c;而二叉搜索树也是一种树形结构 2. 二叉搜索树的特性了解&#xff0c;有助于更好的理解 map 和 set 的特性 …

在JDK17尝鲜Flink1.17

在JDK17尝鲜Flink1.17 前言 还没玩明白老版本&#xff0c;Flink1.17就来了&#xff01;&#xff01;&#xff01;总还是要向前看的。。。 根据官网文档&#xff1a;https://nightlies.apache.org/flink/flink-docs-release-1.17/docs/try-flink/local_installation/ Flink r…

【Excel技巧】如何将一堆文字快速整理成一列表格数据?

在平时的工作中&#xff0c;我们有时候需要把很多零散的分布的内容&#xff08;比如姓名&#xff09;&#xff0c;复制到Excel工作表的单元格内&#xff0c;变成一列。如果一个个复制粘贴&#xff0c;显然太过繁琐。 如何批量快速的完成这一操作呢&#xff1f;只需要下面简单几…

关于排查springboot启动时页面出现404

今天在进行开发时&#xff0c;Contronller代码没有问题&#xff0c;前端html也没问题&#xff0c;发现当浏览器输入localhost:8080时404&#xff0c;于是进行排查发现&#xff0c;SpringbootWebApplication文件放到了子目录下。 springboot的启动文件必须放在父目录下才可以检测…

【Git原理与使用】-- 远程操作

目录​​​​​​​ 理解分布式版本控制系统 远程仓库 新建远程仓库 lssue 与 Pull Request模板文件 知识铺垫 lssue 模板文件 Pull Request模板文件 克隆远程仓库 使用 HTTPS 方式 使用 SSH 方式 第一步&#xff1a;创建SSH Key 向远程仓库推送 过程梳理 实操 …

Java安全——安全提供者

Java安全 安全提供者 在Java中&#xff0c;安全提供者&#xff08;Security Provider&#xff09;是一种实现了特定安全服务的软件模块。它提供了一系列的加密、解密、签名、验证和随机数生成等安全功能。安全提供者基础设施在Java中的作用是为开发人员提供一种扩展和替换标准…

vue中使用Drawflow连线插件,并对端口进行命名

效果如图 场景:项目中需要拖拽模块并连线,有输入端和输出端之分,不同模块不同端口才能相连 文档相关 点击前往------->原项目git地址 点击前往------->提供端口既可输出又可输出方案 点击前往----->查阅发现原项目无法对端口命名 public文件夹下创建drawflow文件夹…

myCobot 280 2023机械臂全新功能,手柄控制、自干涉检测

引言 机械臂是一种可编程的、自动化的机械系统&#xff0c;它可以模拟人类的动作&#xff0c;完成各种任务&#xff0c;例如装配、喷涂、包装、搬运、焊接、研磨等。由于其高度灵活性和多功能性&#xff0c;机械臂在现代社会中已经得到了广泛的应用。 myCobot 280 M5Stack 20…

在服务器部署前后端分离的项目(前后都有), 并使用nginx配置跨域

怎样部署自己的项目呢 先准备一个服务器(小系统最便宜的轻量级服务器就行, 如果不需要给人访问的话)安装宝塔面板 (宝塔面板, 可视化界面, 操作简单, 使用非常方便, 上手也很容易, 如果只是学习, 虚拟机也行没必要花钱, 我使用的CentOS7系统,安装宝塔面板)软件: MySQL, Tomcat…

【问题记录】多线程环境下,使用 std::cout 输出内容会显示混乱

环境 Windows 11 家庭中文版Microsoft Visual Studio Community 2022 (64 位) - Current 版本 17.5.3 测试代码 #include <iostream> #include <Windows.h>//创建的线程数量 #define THREAD_COUNT 4DWORD WINAPI ThreadProc(LPVOID lpParam) {UNREFERENCED_P…

JS事件监听

目录 事件监听 事件监听案例 事件监听 事件&#xff1a;HTML事件是发生在HTML元素上的“事情” 按钮点击鼠标移动到元素上按下键盘按键事件监听&#xff1a;JS可以在事件被检测到时执行代码事件绑定 方法一&#xff1a;通过HTML标签中的事件属性进行绑定 <input type"…

在windows环境下安装支持CUDA的opencv-python

文章目录 附件&#xff1a;GPU和CUDA的关系 —— 开发人员通过CUDA可以使用GPU的计算能力来加速各种计算任务&#xff0c;并提高计算性能和效率。一、环境配置&#xff08;0&#xff09;我的电脑配置环境&#xff08;1&#xff09;CUDA cuDNN下载与安装&#xff08;2&#xff…

【云原生、Kubernetes】Kubernetes核心概念理解

首先我们要掌握 Kubernete 的一些核心概念。 这些核心可以帮助我们更好的理解 Kubernetes 的特性和工作机制。 集群组件 首先&#xff0c;Kubernetes 集群中包含2类节点&#xff0c;分别是&#xff1a;master控制节点和node工作节点。 master 控制节点 负责管理整个集群系统…

【手撕算法|动态规划系列No.4】leetcode91. 解码方法

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

软件测试:系统测试

1 系统测试的概念 系统测试&#xff08;System Testing&#xff09;的定义&#xff1a;将已经集成好的软件系统&#xff0c;作为整个基于计算机系统的一个元素&#xff0c;与计算机硬件、外设、某些支持软件、数据和人员等其他系统元素结合在一起&#xff0c;在实际运行&#…

HDLBits刷题笔记8:Circuits.Sequential Logic.Latches and Flip-Flops

D flip-flop module top_module (input clk,input d,output reg q );always (posedge clk)q < d; endmoduleD flip-flops 建立一个8bit的D触发器 module top_module (input clk,input [7:0] d,output reg [7:0] q );always (posedge clk)q < d; endmoduleDFF with res…