我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

一、插入排序

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

在这里插入图片描述

1.1 执行流程

在这里插入图片描述

(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)

在这里插入图片描述

消耗时间为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

在这里插入图片描述

消耗时间为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的变化,且数组中左右端点代表区间的大小是不断减小的,最终左右端点重合,此时的位置就是插入的位置。
下面是查找的示例:

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

代码如下:


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

在这里插入图片描述

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

1.6 时间空间复杂度

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

1.7 稳定性

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

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

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

排序算法之插入排序法解析

目录什么是插入排序法算法优化心得体会什么是插入排序法插入排序法是一种简单但有效的排序算法,其基本思想是将一个待排序的元素逐个插入到已经排好序的元素序列中,直至所有元素都被插入完成,从而得到一个有序序列。具体步骤如下:假设初始时,第一个
2023-08-08

排序算法图解之Java插入排序

插入排序是一种最简单的排序方法,它的基本思想是将一个记录插入到已经排好序的有序表中,从而一个新的、记录数增1的有序表。本文通过图片合示例讲解了插入排序的实现,需要的可以了解一下
2022-11-13

排序算法图解之Java冒泡排序及优化

冒泡排序即通过对待排序的序列从前往后,依次比较相邻元素的值,若发现逆序则交换位置,使较大的元素逐渐移动到后部。本文通过图片和示例介绍了冒泡排序的实现及优化,需要的可以参考一下
2022-11-13

C++超详细分析优化排序算法之堆排序

堆是计算机科学中一类特殊的数据结构的统称,通常是一个可以被看做一棵完全二叉树的数组对象。而堆排序是利用堆这种数据结构所设计的一种排序算法。本文将通过图片详细介绍堆排序,需要的可以参考一下
2023-02-09

Java 选择排序、插入排序、希尔算法实例详解

1、基本思想:在要排序的一组数中,选出最小的一个数与第一个位置的数交换;然后在剩下的数当中再找最小的与第二个位置的数交换,如此循环到倒数第二个数和最后一个数比较为止。    2、实例  3、算法实现   /** * 选择排
2023-05-31

TypeScript十大排序算法插入排序实现示例详解

这篇文章主要为大家介绍了TypeScript十大排序算法插入排序实现示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
2023-02-23

Python实现快速排序和插入排序算法及自定义排序的示例

一、快速排序快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方
2022-06-04

如何进行C++冒泡排序及其优化算法

这期内容当中小编将会给大家带来有关如何进行C++冒泡排序及其优化算法,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。冒泡排序极其优化算法步骤1.比较相邻的元素。如果第一个比第二个大,就交换他们两个。2.对每
2023-06-21

python 排序算法总结及实例详解

总结了一下常见集中排序的算法归并排序归并排序也称合并排序,是分治法的典型应用。分治思想是将每个问题分解成个个小问题,将每个小问题解决,然后合并。 具体的归并排序就是,将一组无序数按n/2递归分解成只有一个元素的子项,一个元素就是已经排好序的
2022-06-04

浅谈插入排序算法在Python程序中的实现及简单改进

Python实现插入排序的一般范例为:#coding=cp936 #coding=cp936 #插入排序算法 def InsertionSort(A):for j in range(1,len(A)):key = A[j]i = j-1#向
2022-06-04

java数据结构与算法之桶排序实现方法详解

本文实例讲述了java数据结构与算法之桶排序实现方法。分享给大家供大家参考,具体如下:基本思想:假定输入是由一个随机过程产生的[0, M)区间上均匀分布的实数。将区间[0, M)划分为n个大小相等的子区间(桶),将n个输入元素分配到这些桶中
2023-05-31

深入解析Go语言中各种运算符的优先级排序方法

深入解析Go语言中各种运算符的优先级排序方法在Go语言中,运算符的优先级决定了表达式中运算符的计算顺序。正确理解运算符的优先级是编写高效代码的关键之一。本文将深入解析Go语言中各种运算符的优先级排序方法,并提供具体的代码示例。一、算术运算符
深入解析Go语言中各种运算符的优先级排序方法
2023-12-23

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录