Python排序算法之插入排序及其优化方案详解


Posted in Python onJune 11, 2021

一、插入排序

插入排序与我们平时打扑克牌非常相似,将新摸到的牌插入到已有的牌中合适的位置,而已有的牌往往是有序的。

Python排序算法之插入排序及其优化方案详解

1.1 执行流程

Python排序算法之插入排序及其优化方案详解

(1)在执行过程中,插入排序会将序列分为2部分,头部是已经排好序的,尾部是待排序的。
(2)从头开始扫描每一个元素,每当扫描到一个元素,就将它插入到头部合适的位置,使得头部数据依然保持有序

1.2 逆序对

数组 <2,3,8,6,1> 的逆序对为:<2,1> ❤️,1> <8,1> <8,6> <6,1>,共5个逆序对。
插入排序的时间复杂度与逆序对的数量成正比关系,逆序对的数量越多,插入排序的消耗的时间就越多。
当逆序对的数量极少时,插入排序的效率特别高,甚至速度比 O nlogn 级别的快速排序还要快。

1.3 代码实现

将一个元素插入到数组有序的前半部分中,那个插入的位置元素一定是比该元素大,而该位置前的元素比该元素小(或者是没有前一个元素)。所以我们可以通过比较,将该元素进行冒泡:如果前一个元素比我大,则交换位置,否则停止冒泡。

def insertion_sort_ver1(array):
    n=len(array)
    for right in range(1,n):
        cur=right
        while cur>0 and array[cur-1]>array[cur]:
            array[cur-1],array[cur]=array[cur],array[cur-1]
            cur-=1

整体代码:

import numpy as np
import time

#检查是否有序
def orderCheck(array):
    for i in range(len(array)-1):
        if array[i]>array[i+1]:
            print('排序失败')
            return
    print('排序成功')
    
def sort(sort_algorithm,ori_array):
    #先复制一份数组,再进行更改
    array = np.copy(ori_array)
    start=time.clock()
    sort_algorithm(array)
    end=time.clock()
    total_time=float(end-start)
    print(sort_algorithm.__name__+" : %0.5f" % total_time)
    orderCheck(array)

def insertion_sort_ver1(array):
    n=len(array)
    for right in range(1,n):
        cur=right
        while cur>0 and array[cur-1]>array[cur]:
            array[cur-1],array[cur]=array[cur],array[cur-1]
            cur-=1
            
array=np.random.randint(0,10000,2000,dtype=int)
sort(insertion_sort_ver1, array)

Python排序算法之插入排序及其优化方案详解

消耗时间为0.82632秒。

1.4 优化1

在冒泡中,交换前后cur和cur-1位置两个元素的位置,需要进行两次赋值,但如果冒泡仍要继续,cur-1位置的元素还是会被cur-2位置的元素覆盖,所以两次赋值中的一次其实是无意义的,为此我们可以先找到插入位置,然后将后方的元素作统一的移动;或者是在冒泡过程中只进行一次赋值(将前一个元素移动到后方),直到冒泡结束确定插入位置后,再进行待插入元素的插入。

#元素交换作优化
def insertion_sort_ver2(array):
    n=len(array)
    for right in range(1,n):
        cur=right
        elem=array[cur]
        while cur>0 and array[cur-1]>elem:
            array[cur]=array[cur-1]
            cur-=1
        array[cur]=elem

Python排序算法之插入排序及其优化方案详解

消耗时间为0.45987秒,明显变快了。

1.5 优化2

之前我们在寻找插入的位置时,采用的是从大到小依次遍历的方法,因为是在一个有序的数组上寻找插入的位置,我们肯定会想到一种查找的方法:二分查找。通过二分查找,我们可以通过O(logn)级别的比较与O(n)级别的元素移动完成排序任务,而之前我们进行的比较和移动,都是O(n)级别。

1.5.1 普通二分查找

普通的二分查找十分简单,根据中间位置元素大小更新两端索引位置即可,在此两端的索引 [left,right)采用左闭右开的方式,这样未查找到元素的条件就十分简单,因为区间左闭右开,当left<right时,表明区间内还有元素,仍旧可以进行查找;否则,区间里没有元素了,说明元素未查找到,代码如下。

def binary_search(array,target):#[left,right)左闭右开
    left=0
    right=len(array)
    while left<right:#当left<right,表明区间中还有值,否则哪怕left==right,因right不可取,区间中还是无值
        middle = (left + right) >> 1
        if target<array[middle]:
            right=middle
        elif array[middle]<target:
            left=middle+1
        else:
            return middle
    return -1

1.5.2 二分查找插入位置

查找插入位置的二分查找显然和普通二分不同,在此我们修改一下左右端点移动的条件与移动方式。在此左右端点依旧左闭右开,如果当array[middle]小于或等于插入元素target,那么显然middle不可能是插入位置,middle位置的元素也不再需要,left应该为middle+1;而当array[middle]大于target,那么middle有可能是插入的位置(插入位置大于target,前一个元素如果存在,应小于target),应该保留middle,所以right=middle。但是区间是左闭右开,right不可取到,哪怕right=middle,middle不还是无法取得吗?但由于array[middle]不论取何值(不管是大于、等于、小于),都将导致左右端点left、right的变化,且数组中左右端点代表区间的大小是不断减小的,最终左右端点重合,此时的位置就是插入的位置。
下面是查找的示例:

Python排序算法之插入排序及其优化方案详解
Python排序算法之插入排序及其优化方案详解

Python排序算法之插入排序及其优化方案详解
Python排序算法之插入排序及其优化方案详解
Python排序算法之插入排序及其优化方案详解

代码如下:

def binary_search(array,index):
    left=0
    right=index
    while left<right:
        middle=(left+right)>>1
        if array[middle]>array[index]:#大于目标,可能是插入的位置,用right保留
            right=middle
        else:#小于等于,不可能是插入位置,更新left为middle+1
            left=middle+1
    return left #最后插入的位置

1.5.3 使用二分的插入排序

找到插入位置后,我们只需移动位置后面的元素,再将元素插入即可。

#利用二分查找找到插入的点,减少了比较的次数
def insertion_sort_ver3(array):
    n=len(array)
    for right in range(1,n):
        index=binary_search(array,right)
        elem=array[right]
        for i in range(right,index,-1):
            array[i]=array[i-1]
        array[index]=elem

Python排序算法之插入排序及其优化方案详解

可见速度比之前的插入排序仍有提高。

1.6 时间空间复杂度

最坏、平均时间复杂度:O(n^2),最好时间复杂度:O(n),空间复杂度:O(1)。

1.7 稳定性

插入排序将后方的元素从后往前插入,后边相等的元素将插入在左边相等元素的右侧,没有改变原有的位置,属于稳定排序。

到此这篇关于Python排序算法之插入排序及其优化方案详解的文章就介绍到这了,更多相关Python插入排序内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python实现中文转换url编码的方法
Jun 14 Python
Python正则简单实例分析
Mar 21 Python
Python实现两款计算器功能示例
Dec 19 Python
python+matplotlib绘制旋转椭圆实例代码
Jan 12 Python
解决python大批量读写.doc文件的问题
May 08 Python
pycharm修改界面主题颜色的方法
Jan 17 Python
python 实现12bit灰度图像映射到8bit显示的方法
Jul 08 Python
Python修改列表值问题解决方案
Mar 06 Python
基于virtualenv创建python虚拟环境过程图解
Mar 30 Python
Python实现CAN报文转换工具教程
May 05 Python
Spark处理数据排序问题如何避免OOM
May 21 Python
写好Python代码的几条重要技巧
May 21 Python
Python下opencv库的安装过程及问题汇总
Jun 11 #Python
Python实现信息轰炸工具(再也不怕说不过别人了)
撤回我也能看到!教你用Python制作微信防撤回脚本
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
You might like
jq的get传参数在utf-8中乱码问题的解决php版
2008/07/23 PHP
通过php快速统计某个数据库中每张表的数据量
2012/09/04 PHP
Yii2使用小技巧之通过 Composer 添加 FontAwesome 字体资源
2014/06/22 PHP
javascript 表单验证常见正则
2009/09/28 Javascript
JavaScript 打地鼠游戏代码说明
2010/10/12 Javascript
js实现的仿新浪微博完美的时间组件升级版
2011/12/20 Javascript
jQuery setTimeout传递字符串参数报错的解决方法
2014/06/09 Javascript
jQuery学习笔记之 Ajax操作篇(二) - 数据传递
2014/06/23 Javascript
jQuery判断元素上是否绑定了指定事件的方法
2015/03/17 Javascript
快速学习jQuery插件 Form表单插件使用方法
2015/12/01 Javascript
Vue.js基础知识汇总
2016/04/27 Javascript
Vue.js快速入门教程
2016/09/07 Javascript
浅谈Nodejs中的作用域问题
2016/12/26 NodeJs
bootstrap弹出层的多种触发方式
2017/05/10 Javascript
node.js中express-session配置项详解
2017/05/31 Javascript
[02:04]2014DOTA2国际邀请赛 DK一个时代的落幕
2014/07/21 DOTA
[40:55]DOTA2上海特级锦标赛主赛事日 - 2 败者组第二轮#4Newbee VS Fnatic
2016/03/03 DOTA
[44:10]2018DOTA2亚洲邀请赛 4.5 淘汰赛 EG vs VP 第一场
2018/04/06 DOTA
[42:56]VGJ.S vs Serenity 2018国际邀请赛小组赛BO2 第二场 8.19
2018/08/21 DOTA
基于python log取对数详解
2018/06/08 Python
jupyter修改文件名方式(TensorFlow)
2020/04/21 Python
解决python 执行sql语句时所传参数含有单引号的问题
2020/06/06 Python
python3 简单实现组合设计模式
2020/07/02 Python
python遍历路径破解表单的示例
2020/11/21 Python
使用python对excel表格处理的一些小功能
2021/01/25 Python
利用纯css3实现的文字亮光特效的代码演示
2014/11/27 HTML / CSS
美国传奇滑手Paul Rodriguez创办的街头滑板品牌:Primitive Skateboarding
2019/10/29 全球购物
家长对孩子评语
2014/01/30 职场文书
会议邀请书范文
2014/02/02 职场文书
机关出纳岗位职责
2014/04/03 职场文书
酒店节能减排方案
2014/05/26 职场文书
高中教师先进事迹材料
2014/08/22 职场文书
实名检举信范文
2015/03/02 职场文书
学生党支部工作总结2015
2015/05/26 职场文书
MongoDB支持的索引类型
2022/04/11 MongoDB
SQL Server使用PIVOT与unPIVOT实现行列转换
2022/05/25 SQL Server