算法之插入排序及希尔排序(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,一经查实,立即删除!

相关文章

linux 内核tasket机制

tasklet&#xff08;tasklet&#xff0c;有的书中翻译为“任务蕾”&#xff09;是基于软中断实现的。为什么要提供tasklet&#xff1f;因为tasklet相对软中断有以下优势。 &#xff08;1&#xff09;软中断的种类是编译时静态定义的&#xff0c;在运行时不能添加或删除&#x…

谈谈MYSQL中的Explain

目录 前言 基本介绍 Explain结果列解读 概述 key key_len type extra 前言 我们在设计一个系统的时候&#xff0c;有时候通常为了基础业务&#xff0c;写出的查询sql语句并不高效&#xff0c;从而影响到用户使用系统的整体体验感不是很好&#xff0c;我们通常在系统的…

一篇文章搞懂 JavaScript 箭头函数

一篇文章搞懂 JavaScript 箭头函数 JavaScript 箭头函数的引入为我们编写简洁且易读的代码提供了便利。 箭头函数是 ES6&#xff08;ECMAScript 2015&#xff09; 引入的新语法&#xff0c;它可以用一种更简单的方式来定义函数。本文将深入探讨箭头函数的特性、用法和一些最佳…

百度地图定位

https://lbsyun.baidu.com/index.php?titlejspopularGL/guide/geoloaction // 百度地图API功能 var map new BMap.Map(map)var point new BMap.Point(108.95, 34.27)map.centerAndZoom(point, 12)var geolocation new BMap.Geolocation()geolocation.getCurrentPosition(f…

Python常见基础数据结构

Python常见基础数据结构 字符串字符串的构造字符串是一种序列正向索引负向索引有限切片无限切片查询方法压缩方法替换方法格式化插入分割方法 列表列表构造列表同样属于序列列表的元素增加列表其他方法 元组字典字典的构造字典不属于序列字典可变 字符串 字符串的构造 • 单引…

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

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

【强化学习】关于PPO、SAC算法中价值函数的一些胡思乱想

最近的一些关于强化学习中价值函数的一些想法&#xff0c;发在了知乎上&#xff0c;全文考过来调公式有点麻烦&#xff0c;就直接发链接算了。 https://zhuanlan.zhihu.com/p/600300791?utm_psn1712895542018043904 https://zhuanlan.zhihu.com/p/667868767?utm_psn17128948…

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 进行了…

c++ 共享内存

共享内存 一、查看所有的共享内存 (py37) hqnuc:~/tmp/hq$ ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 4 blueberry 600 524288 2 dest 0x000000…

力扣labuladong——一刷day54

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣1660. 纠正二叉树二、力扣100. 相同的树三、力扣572. 另一棵树的子树四、力扣101. 对称二叉树 前言 判断树是否相等&#xff0c;就直接遍历就可以。判断…

同为科技(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…

题目标题:汽水瓶 c语言

1.问题描述 有这样一道智力题&#xff1a;“某商店规定&#xff1a;三个空汽水瓶可以换一瓶汽水。小张手上有十个空汽水瓶&#xff0c;她最多可以换多少瓶汽水喝&#xff1f;”答案是5瓶&#xff0c;方法如下&#xff1a;先用9个空瓶子换3瓶汽水&#xff0c;喝掉3瓶满的&#x…

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

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; 网络豆的主页​​​​​ 目录 写在前面 前期回顾 本期介绍 前言了解 一…