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 相关文章推荐
python3.3教程之模拟百度登陆代码分享
Jan 16 Python
python操作数据库之sqlite3打开数据库、删除、修改示例
Mar 13 Python
深入了解Python中pop和remove的使用方法
Jan 09 Python
Python建立Map写Excel表实例解析
Jan 17 Python
学习python中matplotlib绘图设置坐标轴刻度、文本
Feb 07 Python
Python实现爬虫从网络上下载文档的实例代码
Jun 13 Python
详解TensorFlow查看ckpt中变量的几种方法
Jun 19 Python
Python自定义装饰器原理与用法实例分析
Jul 16 Python
在Pycharm中将pyinstaller加入External Tools的方法
Jan 16 Python
python使用Qt界面以及逻辑实现方法
Jul 10 Python
python tkinter之顶层菜单、弹出菜单实例
Mar 04 Python
实例讲解Python 迭代器与生成器
Jul 08 Python
Python下opencv库的安装过程及问题汇总
Jun 11 #Python
Python实现信息轰炸工具(再也不怕说不过别人了)
撤回我也能看到!教你用Python制作微信防撤回脚本
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
You might like
laravel框架关于搜索功能的实现
2018/03/15 PHP
PHP Trait代码复用类与多继承实现方法详解
2019/06/17 PHP
PHP fopen中文文件名乱码问题解决方案
2020/10/28 PHP
javascript document.images实例
2008/05/27 Javascript
关于hashchangebroker和statehashable的补充文档
2011/08/08 Javascript
jquery验证表单中的单选与多选实例
2013/08/18 Javascript
Ext JS 4实现带week(星期)的日期选择控件(实战一)
2013/08/21 Javascript
关闭浏览器窗口弹出提示框并且可以控制其失效
2014/04/15 Javascript
javascript实现仿IE顶部的可关闭警告条
2015/05/05 Javascript
javascript带回调函数的异步脚本载入方法实例分析
2015/07/02 Javascript
JS基于myFocus库实现各种功能的tab选项卡切换效果
2015/09/19 Javascript
基于OL2实现百度地图ABCD marker的效果
2015/10/01 Javascript
动态加载js、css的实例代码
2016/05/26 Javascript
jqueryMobile 动态添加元素,展示刷新视图的实现方法
2016/05/28 Javascript
Angular 2.0+ 的数据绑定的实现示例
2017/08/09 Javascript
vue中使用sessionStorage记住密码功能
2018/07/24 Javascript
浅谈Vue组件及组件的注册方法
2018/08/24 Javascript
Node.js一行代码实现静态文件服务器的方法步骤
2019/05/07 Javascript
js实现盒子拖拽动画效果
2020/08/09 Javascript
Python中的二叉树查找算法模块使用指南
2014/07/04 Python
Django imgareaselect手动剪切头像实现方法
2015/05/26 Python
Python 读写文件和file对象的方法(推荐)
2016/09/12 Python
Python读取word文本操作详解
2018/01/22 Python
Python实现获取邮箱内容并解析的方法示例
2018/06/16 Python
[原创]Python入门教程1. 基本运算【四则运算、变量、math模块等】
2018/10/28 Python
pandas 强制类型转换 df.astype实例
2020/04/09 Python
Python实现Excel自动分组合并单元格
2021/02/22 Python
canvas实现圆绘制的示例代码
2019/09/11 HTML / CSS
HTML5页面音视频在微信和app下自动播放的实现方法
2016/10/20 HTML / CSS
客户经理岗位职责
2013/12/08 职场文书
农村面貌改造提升实施方案
2014/03/18 职场文书
2014年社区工会工作总结
2014/12/18 职场文书
特种设备安全管理制度
2015/08/06 职场文书
关于mysql中时间日期类型和字符串类型的选择
2021/11/27 MySQL
Python绘画好看的星空图
2022/03/17 Python
Java 定时任务技术趋势简介
2022/05/04 Java/Android