JavaScript二叉树及各种遍历算法详情

news2024/12/23 22:23:44
目录
  • 什么是二叉树
    • 满二叉树
    • 完全二叉树
  • 二叉树的存储
    • 数组存储
    • 链表存储
  • 与二叉树相关的算法
    • 深度优先遍历
    • 广度优先遍历
    • 先序遍历
    • 中序遍历
    • 后序遍历

前言:

上一篇文章中介绍了树的概念、深度优先遍历和广度优先遍历,这篇文章我们来学习一个特殊的树——二叉树。

什么是二叉树

二叉树是每个节点最多只能有两个子节点的树,如下图所示:

一个二叉树具有以下几个特质:

  • i层的节点最有只有2^(i-1)个;
  • 如果这颗二叉树的深度为k,那二叉树最多有2^k-1个节点;
  • 在一个非空的二叉树中,若使用n0表示叶子节点的个数,n2是度为2的非叶子节点的个数,那么两者满足关系n0 = n2 + 1

满二叉树

如果在一个二叉树中,除了叶子节点,其余的节点的每个度都是2,则说明该二叉树是一个满二叉树

如下图所示:

满二叉树除了满足普通二叉树特质,还具有如下几个特质:

  • 满二叉树的的第n层具有2^(n-1)个节点;
  • 深度为k的满二叉树一定存在2^k-1个节点,叶子节点的个数为2^(k-1)
  • 具有n个节点的满二叉树的深度为log_2^(n+1)

完全二叉树

如果一个二叉树去掉最后一次层是满二叉树,且最后一次的节点是依次从左到右分布的,则这个二叉树是一个完全二叉树,

如下图所示:

二叉树的存储

存储二叉树的常见方式分为两种,一种是使用数组存储,另一种使用链表存储。

数组存储

使用数组存储二叉树,如果遇到完全二叉树,存储顺序从上到下,从左到右,如下图所示:

如果是一个非完全二叉树,如下图所示:

需要先将其转换为完全二叉树,然后在进行存储,如下图所示:

可以很明显的看到存储空间的浪费。

链表存储

使用链表存储通常将二叉树中的分为3个部分,如下图:

这三个部分依次是左子树的引用,该节点包含的数据,右子树的引用,存储方式如下图所示:

与二叉树相关的算法

以下算法中遍历用到的树如下

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

// tree.js

const bt = {

  val: 'A',

  left: {

    val: 'B',

    left: { val: 'D', left: null, right: null },

    right: { val: 'E', left: null, right: null },

  },

  right: {

    val: 'C',

    left: {

      val: 'F',

      left: { val: 'H', left: null, right: null },

      right: { val: 'I', left: null, right: null },

    },

    right: { val: 'G', left: null, right: null },

  },

}

module.exports = bt

深度优先遍历

二叉树的深度优先遍历与树的深度优先遍历思路一致,思路如下:

  • 访问根节点;
  • 访问根节点的left
  • 访问根节点的right
  • 重复执行第二三步

实现代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

const bt = {

  val: 'A',

  left: {

    val: 'B',

    left: { val: 'D', left: null, right: null },

    right: { val: 'E', left: null, right: null },

  },

  right: {

    val: 'C',

    left: {

      val: 'F',

      left: { val: 'H', left: null, right: null },

      right: { val: 'I', left: null, right: null },

    },

    right: { val: 'G', left: null, right: null },

  },

}

function dfs(root) {

  if (!root) return

  console.log(root.val)

  root.left && dfs(root.left)

  root.right && dfs(root.right)

}

dfs(bt)

/** 结果

A B D E C F H I G

*/

广度优先遍历

实现思路如下:

  • 创建队列,把根节点入队
  • 把对头出队并访问
  • 把队头的leftright依次入队
  • 重复执行2、3步,直到队列为空

实现代码如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

function bfs(root) {

  if (!root) return

  const queue = [root]

  while (queue.length) {

    const node = queue.shift()

    console.log(node.val)

    node.left && queue.push(node.left)

    node.right && queue.push(node.right)

  }

}

bfs(bt)

/** 结果

A B C D E F G H I

 */

先序遍历

二叉树的先序遍历实现思想如下:

  • 访问根节点;
  • 对当前节点的左子树进行先序遍历;
  • 对当前节点的右子树进行先序遍历;

如下图所示:

递归方式实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

const bt = require('./tree')

function preorder(root) {

  if (!root) return

  console.log(root.val)

  preorder(root.left)

  preorder(root.right)

}

preorder(bt)

/** 结果

A B D E C F H I G

*/

迭代方式实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

// 非递归版

function preorder(root) {

  if (!root) return

  // 定义一个栈,用于存储数据

  const stack = [root]

  while (stack.length) {

    const node = stack.pop()

    console.log(node.val)

    /* 由于栈存在先入后出的特性,所以需要先入右子树才能保证先出左子树 */

    node.right && stack.push(node.right)

    node.left && stack.push(node.left)

  }

}

preorder(bt)

/** 结果

A B D E C F H I G

*/

中序遍历

二叉树的中序遍历实现思想如下:

  • 对当前节点的左子树进行中序遍历;
  • 访问根节点;
  • 对当前节点的右子树进行中序遍历;

如下图所示:

递归方式实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

const bt = require('./tree')

// 递归版

function inorder(root) {

  if (!root) return

  inorder(root.left)

  console.log(root.val)

  inorder(root.right)

}

inorder(bt)

/** 结果

D B E A H F I C G

*/

迭代方式实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

// 非递归版

function inorder(root) {

  if (!root) return

  const stack = []

  // 定义一个指针

  let p = root

  // 如果栈中有数据或者p不是null,则继续遍历

  while (stack.length || p) {

    // 如果p存在则一致将p入栈并移动指针

    while (p) {

      // 将 p 入栈,并以移动指针

      stack.push(p)

      p = p.left

    }

    const node = stack.pop()

    console.log(node.val)

    p = node.right

  }

}

inorder(bt)

/** 结果

D B E A H F I C G

*/

后序遍历

二叉树的后序遍历实现思想如下:

  • 对当前节点的左子树进行后序遍历;
  • 对当前节点的右子树进行后序遍历;
  • 访问根节点;

如下图所示:

递归方式实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

const bt = require('./tree')

// 递归版

function postorder(root) {

  if (!root) return

  postorder(root.left)

  postorder(root.right)

  console.log(root.val)

}

postorder(bt)

/** 结果

D E B H I F G C A

*/

迭代方式实现如下:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

// 非递归版

function postorder(root) {

  if (!root) return

  const outputStack = []

  const stack = [root]

  while (stack.length) {

    const node = stack.pop()

    outputStack.push(node)

    // 这里先入left需要保证left后出,在stack中后出,就是在outputStack栈中先出

    node.left && stack.push(node.left)

    node.right && stack.push(node.right)

  }

  while (outputStack.length) {

    const node = outputStack.pop()

    console.log(node.val)

  }

}

postorder(bt)

/** 结果

D E B H I F G C A

*/

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

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

相关文章

【计算机图形学】期末复习,选择题+判断题篇

【计算机图形学】期末复习,选择题判断题篇 题目来源于百度、B站、中国大学慕课网,适用于期末复习,内容仅供参考,祝大家考试顺利通过!!! 文章目录 【计算机图形学】期末复习,选择题判…

App压力稳定性测试之Monkey

目录 前言: 一、Monkey简介 二、monkey常见命令 三、日志导出 前言: Monkey测试是一种黑盒测试方法,用于测试Android应用程序的压力稳定性,目的是评估应用在极端情况下是否能够稳定、可靠地工作。它是Android SDK自带的一个工…

起动元件框图原理

(一)起动元件作用 为了提高保护动作的可靠性,保护装置的出口均经起动元件闭锁,只有在保护起动元 件起动后,保护装置出口闭锁才被解除。在微机保护装置里,起动元件是由软件来完成的。起动元件起动后&#…

鞣花酸爆增1226%?油橄榄、雪绒花大展拳脚? | 5月功效成分TOP100

数说故事联合用户说共创的5月功效成分榜单如约而至。 本期依旧是你最关注的两大榜单:5月用户最关注功效成分声量TOP100和5月用户最关注功效成分变量TOP100。 榜单通过整合全网社交媒体的声量,并构建指数体系,实时动态监控互联网关键成分的声…

RabbitMQ消息队列的工作模式

文章目录 1.RabbitMQ常用的工作模式2.简单模式3.WorkQueues工作队列模式4.Pub/Sub发布订阅模式5.Routing路由模式6.Topics通配符模式 1.RabbitMQ常用的工作模式 官方文档地址:https://www.rabbitmq.com/getstarted.html 工作模式其实就是消息队列分发消息的路由方…

mysql死锁问题分析

死锁问题分析 起因 起因是线上报了一个死锁问题,然后我就去查看下死锁的原因。 思路 死锁问题的排查, **日常工作中,应对各类线上异常都要有我们自己的 SOP (标准作业流程) ** ,这样不仅能够提高自己的处理问题效率&#xff…

智能本质上是人性的拓扑

智能技术的发展是基于人类智慧和思维方式的延伸和拓展,人类的智慧和思维方式是智能的基础,人类是智能技术的创造者和主导者。然而,人工智能技术却与人性并不一致,根本上,人工智能技术并不具备人类的情感、道德、意识等…

适配器模式(Adapter)

定义 适配器是一种结构型设计模式,它能使接口不兼容的对象能够相互合作。 别名 封装器模式(Wrapper)。 前言 1. 问题 假如你正在开发一款股票市场监测程序,它会从不同来源下载 XML 格式的股票数据,然后向用户呈现…

通过skia导出pdf 生成超链接 skia pdfdocument annotation pdflink

如题 最近导出pdf ,想实现文本支持超链接跳转, 看了下skia的官网文档, 翻墙找各种资料 就是找不到关于怎么实现,毫无头绪咋办呢 我想了一下 1.粗略翻阅了下pdf的格式 了解了下基本的构成 啥root page text 啥的 2.通过pdf格式了解到 链接是通过LinkAn…

npm发布自己的公网包步骤详解

初始化项目 比如我,创建了code-transfor-text_vue项目 根目录初始化git git init .建立开源协议 给项目根目录手动创建LICENSE文件文件,没有后缀名 MIT LicenseCopyright (c) 2023 quanyiPermission is hereby granted, free of charge, to any pers…

Verdaccio搭建本地npm仓库

背景 Verdaccio 是一个 Node.js创建的轻量的私有npm proxy registry 我们在开发npm包的时候,经常需要验证发包流程,或者开发的npm包仅局限于公司内部使用时,就可以借助Verdaccio搭建一个npm仓库,搭建完之后,只要更改np…

DataLeap的全链路智能监控报警实践(二):概念介绍

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 概念介绍 基线监控 根据监控规则和任务运行情况,DataLeap的基线监控能够决策是否报警、何时报警、如何报警以及给谁报警。它保障的是任务整体产出链路&a…

MySQL 数据库操作指南:学习如何使用 Python 进行增删改查操作

文章目录 MySQL 知识点1.1 数据库创建和选择1.2 数据表创建和修改1.3 插入数据1.4 查询数据1.5 更新和删除数据 1.6 索引的创建和使用1.7 外键的使用 Python 中使用 MySQL2.1 连接数据库2.2 创建数据库和数据表2.3 插入数据2.4 查询数据2.5 更新和删除数据2.6 关闭连接 2.7 数据…

【算法系列之贪心算法I】leetcode376. 摆动序列

455.分发饼干 力扣题目链接 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j&…

详细讲解!接口性能测试方案

目录 前言: 性能测试术语解释 性能测试方法及目标 性能需求分析 性能测试范围 性能测试用例与场景 性能测试工具选择 性能测试结果分析 性能测试通过标准 前言: 接口性能测试是指测试系统中各个接口的性能,包括响应时间、吞吐量、并…

现在企业都在强调的客户体验,如何从官网帮助文档入手?

在当前激烈的市场竞争中,企业已经逐渐意识到客户体验的重要性。客户体验是指通过产品和服务所提供的一系列互动和接触,客户对企业的全面感受和评价。而在客户体验中,官网帮助文档作为企业与客户之间互动的重要环节,也扮演着重要的…

性能测试之测试指标

目录 前言 系统性能指标 资源指标 中间件指标 数据库指标 前端指标 稳定性指标 批量处理指标 可扩展性指标 可靠性指标 前言 性能测试是测试一个系统在特定条件下的响应时间、并发用户数、吞吐量、内存使用率、CPU利用率、网络延迟等各项指标的过程。测试指标是根据…

Alibaba Cloud Linux 3.2104 LTS 64位 安装lnmp环境php8、mysql8

Alibaba Cloud Linux 3.2104 LTS 64位服务器安装lnmp环境全过程 以下都为阿里云购买的服务器为例 前言 购买了阿里云的服务器之后切记切记切记! 第一步设置:更多> 网络和安全组> 安全组配置>入方向 第二步 设置root账户的密码(如…

如何在矩池云复现开源对话语言模型 ChatGLM

ChatGLM-6B 是一个开源的、支持中英双语的对话语言模型,基于 General Language Model (GLM) 架构,具有 62 亿参数。结合模型量化技术,用户可以在消费级的显卡上进行本地部署(INT4 量化级别下最低只需 6GB 显存)。 Chat…

ART-Pi BT_WiFi 模块固件下载

源文件《UM5003-RT-Thread ART-Pi BT_WIFI 模块固件下载手册.md》 ART-Pi BT_WiFi 模块固件下载 ART-Pi 板卡在出厂时已经烧录过 BT_WiFi 固件,存储在外部 Flash。如果固件被不慎擦除,会导致 BT_WiFi 模组的功能无法正常使用,出现异常情况&…