插入排序解释

插入排序很好理解,其步骤是 :先将第一个数据元素看作是一个有序序列,后面的 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. 不当使用 union all 导致的SQL解析时间过长的问题优化

    在帮助用户优化应用过程中,发现用户大量使用union all 导致SQL解析非常缓慢的问题.考虑到这个问题很有代表意义,我觉得很有必要对于问题进行总结. 一.用户例子 WITH company_use ...

  2. OOM故障处理流程

    一.OOM机制概述 Linux 内核有个机制叫OOM killer(Out Of Memory killer),该机制会监控那些占用内存过大,尤其是瞬间占用内存很快的进程,为防止内存耗尽而自动把该进程 ...

  3. Enable_hint_table 使用

    KingbaseES enable_hint_table 可以看成类似 oracle outline 工具,可以在不修改SQL 的情况下,通过hint 改变SQL 的执行计划. 一.启用enable_ ...

  4. 【Android 逆向】ARM CPP 类对象

    #include <stdio.h> class aclass{ private: int m; char c; public: aclass(int i, char ch) { prin ...

  5. Linux零拷贝原理

    Linux零拷贝原理 前言 磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝.直接 I/O.异步 I/O 等等,这些优化的目的就是为了提 ...

  6. 01-MyBatisPlus简介

    一.简介 官网:http://mp.baomidou.com/ 参考教程:https://baomidou.com/pages/24112f/ MyBatis-Plus(简称 MP)是一个 MyBat ...

  7. 03_配置Java环境变量

    配置Java环境变量 右键我的电脑-属性-高级系统设置-环境变量 系统变量-新建-变量名JAVA_HOME,变量值为JDK安装路径 系统变量-新建-变量名CLASSPATH,变量值为英文输入法下的. ...

  8. PAT (Basic Level) Practice 1033 旧键盘打字 分数 20

    旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现.现在给出应该输入的一段文字.以及坏掉的那些键,打出的结果文字会是怎样? 输入格式: 输入在 2 行中分别给出坏掉的那些键.以及应该输入 ...

  9. C#-02 传入参数的一些用法2

    C#_02 参数应用2 一.关于 "ref" 局部变量和 "ref" 返回 在前面已经明白了 ref 关键词传递一个对象引用给方法调用,这样在方法中对对象修改过 ...

  10. Vue+vant移动端处理弹窗不能滑动问题

    自己在做项目开发时,使用vantUI组件,在项目中遇到了弹窗组件里面当内容过多时,会出现滚动卡顿或者不能滚动问题,开始一直以为是自己的样式写的有问题,检查下来才发现并不是,而是弹窗组件的问题,于是找到 ...