插入排序

1.插入排序

插入排序分为直接插入排序、折半插入排序、希尔排序(shell sort),后两种是在直接插入排序的改进上而来。

1.直接插入排序

排序思路:假设待排序的元素存放在数组A[1..n]A[1..n]A[1..n]中,在排序过程的某一时刻,A被划分为两个子区间A[1..mid]A[1..mid]A[1..mid]和A[mid+1..n]A[mid+1..n]A[mid+1..n],其中前一个子区间为排好序的有序区,而后一个子区间为未排序的子区间,暂称作无序区。该排序算法顾名思义,取出无序区的第一个元素A[mid+1]A[mid+1]A[mid+1]插入到有序区A[1..mid]A[1..mid]A[1..mid]中适当的位置,A[1..mid+1]A[1..mid+1]A[1..mid+1]变成新的有序区(假设按照升序排序)。动画演示如下:
对于第i趟排序,要将无序区的第一个元素A[mid+1]A[mid+1]A[mid+1](设A[mid+1]的值为aA[mid+1]的值为aA[mid+1]的值为a)插入到有序区的适当位置,此时便将aaa不断的与有序区的元素进行比较(即为动画中红色条形与绿色条形的部分),当找到第一个比aaa小的元素时(假设是A[m](1≤m<mid+1)A[m](1\leq m<mid+1)A[m](1≤m<mid+1)),在该元素的后面将aaa插入,当a是有序区中最小的元素时,将a放在有序区的第一个位置,此时数组中下标m+1m+1m+1到midmidmid的所有元素均要往后移动一格,就像是腾出一个位置来让给aaa,然后把aaa放到数组中mmm的位置。

c/c++代码描述:

void InsertSort(int A[], int n)
{int i, j;for (int i = 2; i <= n; i++)   // 依次将A[2]~A[n]插入到前面已经有序区{if (A[i] < A[i - 1])       // A[i]小于其前面的元素,将A[i]放入有序区{A[0] = A[i];         // A[0]不存放元素,专用于来存放当前需要插入的值for (j = i - 1; A[j] > A[0]; j--) // 从后往前寻找插入位置,直至找到第一个比A[i]小的元素时停止A[j + 1] = A[j];  // 向后挪一个位置,腾出地方让给A[i]}A[j + 1] = A[0];         // A[i]归位,放到有序区合适的位置}
}

python代码描述:

def insert_sort(a):length = len(a)for i in range(1,length):waitting_insert_ele = a[i]j = i - 1while j > -1 and a[j] > waitting_insert_ele: # 与前面有序区进行比较,如果比前面有序区第一个大,则停止,将该元素插入此位置a[j + 1] = a[j]             # 后移操作,给待插入元素“腾位置”j -= 1a[j+1] = waitting_insert_ele    # 当不比前面的数值小时,便在当前位置“赖着不走”print(a)
a = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
insert_sort(a)

运行结果如下:

算法分析:  
空间复杂度:因为直接插入排序并没有开第二个数组,它仅仅只是就着他自己的原来的数组进行排序,利用的存储空间是常数个空间,因而其空间复杂度为O(1)O(1)O(1),即原地工作。 
时间复杂度:在排序过程中,向有序区逐个的插入元素进行了n−1n-1n−1趟,每趟都分为两步:

  • 和前一元素进行比较
  • 将前一元素进行往后挪

其中比较的次数与待排序数组的初始状态有关,在最优情况下,表中元素已有序,此时每遍历一次,都不用移动元素,且只需比较一次,时间复杂度为O(n)O(n)O(n)。在最坏情况下,数组中元素与要排序顺序相反(在本博客中以初始时降序排列为反序),总的比较次数达到最大均为O(n2)O(n^2)O(n2)。平均情况下总的比较次数和移动次数约为n24\frac{n^2} {4}4n2​,所以时间复杂度为O(n2)O(n^2)O(n2)。 
稳定性:每次插入元素时,总是从后向前比较再移动,所以相同元素的相对位置不会发生变化,直接插入排序是一个稳定的排序算法。 
适用性:直接插入排序适用于顺序存储和链式存储的线性表。

2.折半插入排序

排序思路: 思路同直接插入排序一致,但在进行元素比较时采用的是折半查找,在查找待插入位置时时间复杂度为O(nlog2n)O(nlog_2n)O(nlog2​n)(折半查找的时间复杂度)。

c/c++代码描述:

void InsertSort(int A[], int n)
{int i, j, low, high, mid;for (int i = 2; i <= n; i++) // 依次将A[2]~A[n]插入到前面已经有序区{A[0] = A[i]; // A[0]不存放元素,专用于来存放当前需要插入的值low = 1;high = i - 1;while (low < high){mid = (low + high) / 2; //取中间节点if (A[mid] > A[0])high = mid - 1; // 插入位置应在左半子表,即有序区的前半部分elselow = mid + 1; // 插入位置应在右半子表,即有序区的后半部分}for (j = i - 1; j > high + 1; j--) // 从后往前寻找插入位置,直至找到第一个比A[i]小的元素时停止A[j + 1] = A[j];               // 向后挪一个位置,腾出地方让给A[i]A[high + 1] = A[0];                   // A[i]归位,放到合适的地方}
}

python代码描述:

def insert_sort(a):length = len(a)print(a)for i in range(1, length):waitting_insert_key = a[i]low, high = 0, i -1while low <= high:  # 折半查找mid = (low + high) // 2     # “//”表示向下取整,相当于c语言里边的单斜杆if a[mid] > waitting_insert_key:high = mid - 1else:low = mid + 1# 上面的循环体返回第一个比 waitting_insert_key 大的元素的位置,# 当有序区中不存在比它小的元素时(即它自己和有序区中的元素相比是最小的)# 返回 -1j = i - 1while j >= high + 1:    # 元素后移,给waitting_sort_key “腾位置”a[j + 1] = a[j]j -= 1a[high + 1] = waitting_insert_keyprint(a)
a = [0,1,6,3,2,5,4]
b = [3,44,38,5,47,15,36,26,27,2,46,4,19,50,48]
insert_sort(a)
insert_sort(b)

运行结果如下:

算法分析:  折半插入排序仅仅只是减少了比较的时间而已,而对于腾出空间的挪动操作并未有改变,挪动次数取决于元素在存储结构中的初始位置,若初始表中数据整体有序的较多,则移动次数较少,因此折半插入排序的时间复杂度仍然是O(n2)O(n^2)O(n2)。折半插入排序是一种稳定的排序算法。

3.希尔排序(shell sort)

排序思路: 先将待排序的元素分组,从初始表中每相隔距离d取一个元素,形如L[i,i+d,i+2d,i+3d,...,i+kd]L[i,i+d,i+2d,i+3d,...,i+kd]L[i,i+d,i+2d,i+3d,...,i+kd],首次可将n个元素划分成ddd个组(即从第1个元素到第d个元素直接的所有元素是每组的第一个元素,“头儿”),每次分别对这些组进行直接插入排序,当整个表中的元素已基本有序时,再对全体记录进行一次直接插入排序。希尔排序每趟并不产生有序区,在最后一趟排序结束前,所有元素并不一定归位了,但是在希尔排序每趟完成后数据越来越接近有序。动画效果如下(演示动画仅进行了一次分组,第二趟排序便直接对整个序列进行排序了):
动画中演示的是先将分组中值较大的调整至后面,再将值较小的调整至前。

c/c++代码描述:

void shellSort(int A[], int n)
{int d, i, j;for (d = n / 2; d >= 1; d / 2) //每次分组的间隔长度,步长变化for (i = d + 1; i <= n; i++)if (A[i] < A[i - d]) //需将A[i]插入有序区{A[0] = A[i];for (j = i - d; j > 0 && A[j] > A[0]; j -= d)A[j + d] = A[j]; // 给小组中后面值较小的元素挪位置,让较小的元素尽量往前边靠A[j + d] = A[0];  // 最终归位}
}

python代码描述:

def insert_sort(a):length = len(a)d = length >> 1         # 除半操作,即划分分组,刚开始以两个元素为一组,共d组# 此处采用的是位运算,和前面的折半操作稍有不同# 位运算的速度要稍快于普通的乘除while d >= 1:for i in range(d, length, 1):   # 从每组的第二个元素开始遍历if a[i] < a[i - d]:         # 如果当前元素值比前边同组的“有序区”部分的元素小,则把它“调”到有序区waitting_insert_key = a[i]j = i - dwhile j > -1 and a[j] > waitting_insert_key:    # “腾位置”操作a[j + d] = a[j]j -= da[j + d] = waitting_insert_key  # “果宝机甲”归位d = d >> 1          # 分组数减少一半,分区增大一倍,即原来第一次排序# 前一个分区至多2个元素,合并后至第二轮便有4个……print(a)b = [0,1,6,3,2,5,4]
a = [3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48]insert_sort(a)
insert_sort(b)

运行结果如下:

算法分析: 
空间复杂度:因为希尔排序并没有使用第二个数组,它仅仅只是就着他自己的原来的数组进行排序,使用存储空间为常数个空间,因而其空间复杂度为O(1)O(1)O(1)。 
时间复杂度:由于希尔排序的时间复杂度依赖于增量序列的函数,这涉及数学上未解决的难题,所以其时间复杂度分析比较困难。当n在某个特定范围时,希尔排序的时间复杂度约为O(n1.3)O(n^{1.3})O(n1.3)。在最坏情况下希尔排序的时间复杂度为O(n2)O(n^2)O(n2)。 
稳定性:希尔排序是一种不稳定的排序算法。
适用性:希尔排序仅适用于线性表为顺序存储的情况。

后记: 文章中的python代码的运行示例的pycharm风格不同是因为文章是断断续续写的,前两张的运行截图是借同学的电脑运行的截图,后一张是自己吃完晚饭在自己电脑上截的图。平常要忙着考研复习,只有中午、晚上吃完饭回寝室才有时间写一下,文章连着写了好几天才写完。后面也会挤时间陆续把其他的几个基础算法补齐的。欢迎各位大佬指正文中不足的部分,弟弟以后定加改正!

几种重要的排序算法——插入排序相关推荐

  1. 七种常见的排序算法总结

    目录 引言 1.什么是排序? 2.排序算法的目的是什么? 3.常见的排序算法有哪些? 一,插入排序 1.基本思想 2.代码实现 3.性能分析 4.测试 二,希尔排序(缩小增量排序) 1.基本思想 2. ...

  2. access两字段同时升序排序_7 天时间,我整理并实现了这 9 种常见的排序算法

    排序算法 回顾 我们前面已经介绍了 3 种最常见的排序算法: java 实现冒泡排序讲解 QuickSort 快速排序到底快在哪里? SelectionSort 选择排序算法详解(java 实现) 然 ...

  3. 视觉直观感受 7 种常用的排序算法

    2019独角兽企业重金招聘Python工程师标准>>> 1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较 ...

  4. 7 种常用的排序算法直观感受

    1. 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序 ...

  5. 视觉直观感受7种常用的排序算法

    1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通 ...

  6. 几种常用的排序算法之JavaScript实现

    文章目录 插入排序 二分插入排序 选择排序 选择排序 冒泡排序 快速排序 堆排序 归并排序 桶排序 计数排序 插入排序 <html> <script> /* 1)算法简介插入排 ...

  7. 通过视觉直观感受7种常用的排序算法

    1 快速排序 介绍: 快速排序是由东尼·霍尔所发展的一种排序算法.在平均状况下,排序 n 个项目要Ο(n log n)次比较.在最坏状况下则需要Ο(n2)次比较,但这种状况并不常见.事实上,快速排序通 ...

  8. 算法学习--排序算法--插入排序

    算法学习--排序算法--插入排序 插入排序算法 代码实现 插入排序算法 插入排序(Insertion sort)是一种简单直观且稳定的排序算法.如果有一个已经有序的数据序列,要求在这个已经排好的数据序 ...

  9. Java排序算法——插入排序(Insertion Sort)

    之前总结了交换排序的冒泡排序与选择排序的简单选择排序,这次我们来看看插入排序的简单插入排序~ 往期传送门: 冒泡排序: Java排序算法--冒泡排序(Bubble Sort)https://blog. ...

最新文章

  1. vi/vim: 使用taglist插件
  2. 多伦多大学和清华大学创新创业论坛,数据科学研究院建言献策
  3. c语言四则运算实验报告,c语言四则运算实验报告.doc
  4. Segment Routing — SRv6 — SRv6 协议解析
  5. Android 设计模式 - 观察者模式
  6. 一文带你看懂PaddleHub
  7. 索尔维会议记录软件测试,索尔维会议
  8. 关于NSKeyedArchiver的编码格式
  9. 使用Google Guava Cache进行本地缓存
  10. JMeter4.0以上 分布式测试报错 server failed start Listen failed on port
  11. 【python基础】ValueError: only 2 non-keyword arguments accepte
  12. i2c传输距离_使用 ToF 传感器进行距离测量和手势识别的基本原理
  13. Java经典编程题50道之三十一
  14. 谁说前端程序员不了解业务?站出来!
  15. LVS (Linux虚拟服务器)模型及算法
  16. 抱米花-豆丁文档下载器 20100529
  17. 机器学习——联合概率分布及其意义
  18. 辩证的看待IDE工具(Java与Python学习通法)
  19. WebSphere Application Server V7、V8 和 V8.5 中的高级安全性加强,第 1 部分: 安全性加强的概述和方法...
  20. 面试官:说一下什么是熔断?什么是服务降级?

热门文章

  1. python challenge
  2. (libgdx学习)ScrollPane(使用ScrollPane来创建一个横向滚动条)
  3. 【Android】WebView安全漏洞问题
  4. python可以设计网页吗_python能做网页吗?
  5. mapreduce 编程
  6. 跨站脚本攻击(XSS)分类介绍及解决办法
  7. 通达信接口官网-TcApi的工作机制
  8. file_zilla 通过key连接远程服务器
  9. php怎么获取图片拍摄时间,【技巧】如何查看图片的拍摄地点和日期时间等信息...
  10. 校园卡私人区块链平台毕设