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 相关文章推荐
图文详解WinPE下安装Python
May 17 Python
浅谈pandas中Dataframe的查询方法([], loc, iloc, at, iat, ix)
Apr 10 Python
Python多进程原理与用法分析
Aug 21 Python
python pygame实现2048游戏
Nov 20 Python
关于Python-faker的函数效果一览
Nov 28 Python
python实现低通滤波器代码
Feb 26 Python
记一次pyinstaller打包pygame项目为exe的过程(带图片)
Mar 02 Python
python中pickle模块浅析
Dec 29 Python
python 制作网站筛选工具(附源码)
Jan 21 Python
利用Python过滤相似文本的简单方法示例
Feb 03 Python
Python提取PDF指定内容并生成新文件
Jun 09 Python
用python基于appium模块开发一个自动收取能量的小助手
Sep 25 Python
Python下opencv库的安装过程及问题汇总
Jun 11 #Python
Python实现信息轰炸工具(再也不怕说不过别人了)
撤回我也能看到!教你用Python制作微信防撤回脚本
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
You might like
vBulletin HACK----关于排版的两个HACK
2006/10/09 PHP
php+html5基于websocket实现聊天室的方法
2015/07/17 PHP
PHP模块化安装教程
2016/06/01 PHP
thinkphp集成前端脚手架Vue-cli的教程图解
2018/08/30 PHP
Dom 是什么的详细说明
2010/10/25 Javascript
jquery向.ashx文件post中文乱码问题的解决方法
2011/03/28 Javascript
基于JQuery的类似新浪微博展示信息效果的代码
2012/07/23 Javascript
Jquery 的outerHeight方法使用介绍
2013/09/11 Javascript
jquery实现预览提交的表单代码分享
2014/05/21 Javascript
JS特效实现图片自动播放并可控的效果
2015/07/31 Javascript
jQuery实现获取table表格第一列值的方法
2016/03/01 Javascript
JavaScript的Backbone.js框架入门学习指引
2016/05/07 Javascript
简单实现AngularJS轮播图效果
2020/04/10 Javascript
vue中mint-ui环境搭建详细介绍
2017/04/06 Javascript
AngularJS之自定义服务详解(factory、service、provider)
2017/04/14 Javascript
AngularJS全局警告框实现方法示例
2017/05/18 Javascript
nodejs判断文件、文件夹是否存在及删除的方法
2017/11/10 NodeJs
Angularjs Ng_repeat中实现复选框选中并显示不同的样式方法
2018/09/12 Javascript
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
利用Python模拟登录pastebin.com的实现方法
2019/07/12 Python
python实现图片上添加图片
2019/11/26 Python
pytorch实现对输入超过三通道的数据进行训练
2020/01/15 Python
Python内存映射文件读写方式
2020/04/24 Python
利用python清除移动硬盘中的临时文件
2020/10/28 Python
Html5基于canvas实现电子签名并生成PDF文档
2020/12/07 HTML / CSS
法国太阳镜店:Sunglasses Shop
2016/08/27 全球购物
FitFlop澳大利亚官网:英国符合人体工学的鞋类品牌
2017/06/05 全球购物
FC-Moto西班牙:摩托车手最大的购物场所之一
2019/04/11 全球购物
年终自我鉴定
2013/10/09 职场文书
高三毕业寄语
2014/04/10 职场文书
村党支部书记承诺书
2014/05/29 职场文书
殡葬服务心得体会
2014/09/11 职场文书
2014年安全保卫工作总结
2014/11/13 职场文书
2014年科普工作总结
2014/12/06 职场文书
在Django中使用MQTT的方法
2021/05/10 Python
教你利用Nginx 服务搭建子域环境提升二维地图加载性能的步骤
2021/09/25 Servers