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天气预报采集器实现代码(网页爬虫)
Oct 07 Python
用Python编写一个基于终端的实现翻译的脚本
Apr 24 Python
python复制列表时[:]和[::]之间有什么区别
Oct 16 Python
itchat-python搭建微信机器人(附示例)
Jun 11 Python
Python Subprocess模块原理及实例
Aug 26 Python
使用pickle存储数据dump 和 load实例讲解
Dec 30 Python
python ubplot使用方法解析
Jan 10 Python
Django数据库操作之save与update的使用
Apr 01 Python
Python Django搭建网站流程图解
Jun 13 Python
Python正则表达式高级使用方法汇总
Jun 18 Python
python利用tkinter实现图片格式转换的示例
Sep 28 Python
matplotlib绘制鼠标的十字光标的实现(自定义方式,官方实例)
Jan 10 Python
Python下opencv库的安装过程及问题汇总
Jun 11 #Python
Python实现信息轰炸工具(再也不怕说不过别人了)
撤回我也能看到!教你用Python制作微信防撤回脚本
用Python创建简易网站图文教程
python+opencv实现视频抽帧示例代码
用Python将GIF动图分解成多张静态图片
OpenCV-Python 实现两张图片自动拼接成全景图
You might like
PHP和Mysqlweb应用开发核心技术 第1部分 Php基础-1 开始了解php
2011/07/03 PHP
PHP提示Notice: Undefined variable的解决办法
2012/11/24 PHP
php使用Cookie实现和用户会话的方法
2015/01/21 PHP
php 中phar包的使用教程详解
2018/10/26 PHP
JS操作XML中DTD介绍及使用方法分析
2019/07/04 PHP
PHP如何防止用户重复提交表单
2020/12/09 PHP
js 目录列举函数
2008/11/06 Javascript
jquery ajax提交表单数据的两种实现方法
2010/04/29 Javascript
Javascript 面向对象 重载
2010/05/13 Javascript
JQuery each()嵌套使用小结
2014/04/18 Javascript
js中for in语句的用法讲解
2015/04/24 Javascript
javascript 动态修改css样式方法汇总(四种方法)
2015/08/27 Javascript
JavaScript实现的MD5算法完整实例
2016/02/02 Javascript
NodeJs读取JSON文件格式化时的注意事项
2016/09/25 NodeJs
jQuery实现大图轮播
2017/02/13 Javascript
使用Vue制作图片轮播组件思路详解
2018/03/21 Javascript
js实现头像上传并且可预览提交
2020/12/25 Javascript
[47:53]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#2COL VS Spirit
2016/03/02 DOTA
python 字符串split的用法分享
2013/03/23 Python
python实现异步回调机制代码分享
2014/01/10 Python
Python使用arrow库优雅地处理时间数据详解
2017/10/10 Python
详解PyTorch批训练及优化器比较
2018/04/28 Python
python 变量初始化空列表的例子
2019/11/28 Python
python实现微信打飞机游戏
2020/03/24 Python
英国玛莎百货美国官网:Marks & Spencer美国
2018/11/06 全球购物
C#基础面试题
2016/10/17 面试题
教师试用期自我鉴定
2014/02/12 职场文书
大课间体育活动方案
2014/03/12 职场文书
室内设计专业自荐信
2014/05/31 职场文书
开展党的群众路线教育实践活动领导班子对照检查材料
2014/09/25 职场文书
公司感谢信范文
2015/01/22 职场文书
小爸爸观后感
2015/06/15 职场文书
新学期小学班主任工作计划
2019/06/21 职场文书
Win11运行育碧游戏总是崩溃怎么办 win11玩育碧游戏出现性能崩溃的解决办法
2022/04/06 数码科技
微信小程序APP页面的之间的相互传递参数以及自定义组件
2022/04/19 Javascript
python数字图像处理之图像自动阈值分割示例
2022/06/28 Python