直接插入排序的两种做法

可能很多人不会留意到这个问题,今天恰好碰到了,然后来稍微讨论一下

直接插入排序应该是很多数据结构与算法书里第一个讲的排序算法,算法的描述是这样的:

把待排序列视作两段,一段是已排序列,一段是未排序列。每一趟排序时,为未排序列的首位在已排序列中进行查找(因为是直接插入排序,所以这里特指逐个比较)其合适的位置,然后将其插入(插入的过程中伴随着一系列元素的后移)。

当时没有想太多,直接写了个按文字描述的代码:

def InsertSort1(LIST):
    for i in range(1,len(LIST)):#从1开始,将0元素视为已排序列
        TEMP=LIST[i]#保存中间变量
        for ii in range(0,i):
            if LIST[ii]>TEMP:#从前往后逐次比较,如果出现比它大的元素,那么就说明他应该落在此位。此处未加等于号是为了保证排序稳定性
                for iii in range(i,ii,-1):#注意,从后往前位移元素
                    LIST[iii]=LIST[iii-1]
                LIST[ii]=TEMP
                break
    return LIST

后来在看的时候发现好像不太对劲,怎么嵌套了三层for,于是乎回忆起了这一段应该是从后往前进行比较的

def InsertSort2(LIST):
    for i in range(1,len(LIST)):
        TEMP=LIST[i]
        flag=True
        for ii in range(i-1,-1,-1):#从后往前进行逐次比较
            if LIST[ii]>TEMP:
                LIST[ii+1]=LIST[ii]
            else:
                 LIST[ii+1]=TEMP
                 flag=False
                 break
        if flag:
            LIST[0]=TEMP
    return LIST

这里使用了两个辅助变量,TEMP和flag

事实上很多书在写这一段的时候,用了另一种巧妙的方法,只是用了一个辅助变量,这里可以参阅其他文章,我当时写到这里的时候立刻就回忆起了书里把这个做法叫做哨兵,即数组的0元素不用来储存元素,作为temp使用,在需要flag的地方不需要使用flag,保持了操作的一致性。这其实并不是我们要讨论的重点。

乍一看,二方法只嵌套了两层for,是不是比一方法要好呢?

答案是否定的,其实这个问题用一个图就能很好的表达了:

InsertSort1() 的性能十分稳定,在图中,它逐次比较的“路程”和后续位移的“路程”加起来恰好就是前一段线长(+1)

而InsertSort2()的性能不是那么稳定,在图中,当待排元素在已排序列中合适的位置靠后时,它的性能无疑是更好(付出了更短的“路程”),而当待排元素靠前时,它的性能就变差了(付出了双倍,更长的“路程”)

其实两个做法都是符合插入排序思想的,平均性能一致,最好性能的情况下2好于1,最坏情况下1>2

老实说真没想到这个最初始的算法会藏着这么一个有趣的小秘密,也算是颇有收获了

原文地址:https://www.cnblogs.com/asakura/p/11108518.html

时间: 2024-08-03 06:38:20

直接插入排序的两种做法的相关文章

SqlServer保留几位小数的两种做法

SqlServer保留几位小数的两种做法   数据库里的 float momey 类型,都会精确到多位小数.但有时候 我们不需要那么精确,例如,只精确到两位有效数字. 解决: 1. 使用 Round() 函数,如 Round(@num,2) 参数 2 表示 保留两位有效数字. 2. 更好的方法是使用 Convert(decimal(18,2),@num) 实现转换,decimal(18,2) 指定要保留的有效数字. 这两个方法有一点不同:使用 Round() 函数,如果 @num 是常数,如 R

jqGrid中实现radiobutton的两种做法

http://blog.sina.com.cn/s/blog_4f925fc30102e27j.html   jqGrid中实现radiobutton的两种做法 -------------------------------------------------------------------------------------------------- 第一种:colModel: [                {                    name: 'MY_ID',    

SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机)【两种做法】

手动博客搬家: 本文发表于20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680 人生第一道后缀自动机. 说实话SAM我还没学多么明白. 但是题还是要做的. 说起来这玩意真的很妙.可惜我智商低理解不了. 再次验证了代码能力菜到没边.hyw 30min写完我写2.5h. 题目链接 (洛谷) https://www.luogu.org/problemnew/show/SP1812 题目大意 给\(n

LVS+keepalived 的DR模式的两种做法

LVS DR模式搭建 准备工作 三台机器: dr:192.168.13.15 rs1:192.168.13.16 rs2: 192.168.13.17 vip:192.168.13.100 修改DR上的/etc/sysctl.conf文件 net.ipv4.ip_forward=0改为net.ipv4.ip_forward=1 第一种做法lo Dr上的配置 ! Configuration File for Keepalived ! --------------------------------

完全关闭App的两种做法

做项目的时候,涉及到一个注销登录的过程,这时候需要关闭之前打开的所有Activity.仅finish当前Activity显然是不够的.我实践过的方法有两种: 1.基础类BaseActivity中注册广播接收器,接受关闭所有Activity的广播 2.基础类BaseActivity中将Activity加入一个集合中,并提供一个静态finishAll的方法统一关闭 public class ExitAppReceiver extends BroadcastReceiver { @Override p

两种MD5最后的值不一样,因为两种做法不一样

//MD5加密 private static string Md5Hash(string input)         {             MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();             byte[] data = md5Hasher.ComputeHash(Encoding.Default.GetBytes(input));             StringBuilde

使用post方法上传文件的两种做法

项目需要使用HTTP协议中的POST方法上传文件,稍微总结了一下,将过程贴出来,方便以后参考.有两种方法,第一是使用NSMutableURLRequest完全从零开始设置,可以加深对HTTP协议的理解:第二种是直接使用别人封装好的代码,如AFNetworking. 方法一,从0开始文件上传 NSURL *url = [NSURL URLWithString:@"http://yo.diveinedu.com/upload.php"];NSMutableURLRequest *reque

EasyUI Pagination 分页的两种做法

EasyUI 的 datagrid 支持服务器端分页,但是官方的资料比较少,以下总结了两种 datagrid 的服务器端分页机制,可根据情况具体使用. 一:使用 datagrid 默认机制 后台: public JsonResult GetQuestionUnit() {     // easyui datagrid 自身会通过 post 的形式传递 rows and page     int pageSize = Convert.ToInt32(Request["rows"]);  

腰部按摩操有两种做法

一.两手掌对搓至手心热后,分别放至腰部,手掌向皮肤,上下按摩腰部, 至有热感为止.可早晚各一遍,每遍约 200 次.此运动可补肾纳气 二.两手握拳,手臂往后用两拇指的掌关节突出部位,自然按摩腰眼,向内 做环形旋转按摩,逐渐用力,以至酸胀感为好,持续按摩 10 分钟左右,早.中. 晚各一次.腰为肾之府,常做腰眼按摩,可防治中老年人因肾亏所致的慢肌劳损. 腰酸背痛等症. 脚心按摩的方法 是:每日临睡前用温水泡脚,再用手互相擦热后,用左手心按摩右脚心,右手心 按摩左脚心,每次 100 下以上,以搓热双