插入排序解释

插入排序很好理解,其步骤是 :先将第一个数据元素看作是一个有序序列,后面的 n-1 个数据元素看作是未排序序列。对后面未排序序列中的第一个数据元素在这个有序序列中进行从后往前扫描,找到合适的插入位置并插入到其中,每次有序序列的长度 +1

重复这样的操作,将每个未排序序列中的元素插入到当前有序序列中合适的位置。直到未排序序列长度为 0,最后得到一个完整的有序序列,即为排序的结果。

(若当前插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)


插入排序动态演示

我们以序列 [7, 6, 4, 5, 8, 2, 3] 为例进行动态演示

第一次插入

第二次插入

第三次插入

第四次插入

第五次插入

第六次插入

直接插入排序 时间复杂度

最优时间复杂度

假设每一层循环,当前未排序序列中的第一个元素(待插入元素)应当插入的位置都处于当前有序序列的末尾,只需要执行一次判断就可以了。

最优时间复杂度 为: O(n)

最坏时间复杂度

假设每一层循环,当前待插入元素应当插入的位置都在当前有序序列的首位,(设当前有序序列长度为 i )那么我们每一次线性查找比较的次数为 i , 并且每次将后面元素进行后移的次数也为 i

最坏时间复杂度 为:


直接插入排序 核心代码

//插入排序
void InsertSort(vector<int> &v){
int n = v.size();
for(int i = 1; i < n; i++){
int key = v[i]; //当前需要插入的数
int j = i - 1; //j为已排序序列的末下标
while(j >= 0 && v[j] > key){
v[j + 1] = v[j]; //后移
j--;
}
v[j + 1] = key; //插入到已排序序列中的合适位置
}
}

优化方法 折半插入排序

线性查找每一次待插入元素在当前有序序列中合适的插入位置往往是比较低效的,因此我们自然会想到用 二分查找 来查找待插入元素合适的插入位置。

其实改进方法很简单,运用二分查找,定义一个 pos 来记录当前待插入元素 key 在有序序列中合适的位置,然后对 pos 之后的元素进行后移操作,在 pos 位置插入当前待插入元素就可以啦~

注意哦,每次二分查找需要找到的是在前i个数组成的有序序列中第一个大于 key 的位置 pos (若没有比key大的,插入位置即为下标为i的位置)


折半插入排序 时间复杂度

对于折半插入排序,由于始终要进行元素的后移操作,所以在 最坏情况下 利用二分查找确定插入位置确实提高了效率,但是不可避免的是依旧需要消耗 O(n^2) 的时间进行元素后移。由此可得

最优时间复杂度 依然是 O(n)

最坏时间复杂度


折半插入排序 核心代码

//折半插入排序
void BinaryInsertSort(vector<int> &v){
int n = v.size();
for(int i = 1; i < n; i++){
int key = v[i]; /* 折半查找部分 */
int low = 0, high = i - 1, pos = i;
//二分查找找到在前i个数组成的有序序列中第一个大于key的位置pos
//若没有比key大的,插入位置即为下标为i的位置
while(low <= high){
int mid = (low + high)>>1;
if(v[mid] > key){
pos = mid;
high = mid - 1;
}else{
low = mid + 1;
}
} //插入位置后后移
int j = i - 1;
while(j >= pos){
v[j + 1] = v[j];
j--;
}
v[pos] = key; //插入到合适的pos位置
}
}

完整程序源代码

#include<iostream>
#include<vector>
#include<time.h>
using namespace std; //插入排序
void InsertSort(vector<int> &v){
int n = v.size();
for(int i = 1; i < n; i++){
int key = v[i]; //当前需要插入的数
int j = i - 1; //j为已排序序列的末下标
while(j >= 0 && v[j] > key){
v[j + 1] = v[j]; //后移
j--;
}
v[j + 1] = key; //插入到已排序序列中的合适位置
}
} //折半插入排序
void BinaryInsertSort(vector<int> &v){
int n = v.size();
for(int i = 1; i < n; i++){
int key = v[i]; /* 折半查找部分 */
int low = 0, high = i - 1, pos = i;
//二分查找找到在前i个数组成的有序序列中第一个大于key的位置pos
//若没有比key大的,插入位置即为下标为i的位置
while(low <= high){
int mid = (low + high)>>1;
if(v[mid] > key){
pos = mid;
high = mid - 1;
}else{
low = mid + 1;
}
} //插入位置后后移
int j = i - 1;
while(j >= pos){
v[j + 1] = v[j];
j--;
}
v[pos] = key; //插入到合适的pos位置
}
} void show(vector<int> &v){
for(auto &x : v)
cout<<x<<" ";
cout<<endl;
} main(){
vector<int> v;
srand((int)time(0));
int n = 50;
while(n--)
v.push_back(rand() % 100 + 1);
show(v); //InsertSort(v);
BinaryInsertSort(v); cout<<endl<<endl;
show(v);
}

程序运行结果图

[排序算法] 直接/折半插入排序 (C++)的更多相关文章

  1. Java常见排序算法之折半插入排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  2. 排序算法之折半插入排序的思想以及Java实现

    1 基本思想 折半插入排序(binary insertion sort)的基本原理与直接插入排序相同,不同之处在于,确定当前记录在前面有序子数组中的位置时,直接插入排序是采用顺序查找的方法,而折半插入 ...

  3. 我的Java开发学习之旅------>Java经典排序算法之二分插入排序

    一.折半插入排序(二分插入排序) 将直接插入排序中寻找A[i]的插入位置的方法改为采用折半比较,即可得到折半插入排序算法.在处理A[i]时,A[0]--A[i-1]已经按关键码值排好序.所谓折半比较, ...

  4. Java常见排序算法之直接插入排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  5. 排序算法之直接插入排序Java实现

    排序算法之直接插入排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb  选择排序:http://t.cn/hros6e  插入排序: ...

  6. 排序系列 之 折半插入排序算法 —— Java实现

    基本思想: 折半插入算法是对直接插入排序算法的改进,排序原理同直接插入算法: 把n个待排序的元素看成一个有序表和一个无序表,开始时有序表中只有一个元素,无序表中有n-1个元素:排序过程即每次从无序表中 ...

  7. 七内部排序算法汇总(插入排序、Shell排序、冒泡排序、请选择类别、、高速分拣合并排序、堆排序)

    写在前面: 排序是计算机程序设计中的一种重要操作,它的功能是将一个数据元素的随意序列,又一次排列成一个按keyword有序的序列.因此排序掌握各种排序算法很重要. 对以下介绍的各个排序,我们假定全部排 ...

  8. 结构-行为-样式-Js排序算法之 直接插入排序

    最新因工作原因需要接触到算法,之前学习C++的时候有接触过算法,Javascript中实现算法其实也是大同小异.下面我讲下第一个实现的排序算法--直接插入排序.基本实现思路:假定一个数组中前n(n&g ...

  9. 基本的排序算法C++实现(插入排序,选择排序,冒泡排序,归并排序,快速排序,最大堆排序,希尔排序)

    博主欢迎转载,但请给出本文链接,我尊重你,你尊重我,谢谢~http://www.cnblogs.com/chenxiwenruo/p/8529525.html特别不喜欢那些随便转载别人的原创文章又不给 ...

  10. 八大排序算法之直接插入排序(InsertionSort)

    常见的排序算法 今天复习[直接插入排序] 核心思想:有序数组中 找位置 -- 给无序数组第一个 找位置 ` public class InsertionSort { // 核心思想:有序数组中 找位置 ...

随机推荐

  1. KingbaseES 数据库大小写敏感特性

    针对不同版本.是否启用大小写敏感,特征汇总如下:

  2. Mysql 实现 向上递归查找父节点并返回树结构

    需求:通过mysql 8.0以下版本实现,一个人多角色id,一个角色对应某个节点menu_id,根节点的父节点存储为NULL, 向上递归查找父节点并返回树结构. 如果只有叶子,剔除掉; 如果只有根,只 ...

  3. k8s驱逐篇(4)-kube-scheduler抢占调度驱逐

    介绍kube-scheduler抢占调度驱逐之前,先简单的介绍下kube-scheduler组件: kube-scheduler简介 kube-scheduler组件是kubernetes中的核心组件 ...

  4. kafka的auto.offset.reset详解与测试

    1. 取值及定义 auto.offset.reset有以下三个可选值: latest (默认) earliest none 三者均有共同定义: 对于同一个消费者组,若已有提交的offset,则从提交的 ...

  5. Mysql 安全加固经验总结

    本文为博主原创,转载请注明出处: 目录 1.内网部署Mysql 2. 使用独立用户运行msyql 3.为不同业务创建不同的用户,并设置不同的密钥 4.指定mysql可访问用户ip和权限 5. 防sql ...

  6. 关于thinkphp5.1(tp5.1)中sum计算结果不精确、不准确的问题

    使用sprintf函数处理,虽然原理没搞懂,但是问题解决了 复现: test表中有两列,值分别是-0.33和10,数据类型是float SELECT SUM(`val`) AS tp_sum FROM ...

  7. Python数据分析教程(一):Numpy

    原文链接:https://blog.onefly.top/posts/13140.html 数据的纬度 一维数据:列表和集合类型 二维数据:列表类型 多维数据:列表类型 高维数据:字典类型或数据表示格 ...

  8. 带你了解CANN的目标检测与识别一站式方案

    摘要: 了解通用目标检测与识别一站式方案的功能与特性,还有实现流程,以及可定制点. 本文分享自华为云社区<玩转CANN目标检测与识别一站式方案>,作者: Tianyi_Li. 背景介绍 目 ...

  9. 使用nginx-ingress-controller配置https,但是再同时配置使用http

    默认情况下,如果为该 Ingress 启用了 TLS,控制器会使用 308 永久重定向响应将 HTTP 客户端重定向到 HTTPS 端口 443.( Ingress 里配置了 https 证书的话,默 ...

  10. Elasticsearch索引生命周期管理探索

    文章转载自: https://mp.weixin.qq.com/s?__biz=MzI2NDY1MTA3OQ==&mid=2247484130&idx=1&sn=454f199 ...