插入排序解释

插入排序很好理解,其步骤是 :先将第一个数据元素看作是一个有序序列,后面的 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. Skype for Business server 数据库安装

    之前安装了SFB 2015标准版,但是没有安装归档据库,现在打算重新安装.环境中安装的是默认自带的SQL EXPRESS. 继续安装向导,安装SQL数据库.但是在最后的时候遇到了问题. 安装向导报错 ...

  2. 在工作组的环境中配置Windows 2012 R2的远程桌面服务

    在工作组的环境中配置Windows 2012 R2的远程桌面服务 How to configure Remote Desktop Service in Windows 2012 R2 workgrou ...

  3. Elastic:为Elasticsearch启动https访问

  4. vivo 公司 Kubernetes 集群 Ingress 网关实践

    文章转载自:https://mp.weixin.qq.com/s/qPqrJ3un1peeWgG9xO2m-Q 背景 vivo 人工智能计算平台小组从 2018 年底开始建设 AI 计算平台至今,已经 ...

  5. 通过使用nginx来实现logstash的负载均衡

    文章转载自:https://blog.csdn.net/UbuntuTouch/article/details/106813223 总结: nginx配置,192.168.0.5 user nginx ...

  6. mac 批量修改文件的后缀名

    1-将需要修改的文件拖到同一个文件夹 2-打开终端输入 for i in *; do mv "$i" "$i.jpg";done

  7. LeetCode - 二维数组及滚动数组

    1. 二维数组及滚动数组总结 在二维数组num[i][j]中,每个元素都是一个数组.有时候,二维数组中的某些元素在整个运算过程中都需要用到:但是有的时候我们只需要用到前一个或者两个数组,此时我们便可以 ...

  8. 自学Spring

    Spring官网地址https://spring.io/ springManven官网地址:https://mvnrepository.com------------------------ spri ...

  9. 关于Linux中使用bc命令计算圆周率

    Linux系统中,我们可以安装bc计算器用来计算pi值(π圆周率) 在玩的同时,这可以从某些方面反映出一个CPU的运算能力,在命令最前加上time即可 如果系统中没有bc命令,需要先进行安装:yum ...

  10. python中的多线程与多进程

    线程概念: 线程也叫轻量级进程,是操作系统能够进行运算调度的最小单位,它被包涵在进程之中,是进程中的实际运作单位. 线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源,但它可与同属一个进程的其 ...