算法之插入排序及希尔排序(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个数是已排好的,即endwhile (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个数是已排好的,即endwhile (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个数是已排好的,即endwhile (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

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

希尔排序缺点:

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

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

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

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

相关文章

Python神器解密:掌握property特性巧管理属性

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com property 是Python中的一个内置装饰器&#xff0c;它用于创建属性并允许开发者定义特定的操作&#xff0c;例如获取&#xff08;getter&#xff09;、设置&#xff08;setter&#xff09;和删除&#xff08;dele…

Vue中的过滤器了解吗?过滤器的应用场景有哪些?

​&#x1f308;个人主页&#xff1a;前端青山 &#x1f525;系列专栏&#xff1a;Vue篇 &#x1f516;人终将被年少不可得之物困其一生 依旧青山,本期给大家带来vue篇专栏内容:vue-filter过滤器 目录 一、是什么 二、如何用 定义filter 小结&#xff1a; 三、应用场景 四…

苍穹外卖项目笔记(6)— Redis操作营业状态设置

1 在 Java 中操作 Redis 1.1 Redis 的 Java 客户端 Jedis&#xff08;官方推荐&#xff0c;且命令语句同 redis 命令&#xff09;Lettuce&#xff08;底层基于 Netty 多线程框架实现&#xff0c;性能高效&#xff09;Spring Data Redis&#xff08;对 Jedis 和 Lettuce 进行了…

同为科技(TOWE)模块化定制化让每条PDU实现专属供电解决方案

作为追求最高功率和空间效率的动态数据中心的理想产品&#xff0c;模块化、定制化PDU是追求最高功率和空间效率的动态数据中心的理想产品。同为科技&#xff08;TOWE&#xff09;是我国PDU行业的开创者和领导者&#xff0c;曾率先于中国电源分配单元http://www.pdu.com.cn网站上…

机器学习实战第3天:手写数字识别

☁️主页 Nowl &#x1f525;专栏《机器学习实战》 《机器学习》 &#x1f4d1;君子坐而论道&#xff0c;少年起而行之 ​ 文章目录 一、任务描述 二、数据集描述 三、主要代码 &#xff08;1&#xff09;主要代码库的说明与导入方法 &#xff08;2&#xff09;数据预…

2023-11-28 C语言if语句多个||或 与的时时候,会顺序执行,不满足条件则退出,不会再比较后面的内容,实例测试

一、if(i > 0 || image(0) > 5)或者if(i > 0 && image(0) > 5)&#xff0c;C语言if语句多个||或 与&&的时时候&#xff0c;会顺序执行&#xff0c;不满足条件则退出&#xff0c;不会再比较后面的内容。 二、测试代码 #include <stdio.h> #i…

成为网络安全高手!教你如何做出专业级别的渗透测试

01、信息收集 1、域名、IP、端口 域名信息查询&#xff1a;信息可用于后续渗透 IP信息查询&#xff1a;确认域名对应IP&#xff0c;确认IP是否真实&#xff0c;确认通信是否正常 端口信息查询&#xff1a;NMap扫描&#xff0c;确认开放端口 发现&#xff1a;一共开放两…

Linux CentOS_7解决无法上网的问题

参考视频&#xff1a;保姆式教学虚拟机联网liunx(centos)_哔哩哔哩_bilibili 第一步&#xff1a;选择网络模式 第二步&#xff1a;配置网卡命令&#xff1a;打开终端执行命令&#xff1a; 1、先切换到根目录下&#xff0c;防止在第执行cd /etc/sysconfig/network-scripts命的…

java多线程-扩展知识一:进程线程、并发并行、同步异步

1、进程 进程&#xff08;Process&#xff09;是计算机中的程序关于某数据集合上的一次运行活动&#xff0c;是系统进行资源分配的基本单位&#xff0c;是操作系统结构的基础。在早期面向进程设计的计算机结构中&#xff0c;进程是程序的基本执行实体&#xff1b;在当代面向线程…

云计算——ACA学习 阿里云云计算服务概述

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号&#xff1a;网络豆云计算学堂 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a; 网络豆的主页​​​​​ 目录 写在前面 前期回顾 本期介绍 前言了解 一…

【领域驱动设计 学习目标及大纲】从CRUD到架构设计

从2018年至今&#xff0c;已工作了5年有余&#xff0c;回望这5年的工作历程&#xff0c;虽然一直在学习、一直在积累&#xff0c;但其实都在术的层面上停留&#xff0c;也就是具体的技术点。这5年多的时间里其实也不是没有窥道的想法&#xff1a; 一次是2018年刚工作的时候&am…

FPGA模块——AD高速转换模块(并行输出转换的数据)

FPGA模块——AD高速转换模块&#xff08;并行输出转换的数据&#xff09; &#xff08;1&#xff09;AD9280/3PA9280芯片&#xff08;2&#xff09;代码 &#xff08;1&#xff09;AD9280/3PA9280芯片 AD9280/3PA9280芯片的引脚功能&#xff1a; 工作电压2.7到5.5v 数据对应&a…

采购申请的库存地点和MRP2的库存地点的关系

F类材料的采购申请的库存地点&#xff0c;带外部采购申请仓储地点 X类材料的采购申请的库存地点,从MRP2的生产仓储地点自动带到计划订单再到生产工单再到采购申请。

MSTP实验

目录 一、实验拓扑 二、实验要求 三、实验步骤 1、创建vlan 2、创建端口组&#xff0c;放通vlan 3、配置MSTP 4、配置主备奋根 一、实验拓扑 二、实验要求 1、所有交换机上创建vlan10&#xff0c;vlan20&#xff0c;vlan30和vlan40 2、所有交换机之间的端口配置为Trunk…

Redis(二):常见数据类型:String 和 哈希

引言 Redis 提供了 5 种数据结构&#xff0c;理解每种数据结构的特点对于 Redis 开发运维⾮常重要&#xff0c;同时掌握每 种数据结构的常⻅命令&#xff0c;会在使⽤ Redis 的时候做到游刃有余。 Redis 的命令有上百种&#xff0c;我们不可能全部死记硬背下来&#xff0c;但是…

【小白进阶】Linux 调试大法——gdb

初衷 gdb调试是每一个后端开发工程师所必备的技能&#xff0c;我们工作总是会用gdb协助我们去分析和调试问题。但是大部分同学的技能仅停留在最基础的查看问题。即gdb program -->r --> 问题复现 --> bt 查看源码中的哪一行出现了错误。再稍微熟练点的&#xff0c;可能…

抖音视频如何无水印下载,怎么批量保存主页所有视频没水印?

现在最火的短视频平台莫过于抖音&#xff0c;当我们刷到一个视频想下载下来怎么办&#xff1f;我们知道可以通过保存到相册的方式下载&#xff0c;但用这种方法下载的视频带有水印&#xff0c;而且有些视频不能保存到相册&#xff08;这是视频作者设置了禁止下载&#xff09;。…

Unity 关于SpriteRenderer 和正交相机缩放

float oldWidth 750f;float oldHeight 1334f;float newWidth Screen.width;float newHeight Screen.height;float oldAspect oldWidth / oldHeight;float newAspect newWidth / newHeight;//水平方向缩放float horizontalCompressionRatio newAspect / oldAspect;//垂直…

IDEA插件推荐

今天给大家推荐一款IDEA插件&#xff1a;Apipost-Helper-2.0&#xff0c;支持三大功能&#xff1a;写完代码IDEA内一键生成API文档&#xff1b;写完代码IDEA内一键调试&#xff1b;生成API目录树&#xff0c;双击即可快速定位API定义的代码…非常好用&#xff01;而且完全免费&…