二叉树基础-1

一. 树

树?
树
上面图片所示是是自然树的形态!下图是数据结构中的树,看起来就像倒挂的树(根朝上,叶子朝下)吧!
树结构

看一下定义吧。

树形数据结构是一类重要的非线性数据结构

树形数据结构可以表示数据元素之间一对多的关系。其中以树与二叉树最为常用,直观看来,树是以分支关系定义的层次结构。

节点: 树上每个元素(如:A、B、C、D 节点)
父子关系: 来连接相邻节点之间的关系(如:A 节点和 B 节点之间为父子关系)
父节点和子节点: 相对关系(如:A 节点是 B 节点的父节点,B 节点是 A 节点的子节点)
兄弟节点: 相对关系(如:B、C、D 节点互为兄弟节点)
根节点: 没有父节点的节点(如:E 节点)
叶子节点或者叶节点: 没有子节点的节点(如:G 节点、K 节点)

节点的高度: 节点到叶子节点的最长路径
节点的深度: 节点到根节点的路径长度
节点的层数: 节点的深度 + 1
树的高度: 根节点高度
图例

二. 二叉树

如果一棵树,它的任意一个节点最多有2个节点,那它就是二叉树。

1. 满二叉树

如果一棵二叉树,它的叶子节点全部都在最底层,其它节点都有 2 个节点,那它就是满二叉树。

满二叉树

2. 完全二叉树

如果一棵二叉树,
它的叶子节点全部都在最后 2 层;
最后 1 层的节点全都靠左排列;
除最后 1 层外,其它层的节点树都达到最大,
那它就是完全二叉树。
完全二叉树

三. 二叉树的存储方式

1. 链式存储法

基于指针或者引用的链式存储法。
链式存储法
每个节点有三个字段,其中一个存储数据,另外两个是指向左右子节点的指针。顺着根节点,就可以通过左右子节点的指针,把整棵树都串起来。

tip: 大部分二叉树都是使用这种方式存储的。

2. 顺序存储法

基于数组的顺序存储法。
顺序存储法
如果节点 X 存储在数组中下标为 i 的位置,下标为 2 * i 的位置存储的就是左子节点,下标为 2 * i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为 1 的位置),这样就可以通过下标计算,把整棵树都串起来。

tip: 顺序存储法适用于完全二叉树。对于非完全二叉树,根据下标构建存储数据后,会有一些存储空间没有使用,造成浪费。

四. 二叉树的遍历

二叉树的遍历
javascript 实现一下吧!

// Definition for a binary tree node.
  function TreeNode(val, left, right) {
      this.val = (val===undefined ? 0 : val)
      this.left = (left===undefined ? null : left)
      this.right = (right===undefined ? null : right)
  }

1. 前序遍历

题目描述

输入示例
递归实现:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
// 递归方法
var preorderTraversal = function (root) {
    let result = [];
    if (!root) {
        return result;
    }
    let tracersal = function (root) {
        if (root) {
            result.push(root.val);
            tracersal(root.left);
            tracersal(root.right);
        }
    }
    tracersal(root);
    return result;
};

非递归实现:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
// 非递归方法(代码模拟实现栈)
var preorderTraversal = function (root) {
    let stack = [root];
    let result = [];
    while (stack.length > 0) {
        let node = stack.pop();
        if (node) {
            result.push(node.val);
            node.right && stack.push(node.right);
            node.left && stack.push(node.left);
        }
    }
    return result;
};
2. 中序遍历

题目
输入输出示例

递归实现:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var inorderTraversal = function (root) {
    let result = [];
    if (!root) {
        return result;
    }
    let traversal = function (node) {
        if (node) {
            traversal(node.left);
            result.push(node.val);
            traversal(node.right);
        }
    }
    traversal(root);
    return result;
};

非递归实现:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var inorderTraversal = function (root) {
    let stack = [];
    let result = [];
    while (root || stack.length > 0) {
        while (root) {
            stack.push(root);
            root = root.left;
        }
        let node = stack.pop();
        result.push(node.val);
        root = node.right;
    }
    return result;
};
3. 后序遍历

题目
输入输出示例

递归实现:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function (root) {
    let result = [];
    if (!root) {
        return result;
    }
    let traversal = function (node) {
        if (node) {
            traversal(node.left);
            traversal(node.right);
            result.push(node.val);
        }
    }
    traversal(root);
    return result;
};

非递归实现:

/**
 * @param {TreeNode} root
 * @return {number[]}
 */
var postorderTraversal = function (root) {
    let stack = [];
    let result = [];
    // 标识上一次处理的节点
    let prev = null;
    if (!root) {
        return result;
    }
    while (root || stack.length > 0) {
        while (root) {
            stack.push(root);
            root = root.left;
        }
        let node = stack.pop();
        // prev === node.right: 表示这个节点的右子树已经处理完毕了,可以处理该节点了
        if (!node.right || prev === node.right) {
            result.push(node.val);
            prev = node;
            root = null;
        } else {
            // 当前处理节点 node 有右子树且尚未处理
            stack.push(node);
            root = node.right;
        }
    }
    return result;
};
4. 层序遍历

递归实现:

/**
 * @param {TreeNode} root
 * @return {number[][]}
 */
var levelOrder = function (root) {
    let result = [];
    if (!root) {
        return result;
    }
    let helper = function (node, arr, level) {
        if (!node) {
            return;
        }
        if (!arr[level]) {
            arr[level] = [];
        }
        arr[level].push(node.val);
        helper(node.left, arr, level + 1);
        helper(node.right, arr, level + 1);
    }
    helper(root, result, 0);
    return result;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值