《算法导论》第2章 算法基础(插入排序、归并排序、复杂度计算)

2023-05-16

(最近在自己学习《算法导论》一本书,之前本来喜欢手写笔记,但是随即发现自己总是把笔记弄丢,所以打算做一个电子版的笔记)

(另外书中用的都是伪代码,笔记中如果需要尝试的地方都是python代码)

2.1 插入排序

        基本思想:将待排序的数列看成两个部分(以从小到大为例),前一半是排序完成的,后一半是乱序的,对于乱序的第一个,开始和前一半里最大的数字、第二大的数字……依次比较,等到合适的位置就将它放进去。然后比对过的数字向后移动一位,相应的排序完成的长度加一,没有排序的减一。如:

5 | 2 6 4 3 1 ➡️   2 ? 5: 2 < 5!                                                      把2插到5前面

2 5 | 6 4 3 1 ➡️   6 ? 5: 6 > 5!                                                      把6插到5后面

2 5 6 | 4 3 1 ➡️   4 ? 6: 4 < 6!  4 ? 5:  4 < 5!  2 ? 4: 2<4!       把4插到2和5之间 

……

        另外在证明插入排序的这个部分用到了循环不变式

        初始化:循环的第一次迭代之前,命题为真;

        保持:如果循环的某次迭代之前它为真,那么下次迭代之前它仍然为真;

        终止:在循环终止时,不变式为我们提供一个有用的性质,该性质有助于证明算法正确。

        在插入排序之中,初始化性质体现在一开始分成两个部分的时候,第一个部分由于长度是1,所以也是必然满足所谓的“从小到大”排列的。而保持的性质则体现在如果将一个新的数字插入到序列中,例如把4插入的那一步,插入之前和之后仍然满足第一个序列按照“从小到大”排列。而终止性质则体现在排序的过程结束的时候,第一个序列是“从小到大”排列的,是“有用的性质”,可以证明这个算法是正确的。

2.2 分析算法

        分析算法的效率,采用的假想中的一种通用的单处理器计算模型——随机访问机(random-access machine,RAM)来实现,它包含着算数指令(加减乘除求余取整),数据移动(装入、存储、复制)和控制指令(条件与无条件转移、子程序调用和返回),每条指令的时间都是常数,有助于我们评价一个算法的时间效率。

        由于是理想模型,不会考虑实际计算中计算机的运行速度、高速缓存、虚拟内存等等

        通过分析算法复杂度,可以给出最坏情况下的运行时间,尽管很多时候时间和数据规模的函数并不是一个简单的基本初等函数乘以一个系数,但是只需要考虑它在趋向于较大的数据规模时主要控制运行时间的一项。也就是高次项。相比于考虑它的值,考虑它的变化率往往是更加有意义的。换句话说,我们真正感兴趣的是运行时间的增长率增长量级

        *为什么往往考虑最坏情况?

        -可以对算法的运行状态进行有效的表征(例如超过最坏情况仍没有看到结果,可能bug了)

        -很多时候最坏情况往往是平均情况,例如数据库查找时,很多时候找不到所需要的数据,但是算法很有可能将整个数据库遍历了一遍,也就是最坏情况。

2.3 设计算法

        利用“分治法”的设计方法,可以设计出一种比插入排序更快的方法:归并排序(递归)

        基本思想:如果有两个有序的列表片段,和两个位置指针,通过比较位置指针指向的值的大小,依次插入,最终得到的大列表片段也是有序的。而且又很明显这两个列表片段长度是1的时候,列表显然是有序的。

自己尝试的python代码:

# 算法导论2.3 归并排序练习代码
def guibing(List, p, q, r):
    '''
    递归排序函数
    :param List: 等待排序的列表
    :param p: 等待排序的列表片段的下界
    :param q: 等待排序的列表片段的中间值
    :param r: 等待排序的列表片段的上界
    :return: 排序好的List
    '''
    if p == q or q == r:
        return List
    ListL = guibing(List, p, (p + q) // 2, q)[p:q]
    ListR = guibing(List, q, (q + r) // 2, r)[q:r]
    print(ListL, ListR)
    ListL.append(1000)
    ListR.append(1000)
    L, R = 0, 0
    list_return = []
    while L < q - p or R < r - q:
        if ListL[L] < ListR[R]:
            list_return.append(ListL[L])
            L += 1
        else:
            list_return.append(ListR[R])
            R += 1
    list_return = List[:p] + list_return + List[r:]
    print(list_return)
    print('-'*80)
    return list_return


guibing([2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 56, 25, 56, 34], 1, 8, 15)

        输出:

[5] [3]
[2, 42, 3, 5, 44, 53, 4, 7, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[42] [3, 5]
[2, 3, 5, 42, 44, 53, 4, 7, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[44] [53]
[2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[4] [7]
[2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[44, 53] [4, 7]
[2, 42, 5, 3, 4, 7, 44, 53, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[3, 5, 42] [4, 7, 44, 53]
[2, 3, 4, 5, 7, 42, 44, 53, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[4] [83]
[2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[9] [4, 83]
[2, 42, 5, 3, 44, 53, 4, 7, 4, 9, 83, 56, 25, 56, 34]
--------------------------------------------------------------------------------
[56] [25]
[2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 25, 56, 56, 34]
--------------------------------------------------------------------------------
[56] [34]
[2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 56, 25, 34, 56]
--------------------------------------------------------------------------------
[25, 56] [34, 56]
[2, 42, 5, 3, 44, 53, 4, 7, 9, 4, 83, 25, 34, 56, 56]
--------------------------------------------------------------------------------
[4, 9, 83] [25, 34, 56, 56]
[2, 42, 5, 3, 44, 53, 4, 7, 4, 9, 25, 34, 56, 56, 83]
--------------------------------------------------------------------------------
[3, 4, 5, 7, 42, 44, 53] [4, 9, 25, 34, 56, 56, 83]
[2, 3, 4, 4, 5, 7, 9, 25, 34, 42, 44, 53, 56, 56, 83]
--------------------------------------------------------------------------------

进程已结束,退出代码为 0

        很容易看到列表长度的变化,和按次序插入的过程。

        分治法解决问题的步骤:

        分解:分解原问题成若干个子问题

        解决:求解子问题,如果子问题的规模足够小就直接求解

        合并:将子问题合并成原问题的解。

        通过这样的递归方法,我们可以看到,一个排序问题会被转化为2个规模是原来一半大小的排序问题,最终按照指数形式被分解成很多个规模为1的问题。很容易猜到算法的复杂度应该是一个和对数相关的算式。事实上是O(nlgn)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

《算法导论》第2章 算法基础(插入排序、归并排序、复杂度计算) 的相关文章

  • Collections类 [Java]

    Collections工具类 Collections是一个操作Collection集合和Map集合的工具类 Collections不仅仅是操作Collection集合 还可以操作Map集合 Collection和Collections有什么
  • 我阿里P7了解到的Android面试的一些小内幕!已拿offer

    前言 这些题目是网友去百度 小米 乐视 美团 58 猎豹 360 新浪 搜狐等一线互联网公司面试被问到的题目 熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率 欢迎一线公司员工以及网友提交面试题库 xff0c 欢迎留言 网上的都是按
  • 7月编程排行榜来啦!这次有何新变化?

    每月编程排行榜可能会迟到 xff0c 但永远不缺席 7月的编程排行榜已出 xff0c 接下来一起看看有哪些看点吧 Tiobe编程排行榜前20名 Tiobe编程排行榜Top 10趋势 TIOBE Index编程社区指数是编程语言流行度的一个指
  • 操作系统 记录型信号量实现生产者消费者问题(完整代码)

    问题描述 用信号量模拟生产者 消费者问题的过程 生产者和消费者两个线程共享同一个缓冲区 xff0c 生产者不断向缓冲区中添加产品 xff0c 消费者从缓冲区中消费产品 要保证缓冲区满了之后生产者不能再继续添加产品 xff0c 需要等消费者至
  • 制版经验分享—使用AD18

    文章目录 前言一 封装二 走线三 注意细节四 制版流程五 制版细节总结 前言 在做一些培训题目时 xff0c 由于时间有限制 xff0c 在外面开板会花费好几天的制作和快递时间 xff0c 所以有时候就需要自己制版 xff0c 在这里我记录
  • Java打印九九乘法表

    1 使用双重for循环打印九九乘法表 Java源代码如下 xff1a for int i 61 0 i lt 61 9 i 43 43 for int j 61 1 j lt 61 i j 43 43 System out print i
  • 解决selenium打开Chrome浏览器自动退出的问题

    好不容易安装好selenium和对应的浏览器驱动器后终于可以运行程序了 xff0c 结果发现一运行程序后浏览器打开就自动退出了 xff0c 但是我在Python代码中并没有写driver quit 方法 xff0c 上网查了查发现原来是我的
  • 在Java应用中嵌入sshd服务

    这个应用需要依赖apache mina的子项目sshd xff0c 项目主页http mina apache org sshd project index html xff0c 当前版本号为0 8 0 这里的sshd和Linux下的sshd
  • openssl开发库安装时的踩坑指南

    序 前几天用linux编译一个提权脚本的时候报错 openssl opensslv h 没有那个文件或目录 的问题 无论如何也解决不了 xff0c 这下我记录一个踩坑指南防止下一个人掉进坑里 操作 总体介绍 首先介绍一下 xff0c 这个报
  • 性能测试脚本用例【模板】

    产品名称Product name 密级Confidentiality level 秘密 产品版本Product version Total 12pages 共12页 性能测试脚本用例 仅供内部使用 拟制 日期 xff1a 审核 日期 xff
  • Java常见的集合类

    我们常见的Java集合类有List Set Map List 1 接口可以被继承 2 接口可以被多次实现 3 List和ArrayList package List import java util ArrayList import jav
  • WIN7我的电脑右键管理打不开

    问题现象 xff1a 我的电脑右键点击管理无法正常打开 xff0c 会弹出下面的报错信息 首先打开注册表 xff0c 打开运行 xff0c 输入regedit 选择路径 xff1a HKEY LOCAL MACHINE SOFTWARE C
  • LIKE的用法

    我们来谈谈关于like运算符的理解 xff1a 下面是like的语法 xff0c 以后使用到like运算符的都必须根据这个语法使用 LIKE 运算符是用来匹配通配符指定模式的文本值 如果搜索表达式与模式表达式匹配 xff0c LIKE 运算
  • 从0开始详细安装archlinux(UEFI启动)

    隔了一周没更新 xff0c 前阵子把电脑windows卸了装了个archlinux xff0c 不得不说arch是真的香 xff0c 但是坑也是真的多 xff0c 刚踩完所有的坑 xff0c 滚回来写blog了 注 xff1a 本贴为UEF
  • archlinux开机无法联网问题,以及安装archlinuxcn和yay管理器

    前一篇已经安装完了archlinux系统 xff0c 不过真正难的其实并不是安装 xff0c 你的路现在才开始 xff0c 哈哈 添加用户 建议 xff0c 不然使用登录管理器的时候不支持root用户 span class token fu
  • archlinux安装kde桌面和sddm登录管理器

    前几篇已经配置好了archlinuxcn软件仓库 xff0c 网络和nvidia驱动 xff0c 现在来给你的archlinux安装一个kde桌面 xff08 kde玩法有很多 xff0c 可以自己去搜一搜美化教程 xff09 xff0c
  • Spring框架学习

    目录 目录 学习内容 xff1a IoC java中创建对象有哪些方式 xff1a ioc的体现 xff1a DI 是ioc的技术实现 spring的第一个核心功能 ioc Spring 八大模块 Spring的特点 xff1a Sprin
  • CenOs6.7不能使用yum命令

    因为官方不维护了所以 先用更换源 wget O etc yum repos d CentOS Base repo https mirrors aliyun com repo Centos vault 6 10 repo https deve
  • PowerMock注解PowerMockIgnore的使用方法

    故事要从一个异常开始 xff0c 某天我在开发一个加密 解密特性 xff0c 算法使用的是3DES xff0c 样例代码如下 package org jackie study powermock import java io Unsuppo
  • 如何写一棵AVL树

    二叉查找树 二叉查找树有一个缺陷就是查询效率跟树的高度有关 在极端情况下 xff0c 查询效率为n 如何解决二叉查找树效率低问题 xff1f 要增加查询效率 xff0c 高效的方案是在插入的时候对树进行一下平衡操作 xff0c 降低树的高度

随机推荐