插入排序解释

插入排序很好理解,其步骤是 :先将第一个数据元素看作是一个有序序列,后面的 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 R6 集群备库网卡down测试案例

    数据库版本: test=# select version(); version ------------------------------------------------------------ ...

  2. winfrom杀死进程及关闭进程

    ProcessStartInfo process = new ProcessStartInfo(); process.FileName = AppDomain.CurrentDomain.BaseDi ...

  3. [Python]-string-字符串

    字符串是Python中很常用的数据类型,此处记录一些典型用法并随时更新. split()方法 通过指定分隔符对字符串进行切片,如果参数 num 有指定值,则分隔 num+1 个子字符串. 两个参数st ...

  4. linux下安装mysql(rpm安装)

    Mysql 5.7.29安装步骤 1.首先卸载自带的Mysql-libs(如果之前安装过mysql,要全都卸载掉) rpm -qa | grep -i -E mysql\|mariadb | xarg ...

  5. Django 连接数据库 MySQL

    一.Django 连接 MySQL 修改 settings.py 文件 # 默认用的是sqlite3 # Database # https://docs.djangoproject.com/en/4. ...

  6. 从 Yum 更新中排除特定/某些包的三种方法

    方法 1:手动或临时用 yum 命令排除包 要排除单个包: # yum update --exclude=kernel 或者 # yum update -x 'kernel' 要排除多个包.以下命令将 ...

  7. 18个一线工作中常用的Shell脚本

    1.检测两台服务器指定目录下的文件一致性 #!/bin/bash ###################################### 检测两台服务器指定目录下的文件一致性 ######### ...

  8. Prometheus告警处理

    在Prometheus Server中定义告警规则以及产生告警,Alertmanager组件则用于处理这些由Prometheus产生的告警.Alertmanager即Prometheus体系中告警的统 ...

  9. 微信小程序之发起请求

    wx.request({ url: api.api + '/weChat/api/user/myAunt', // 仅为示例,并非真实的接口地址 data: {}, method: 'GET', he ...

  10. PTA 520钻石争霸赛 2021

    7-1 自动编程 签到题 #include<bits/stdc++.h> typedef long long ll; const int maxm = 1e5 + 5; const int ...