【Algorithms 4】算法(第4版)学习笔记 02 - 1.4 算法分析

文章目录

    • 前言
    • 参考目录
    • 学习笔记
      • 1:科学方法
      • 2:观察举例:三数之和
      • 3:近似
      • 4:增长数量级
      • 4.1:二分查找 demo
      • 4.2:二分查找代码实现
      • 4.3:二分查找比较次数的证明(比较次数最多为lgN+1)
      • 5:三数之和的优化
      • 5.1:三数之和优化代码实现
      • 6:上下界

前言

经过上一章节对于 union-find 算法的实现以及分析,这一章节主要是对于算法的一些分析以及理论性的总结说明,还包含三数之和的实现以及优化、二分查找的实现以及证明等。

需要说明一下,Sedgewick 教授讲解第一章的顺序不是按照书本的编排顺序,而是先讲了实例,再对算法分析进行总结,然后再到基础理论说明,即 1.5 到 1.4 再到 1.3(1.1 和 1.2 没有讲,主要是 Java 相关的内容,但实际上算法课是没有语言限制的,可能有 Java 基础的话看这本书会比较舒服,但是如果是听教授讲课我觉得影响不大)。

参考目录

  • B站 普林斯顿大学《Algorithms》视频课
    (请自行搜索。主要以该视频课顺序来进行笔记整理,课程讲述的教授本人是该书原版作者之一 Robert Sedgewick。)
  • 微信读书《算法(第4版)》
    (本文主要内容来自《1.4 算法分析》)
  • 官方网站
    (有书本配套的内容以及代码)

学习笔记

注1:下面引用内容如无注明出处,均是书中摘录。
注2:所有 demo 演示均为视频 PPT demo 截图。

1:科学方法

本章开篇首先说明的是应用于算法研究的科学方法以及其原则。

(截图自官方文档)
在这里插入图片描述

(用官网的英文原版是便于直观展示每一个强调的点

再贴一下中译版:

在这里插入图片描述

2:观察举例:三数之和

简单说明一下三数之和,即输入一组整数,需要统计出所有和为 0 的三整数数组的数量。

首先,最容易想到的便是暴力算法。

edu.princeton.cs.algs4.ThreeSum#count

在这里插入图片描述

三重循环,由已有的运行时间记录推算得到的运行时间大致为:

T(N)=9.98×10-11×N3

3:近似

一个程序运行的总时间主要和两点有关:
❏执行每条语句的耗时;
❏执行每条语句的频率。
前者取决于计算机、Java编译器和操作系统,后者取决于程序本身和输入。

我们常常使用约等于号(~)来忽略较小的项,从而大大简化我们所处理的数学公式。该符号使我们能够用近似的方式忽略公式中那些非常复杂但幂次较低,且对最终结果的贡献无关紧要的项。

在这里插入图片描述

4:增长数量级

在这里插入图片描述

表1.4.7 对增长数量级的常见假设的总结
在这里插入图片描述

在增长数量级这一节中,主要以二分查找来进行说明。

4.1:二分查找 demo

简单说明二分查找的demo:

给定一个排序好的数组以及一个key,查到key在数组中的下标。

实现方式:

二分查找:循环比较key和数组中间的元素

  • 如果key小,往左;
  • 如果key大,往右;
  • 相等,返回。

在一组排序好的数字中找到整数 33 的下标:

在这里插入图片描述

4.2:二分查找代码实现

edu.princeton.cs.algs4.BinarySearch#indexOf

在这里插入图片描述

4.3:二分查找比较次数的证明(比较次数最多为lgN+1)

先看下教授给出的证明方式:

在这里插入图片描述

但是吧,我数学真的一般般,所以我又去问了一下通义,所幸看懂了它给出的证明步骤:

(格式有点问题,我就直接贴原文了,有些描述进行了修改)

二分查找(Binary Search)在每次迭代中都会将搜索范围减半,直到找到目标值或者搜索范围缩小到不存在为止。假设我们有一个包含n个元素的有序数组(比如升序排列),初始搜索范围是整个数组,即从索引0到n-1。

证明步骤:

  1. 初始化比较次数k=0,表示开始时还未进行任何比较。

  2. 每次迭代,我们将当前搜索区间划分为两半,取中间元素与目标值进行比较。如果相等,则找到了目标值并停止搜索;如果不相等,根据比较结果舍弃一半区间(不包含目标值的那一半)。

  3. 由于每次比较后至少会排除掉原来区间的一半,因此,在第k次迭代后剩余的区间长度为 n 的 部分。

    对于长度n的数组,k=0是,剩余部分为 1/(20) = 1;
    以此类推,剩余部分为 1/(21) = 1/2;1/(22) = 1/4;1/8;1/16……

  4. 我们的目标是确定最大的比较次数,使得剩下的区间长度为1(即只剩一个元素或刚好找到目标值)。这意味着:
    n / 2 k = 1 n/2^k=1 n/2k=1

  5. 解这个方程得到:
    k = l o g 2 ( n ) k = log~2~(n) k=log 2 (n)

  6. 因为实际情况下k必须是整数,并且计算机程序中通常使用向下取整来决定迭代次数,所以实际上最大迭代次数是。

  7. 但是,当 log2(n) 不是整数时,需要再进行一次迭代以确定最后一个元素是否为目标值,所以总共的最大比较次数应该是向下取整的基础上加1
    最大比较次数 = ⌊ log ⁡ 2 ( n ) ⌋ + 1 最大比较次数= \lfloor \log_2(n) \rfloor + 1 最大比较次数=log2(n)⌋+1

  8. 这意味着对于任意大小为n的有序数组,最多需要执行第 7 点中计算得到的比较次数就能确定目标值是否存在。

5:三数之和的优化

对于 2 中三数之和的暴力算法,这里提出了一种利用二分查找进行优化的方法:

在这里插入图片描述

  • 升序排列非重复的一组数字
  • 对于每一对组合 a[i]a[j],利用二分查找寻找是否存在 -(a[i]+a[j])

5.1:三数之和优化代码实现

edu.princeton.cs.algs4.ThreeSumFast#count

在这里插入图片描述

6:上下界

这一部分属于理论性比较强的内容,主要是说明了这个概念对于算法研究的必要性。

在这里插入图片描述

同样贴一下通义关于上下界概念的说明,便于理解:

算法上下界是指在分析算法性能时,对算法执行时间或空间复杂度的一个范围的界定。这个范围可以帮助我们更好地了解算法在不同情况下的表现,并对算法进行更全面的评估。

  1. 算法上界(Upper Bound):

    • 定义:算法在最坏情况下的执行时间或空间复杂度的一个上限。
    • 作用:提供了算法性能的悲观估计。上界告诉我们,在最不利的情况下,算法的性能不会超过这个值。这对于确保算法在任何情况下都能在合理的时间内完成任务很有帮助。
  2. 算法下界(Lower Bound):

    • 定义:算法在最好情况下的执行时间或空间复杂度的一个下限。
    • 作用:提供了算法性能的乐观估计。下界告诉我们,在最理想的情况下,算法的性能不会低于这个值。这对于了解算法的优势和在最优情况下能够达到的极限非常重要。
  3. 平均情况复杂度:

    • 平均情况复杂度考虑了算法在所有可能输入下的性能。它可以被视为上界和下界的平均值。

在分析算法性能时,我们通常关注最坏情况下的上界,因为这提供了对算法在任何情况下的性能都足够保守的估计。同时,下界可以帮助我们了解算法的潜在优势。

作用:

  1. 性能保证: 算法上界提供了对算法在最坏情况下性能的保证,这对于实际应用中的稳定性和可靠性至关重要。

  2. 算法选择: 在设计和选择算法时,我们可以根据算法的上下界来判断它是否满足问题的要求。较低的上界和较高的下界通常是理想选择的标志。

  3. 问题难度: 下界可以用来表征特定问题的难度。如果一个问题的下界很高,说明在任何情况下找到更好的算法可能是困难的。

  4. 理论研究: 上下界有助于理论计算机科学的研究,因为它们提供了对问题复杂性的深刻理解,而不仅仅是特定算法的表现。

总体来说,算法上下界的定义和分析有助于我们更全面地理解算法的性能,并在设计和选择算法时做出明智的决策。

(完)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/443245.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

知识推理的多重途径

目录 前言1 逻辑及推理简介2 演绎推理:Top-Down Logic2.1 肯定前件假言推理2.2 否定后件假言推理2.3 演绎推理的逻辑链条 3 归纳推理:Bottom-Up Logic3.1 从特例到一般3.2 逐步推导的过程 4 溯因推理:结果的可解释逻辑4.1 推断过程的回溯4.2 …

西瓜书读书笔记整理(十二) —— 第十二章 计算学习理论(下)

第十二章 计算学习理论(下) 12.4 VC 维(Vapnik-Chervonenkis dimension)12.4.1 什么是 VC 维12.4.2 增长函数(growth function)、对分(dichotomy)和打散(shattering&…

[Java 并发基础]多线程编程

文章参考: https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html https://juejin.cn/post/6970558076642394142 文章目录 线程的创建方式继承 Thread实现 Runnable 接口实现 Callable 接口使用 Lambda使用线程池 线程创建相关的 jdk源码Thr…

“死“社群先不要扔,想办法激活一下,隔壁的运营都馋哭了

私域运营已成为当下很多企业寻求增长的标配。在这过程中,社群运营就是极为重要的一个环节。过去我们为了流量,疯狂建群拉人。但建社群容易活跃难,活跃一段时间后,社群会越来越安静。 不仅如此,群主和管理员也渐渐疏于…

优化器刺客之limit 1--Order by col limit n 代价预估优化探索

一、现象 order by 排序加了limit后更慢了? test# explain analyze select userid from dba_users where username like %aaaaaaaaaaaaaaaaaa% order by userid ;QUERY PLAN --------------…

CentOS7中安装ElasticSearch

文章目录 检测是否安装了Elasticsearch安装JDK下载java配置 下载Elasticsearch解压安装Elasticsearch修改配置文件启动Elasticsearch常见问题 ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasti…

【数据结构 02】队列

一、原理 队列通常是链表结构,只允许在一端进行数据插入,在另一端进行数据删除。 队列的特性是链式存储(随机增删)和先进先出(FIFO:First In First Out)。 队列的缺陷: 不支持随机…

【C/C++】C/C++编程——整型(一)

整型 C 中的整型是基本的数据类型之一,用于表示没有小数部分的数。这包括正整数、负整数以及零。C 提供了多种整型,以适应不同大小的数值需求和优化内存使用。 整型的种类 C 中的整型可以根据其大小(即占用的字节数)和能够表示…

方法阻塞的解决方案之一

1、简单使用 一个h一个cpp文件 #pragma once #include <iostream> #include <thread> #include <atomic> #include <chrono> #include <string>class Person {public:struct dog {std::string name;int age;};public:void a(std::atomic<bo…

笔记本从零安装ubuntu server系统+环境配置

文章目录 前言相关链接ubuntu Server 安装教程屏幕自动息屏关上盖子不休眠MobaXterm外网SSH内网穿透IPV6远程 为什么我要笔记本装Linux为什么要换ubuntu Server版能否连接wifi之后Linux 配置清单总结 前言 之前装了个ubuntu desktop 版&#xff0c;发现没有命令行&#xff0c;…

《HTML 简易速速上手小册》第4章:HTML 的表单与输入(2024 最新版)

文章目录 4.1 表单的基础&#xff08;&#x1f4dd;&#x1f680;&#x1f4ac; 开启沟通的大门&#xff09;4.1.1 表单基础知识点4.1.2 基础示例&#xff1a;创建一个简单的注册表单4.1.3 案例扩展一&#xff1a;创建一个调查问卷4.1.4 案例扩展二&#xff1a;创建一个预订表单…

【01】Linux 基本操作指令

带⭐的为重要指令 &#x1f308; 01、ls 展示当前目录下所有文件&#x1f308; 02、pwd 显示用户当前所在路径&#x1f308; 03、cd 进入指定目录&#x1f308; 04、touch 新建文件&#x1f308; 05、tree 以树形结构展示所有文件⭐ 06、mkdir 新建目录⭐ 07、rmdir 删除目录⭐…