极客时间:数据结构与算法之美【文章笔记 实践 总结】

news2025/2/22 17:15:36

原文链接:https://time.geekbang.org/column/intro/100017301

  • 27 | 递归树:如何借助树来求解递归算法的时间复杂度?
    • 如何借助树来分析归并排序算法的时间复杂度?
    • 如何借助树来分析快速排序算法的时间复杂度?
    • 如何借助递归树来分析斐波那契数列的时间复杂度?
    • 如何借助递归树来分析全排列的时间复杂度?
    • 1 个细胞的生命周期是 3 小时,1 小时分裂一次。求 n 小时后,容器内有多少细胞?如何分析递归时间时间复杂度?
  • 28 | 堆和堆排序:为什么说堆排序没有快速排序快?
    • 如何理解 "堆"?
    • 如何实现一个堆?
      • 如何存储一个堆?
      • 堆支持哪些操作?
        • 插入元素
        • 删除堆顶元素
    • 如何基于堆实现排序?
      • 建堆
      • 排序
    • 解答开篇
    • 内容小结
    • 课后思考
  • 29 | 堆的应用:如何快速获取到Top 10最热门的搜索关键词?

27 | 递归树:如何借助树来求解递归算法的时间复杂度?

如何借助树来分析归并排序算法的时间复杂度?

归并排序递归树
每次分解一分为二,代价很低,时间上消耗记作O(1)。
每一层合并消耗时间相同,和数据规模相关,记作 O(n)。
归并排序递归树是一颗满二叉树,高度为 log2n。
归并排序时间复杂度:O(n logn)。

如何借助树来分析快速排序算法的时间复杂度?

平均情况:1 : k
k = 9 时。

快速排序递归树

每一层遍历 n 个元素。
快速排序结束条件:叶子节点 1 个元素。
根节点 n 个元素到叶子节点 1 个元素最短路径每一层乘 1 /10,最长路径每一层乘 9 / 10。
根节点到叶子节点最短路径:log10n,最长路径 log(10 / 9 ) n。
遍历个数在 n * log10 到 n * log(10 / 9 ) n 之间,快速排序时间复杂度为:O(n logn)。

k 的值不随 n 改变,对最终时间复杂度无影响。

如何借助递归树来分析斐波那契数列的时间复杂度?

斐波那契数列的递归树

f(n) 分解为 f(n - 1) 和 f(n - 2),每次数据规模 -1 或 -2,叶子节点数据规模是 1 或者 2。
根节点到叶子节点最长为 n ,最短为 n / 2。
合并的操作只需要一次加法运算,耗时记作 O(1)。
每一层消耗时间为 2^ (k - 1) ,路径长度为 n 总和为 2^n - 1。
在这里插入图片描述
路径长度为 n 总和为 2^(n / 2) - 1。
在这里插入图片描述
时间复杂度为指数级别。

如何借助递归树来分析全排列的时间复杂度?

最后一位有 n 种情况,求解 n 个 “n - 1数据的排列” 的子问题。

递推公式:

假设数组中存储的是123...n。
        
f(1,2,...n) = {最后一位是1, f(n-1)} + {最后一位是2, f(n-1)} +...+{最后一位是n, f(n-1)}

全排列

第一层有 n 此交换,第二层有 n (n - 1) 次交换,第三层有 n(n - 1)(n - 2) 此交换,最后一层有 n(n - 1)(n - 2) *…21 次交换。

总交换次数:

n + n*(n-1) + n*(n-1)*(n-2) +... + n*(n-1)*(n-2)*...*2*1
n*(n-1)*(n-2)*...*2*1 为 n!

总和小于 n * n!,全排列递归时间复杂度大于O(n!),小于O(n * n!)。时间复杂度非常高。

1 个细胞的生命周期是 3 小时,1 小时分裂一次。求 n 小时后,容器内有多少细胞?如何分析递归时间时间复杂度?

需要重新系统完整的分析。

28 | 堆和堆排序:为什么说堆排序没有快速排序快?

特殊的树:堆(Heap)。
堆排序:原地排序,时间复杂度为O(n logn)。

如何理解 “堆”?

堆满足的条件是什么?(2个)

  • 堆是一个完全二叉树。(除了最后一层,其他层节点个数都是满的,最后一层的节点都靠左排列。)
  • 堆中每个节点的值都大于等于[大顶堆](或小于等于[小顶堆])其左右子节点的值。

定义堆

1 和 2是大顶堆,3是小顶堆,4不是堆。

如何实现一个堆?

如何存储一个堆?

完全二叉树用数组存储。

完全二叉树

下标为 i 的左子节点下标为 i * 2,右子节点下标为 i * 2 + 1,父节点为下标 i / 2 的节点。

堆支持哪些操作?

插入元素

往堆中插入一个元素,满足堆的特性,通过堆化实现。堆

从下往上堆化:顺着节点所在的路径,向上或者向下,对比,然后交换。
堆化的详细过程
堆化的代码实现过程:

public class Heap {
  private int[] a; // 数组,从下标1开始存储数据
  private int n;  // 堆可以存储的最大数据个数
  private int count; // 堆中已经存储的数据个数

  public Heap(int capacity) {
    a = new int[capacity + 1];
    n = capacity;
    count = 0;
  }

  public void insert(int data) {
    if (count >= n) return; // 堆满了
    ++count;
    a[count] = data;
    int i = count;
    while (i/2 > 0 && a[i] > a[i/2]) { // 自下往上堆化
      swap(a, i, i/2); // swap()函数作用:交换下标为i和i/2的两个元素
      i = i/2;
    }
  }
 }
删除堆顶元素

把最后一个节点放在堆顶,父子节点对比,不满足父子节点大小关系的,互换两个节点。重复该过程,知道父子节点之间满足大小关系为止。

移除的是数组中最后一个元素,堆化的过程都是数据交换操作,不会出现数组空洞。
删除堆顶元素

代码演示:

public void removeMax() {
  if (count == 0) return -1; // 堆中没有数据
  a[1] = a[count];
  --count;
  heapify(a, count, 1);
}

private void heapify(int[] a, int n, int i) { // 自上往下堆化
  while (true) {
    int maxPos = i;
    if (i*2 <= n && a[i] < a[i*2]) maxPos = i*2;
    if (i*2+1 <= n && a[maxPos] < a[i*2+1]) maxPos = i*2+1;
    if (maxPos == i) break;
    swap(a, i, maxPos);
    i = maxPos;
  }
}

n 个节点的完全二叉树,树高度不会超过 log2n。
堆化时间复杂度和树高度成正比,为O(log n)。
插入元素和删除堆顶元素主要逻辑是堆化,时间复杂度为O(log n)。

如何基于堆实现排序?

时间复杂度稳定为 O(n logn),原地排序算法。

建堆

第一种:在堆中插入一个元素的思路。从前往后处理数组,从下往上堆化。

第二种:从后往前处理数组,每个数据都从上往下堆化。
叶子节点往下堆化只能自己和自己比较,所以从最后一个非叶子节点开始堆化:
从上往下堆化
从上往下堆化

private static void buildHeap(int[] a, int n) {
  for (int i = n/2; i >= 1; --i) {
    heapify(a, n, i);
  }
}

private static void heapify(int[] a, int n, int i) {
  while (true) {
    int maxPos = i;
    if (i*2 <= n && a[i] < a[i*2]) maxPos = i*2;
    if (i*2+1 <= n && a[maxPos] < a[i*2+1]) maxPos = i*2+1;
    if (maxPos == i) break;
    swap(a, i, maxPos);
    i = maxPos;
  }
}

建堆的时间复杂度:
叶子节点不需要堆化,需要堆化的节点从倒数第二层开始。每个节点的堆化过程,比较和交换的节点个数,根节点的高度 k 成正比。

每一层节点个数和对应的高度换出来如下:
节点个数及高度

将每个节点的高度求和,得出的就是建堆的时间复杂度。

每个非叶子节点高度求和:
每个非叶子节点高度求和

把公式左右都乘以 2,就得到另一个公式 S2。我们将 S2 错位对齐,并且用 S2 减去 S1,可以得到 S

结果

通过等比数列求和公式:
等比数列求和

h = log2你,带入公式,S = O(n),建堆时间复杂度为O(n)。

排序

数组中第一个元素,堆顶最大元素和最后一个元素交换,最大元素放到下标为 n 的位置。
将 n - 1 个元素重新构建成堆,再取堆顶元素放到 n - 1 ,一直重复,最后堆中只有下标为 1 的一个元素,排序工作就完成了。

堆排序

代码演示:

// n表示数据的个数,数组a中的数据从下标1到n的位置。
public static void sort(int[] a, int n) {
  buildHeap(a, n);
  int k = n;
  while (k > 1) {
    swap(a, 1, k);
    --k;
    heapify(a, k, 1);
  }
}

原地排序。
建堆时间复杂度为 O(n),排序过程时间复杂度为O(n logn),堆整体的时间复杂度为 O(n logn)。
不稳定排序。

解答开篇

堆排序数据访问方式没有快速排序友好。
快速排序,数据顺序访问,可以有效利用CPU缓存。
堆排序,数据跳着访问。

堆顶节点堆化,会依次访问数组下标1,2,4,8。
堆化

同样的数据,排序过程中,堆排序算法的数据交换次数多于快速排序。
快速排序数据交换次数不会比逆序度多。
堆排序第一步是建堆,建堆会打乱数据原有的先后顺序,导致原数据有序度降低。

堆化后有序度降低

内容小结

堆是一种完全二叉树。
大顶堆和小顶堆。

插入一个数据:新插入元素放到数组最后,从下往上堆化。时间复杂度:O(logn)
删除堆顶元素:将数组中最后一个元素放到堆顶,从上往下堆化。时间复杂度:O(logn)

堆排序:
建堆:将下标从 n / 2 到 1 的节点,依次从上到下堆化操作,将数组中的数据组织成堆这种数据结构。
排序:迭代的将堆顶元素放在堆末尾,将堆大小减一,然后再堆化。重复这个过程,直到堆中只剩下一个元素,整个数组中数据有序。

课后思考

对于完全二叉树来说,下标从 n / 2​+1 到 n 的都是叶子节点,这个结论是怎么推导出来的呢?

关于堆,你还能想到它的其他应用吗?

29 | 堆的应用:如何快速获取到Top 10最热门的搜索关键词?

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

macos (M2芯片)搭建flutter环境

安装的版本3.13.4、电脑上没有安装过android studio、安装过brew 1.在终端运行sudo softwareupdate --install-rosetta --agree-to-license&#xff0c;下图展示安装成功的效果 2.下载以下安装包来获取最新的 stable Flutter SDK 3.解压&#xff0c;⚠️注意下载安装sdk的包名…

沉积物微体古生物鉴定

声明 本文是学习GB-T 42629.4-2023 国际海底区域和公海环境调查规程 第4部分&#xff1a;海洋沉积物物理特性调查. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本文件规定了国际海底区域和公海环境调查中的沉积物组成、物理力学性质、生物…

第二章 进程与线程 十三、进程互斥的软件实现方法(单标志法、双标志先检查、双标志后检查、Peterson算法)

目录 一、单标志法 1、算法思想 2、具体逻辑 二、双标志先检查 1、算法思想 2、具体逻辑 三、双标志后检查 1、算法思想 2、具体逻辑 四、Peterson算法 1、算法思想 2、具体逻辑 五、总结 一、单标志法 1、算法思想 两个进程在访问完临界区后会把使用临界区的权限…

as-if-serial与happens-before原则详解

文章目录 前言详解解决多线程下的问题 Happens-before原则总结as-if-serial语义happens-before的例子 前言 "as-if-serial"原则是Java内存模型中的一个重要概念。该规则规定&#xff1a;不管怎么重排序&#xff08;编译期间的重排序&#xff0c;指令级并行的重排序&…

MYSQL存储引擎基础知识介绍

下面重点介绍几种常用的存储引擎,并对比各个存储引擎之间的区别&#xff0c;以帮助读者理解 不同存储引擎的使用方式。 MyISAM MyISAM是 MySQL的默认存储引擎。MyISAM不支持事务、也不支持外键&#xff0c;其优势是访 问的速度快&#xff0c;对事务完整性没有要求或者以 SEL…

怒刷LeetCode的第11天(Java版)

目录 第一题 题目来源 题目内容 解决方法 方法一&#xff1a;迭代 方法二&#xff1a;递归 方法三&#xff1a;指针转向 第二题 题目来源 题目内容 解决方法 方法一&#xff1a;快慢指针 方法二&#xff1a;Arrays类的sort方法 方法三&#xff1a;计数器 方法四…

【Java 基础篇】Java线程组详解

Java线程组是一种用于管理线程的机制&#xff0c;它允许你将线程组化为一个单元&#xff0c;并对组内的线程进行一些操作和控制。本文将详细介绍Java线程组的概念、如何创建和管理线程组&#xff0c;以及线程组的一些常见用法。 什么是线程组&#xff1f; 线程组是一个用于组…

python生成PDF报告

前言 最近接到了一个需求-将项目下的样本信息汇总并以PDF的形式展示出来&#xff0c;第一次接到这种PDF的操作的功能&#xff0c;还是有点慌的&#xff0c;还好找到了reportlab这个包&#xff0c;可以定制化向PDF写内容&#xff01; 让我们由简入深进行讲解 一、reportlab是…

2023年腾讯云轻量服务器测评:16核 32G 28M 配置CPU测试

腾讯云轻量应用服务器16核32G28M配置优惠价3468元15个月&#xff08;支持免费续3个月/送同配置3个月&#xff09;&#xff0c;轻量应用服务器具有100%CPU性能&#xff0c;系统盘为380GB SSD盘&#xff0c;28M带宽下载速度3584KB/秒&#xff0c;月流量6000GB&#xff0c;折合每天…

由于找不到d3dx9_43.dll,无法继续执行代码要怎么解决

D3DX9_43.dll是一个动态链接库文件&#xff0c;它是DirectX的一个组件&#xff0c;主要用于支持一些旧版本的游戏和软件。当电脑缺少这个文件时&#xff0c;可能会导致这些游戏和软件无法正常运行。例如&#xff0c;一些老游戏可能需要D3DX9_43.dll来支持图形渲染等功能。此外&…

二分类问题的解决利器:逻辑回归算法详解(一)

文章目录 &#x1f34b;引言&#x1f34b;逻辑回归的原理&#x1f34b;逻辑回归的应用场景&#x1f34b;逻辑回归的实现 &#x1f34b;引言 逻辑回归是机器学习领域中一种重要的分类算法&#xff0c;它常用于解决二分类问题。无论是垃圾邮件过滤、疾病诊断还是客户流失预测&…

git安装配置教程

目录 git安装配置1. 安装git2. git 配置3.生成ssh key:4. 获取生产的密钥3. gitee或者github添加ssh-key4.git使用5. git 使用-本地仓库与远程仓库建立连接第一步&#xff1a;进入项目文件夹&#xff0c;初始化本地仓库第二步&#xff1a;建立远程仓库。 建立远程连接的小技巧 …

strcpy常见的错误

char* arr "handsome"; strcpy(arr, "pretty"); printf("%s\n", arr); 这个程序在编译器上是运行不出来的&#xff0c;因为arr是一个字符串指针&#xff0c;它的值不可以被修改&#xff0c;可以将arr改成字符数组

录屏没有声音怎么办,3个方法教你解决

随着科技的不断发展&#xff0c;人们越来越依赖电子设备进行工作和学习。在这个过程中&#xff0c;录屏已经成为了一种必要的技能。无论是手机还是电脑&#xff0c;我们都可以通过录屏来记录重要的信息。但是&#xff0c;有时候我们在录屏时会发现声音无法正常录制&#xff0c;…

前后端分离的低代码快速开发框架

低代码开发正逐渐成为企业创新的关键工具。通过提高开发效率、降低成本、增强灵活性以及满足不同用户需求&#xff0c;低代码开发使企业能够快速响应市场需求&#xff0c;提供创新解决方案。选择合适的低代码平台&#xff0c;小成本组建一个专属于你的应用。 项目简介 这是一个…

竞赛 基于深度学习的人脸识别系统

前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的人脸识别系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/…

spring security教程(一)--认证

零.简介 【1】简介 【2】登录校验流程 【3】原理&#xff08;入门的时候先了解一下就好&#xff09; 一.思路分析 二.建表 确保你已经建立好一张用户表&#xff0c;并且引入springboot&#xff0c;mybatis&#xff0c;mp,slf4j等基础依赖。 即使你有多个角色你也可以将他们的…

安装社区版本OB

获取一键安装包 https://www.oceanbase.com/softwarecenter 离线安装 [admintest001 ~]$ tar -xzf oceanbase-all-in-one-*.tar.gz [admintest001 ~]$ cd oceanbase-all-in-one/bin/ [admintest001 bin]$ ./install.sh [admintest001 bin]$ source ~/.oceanbase-all-in-one/…

【人工智能】企业如何使用 AI与人工智能的定义、研究价值、发展阶段的深刻讨论

前言 人工智能&#xff08;Artificial Intelligence&#xff09;&#xff0c;英文缩写为AI。 它是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新的技术科学。人工智能是新一轮科技革命和产业变革的重要驱动力量。 &#x1f4d5;作者简介&#x…

stm32学习-芯片系列/选型/开发方式

【03】STM32HAL库开发-初识STM32 | STM概念、芯片分类、命名规则、选型 | STM32原理图设计、看数据手册、最小系统的组成 、STM32IO分配_小浪宝宝的博客-CSDN博客  STM32&#xff1a;ST是意法半导体&#xff0c;M是MCU/MPU&#xff0c;32是32位。  ST累计推出了&#xff1a…