链表 - 二叉树

树节点类型

class TreeNode {
    value: number
    left?: TreeNode
    right?: TreeNode
    constructor(value: number, left?: TreeNode, right?: TreeNode){
        this.value = value;
        this.left = left;
        this.right = right;
    }
}
// 简写
class TreeNode {
    constructor(public value: number,public  left?: TreeNode,public  right?: TreeNode){
    }
}
二叉树:一个节点最多有两个子节点
  • 高度Height:节点到叶子节点的最长路径(从下到上)
  • 深度Depth:根节点到这个节点所经历的边的个数(从上到下)
  • 层Level:节点的深度 + 1(计数起点为1)

二叉树:一个节点最多有两个子节点(完全二叉树、满二叉树)

如何存储
  • 链式存储
  • 顺序存储
    如何构建一个二叉树,从根节点开始创建时不知道他对应的左树和右树,即new一个class,不好传参。

可以考虑从最底部的节点开始,直至创建到根节点。

const trees = {
  value: 0,
  left: {
    value: 1,
    left: {
      value: 3
    }
  },
  right: {
    value: 2,
    left: {
      value: 4,
      left: {
        value: 6
      },
      right: {
        value: 7
      }
    },
    right: {
      value: 5
    }
  }
}

const root = new TreeNode(0, new TreeNode(1), new TreeNode(2))

const node5 = new TreeNode(5)
const node7 = new TreeNode(7)
const node6 = new TreeNode(6)
const node6 = new TreeNode(4, node6, node7);

如何遍历上面的树做节点的记录或处理节点数据呢?

广度优先遍历(BFS)Breadth First Search

从树的第一层(根结点)开始,自上至下逐层遍历;在同一层中,按照从左到右的顺序对结点逐一访问。
在这里插入图片描述
代码如下:

function bfs(root: TreeNode) {
// 使用数组模拟队列。首先将根节点归入队列。当队列不为空的时候,执行循环:取出队列的一个节点,如果该结点的左子树为非空,则将该结点的左子树入队列;如果该结点的右子树为非空,则将该结点的右子树入队列。
  const queue: TreeNode[] = [];
  queue.push(root)

  // 从上到下遍历二叉树的每一层
  while (queue.length) {
      const sz = queue.length
      // 从左到右遍历每一层的每个节点
      for (let i = 0; i < sz; i++) {
          const curr = queue.shift()!
          // 访问
          console.log(curr.value)
          // 将下一层节点放入队列
          if (curr.left)
              queue.push(curr.left)
          if (curr.right)
              queue.push(curr.right)
      }
  }
} // 0 > 1 > 2 > 3 > 4 > 5 > 6 > 7

执行后:
在这里插入图片描述

递归遍历/深度优先遍历(DFS)Depth First Search

对每一个可能的分支路径深入到不能再深入为止,而且每个节点只能访问一次.

定义下列字母:
D:访问根结点,L:遍历根结点的左子树,R:遍历根结点的右子树。
根据先访问节点数据定义可以有如下遍历(先左后右):
前序遍历:DLR
中序遍历:LDR
后序遍历:LRD
顺着字母表示的意思念下来就是遍历的顺序了

代码如下:时间复杂度O(n)

  • 前序遍历:DLR
function preOrder(root?: TreeNode) {
    if (!root) return
    console.log(root.value)
    preOrder(root.left)
    preOrder(root.right)
}
// 0 > 1 > 3 > 2 > 4 > 6 > 7 > 5
  • 中序遍历:LDR
function preOrder(root?: TreeNode) {
    if (!root) return
    preOrder(root.left)
    console.log(root.value)
    preOrder(root.right)
} // 3 > 1 > 0 > 6 > 4 > 7 > 2 > 5
  • 后序遍历:LRD
function preOrder(root?: TreeNode) {
    if (!root) return
    preOrder(root.left)
    preOrder(root.right)
    console.log(root.value)
}
// 3 > 1 > 6 > 7 > 4 > 5 > 2 > 0

总结起来就是下面代码,只是处理逻辑的位置不同

function traverse(root?: TreeNode) {
    if (!root) return
    // 前序位置
    traverse(root.left)
    // 中序位置
    traverse(root.right)
    // 后序位置
}

二叉树题型
在这里插入图片描述

无环单连通的树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值