树形结构

1,360 阅读3分钟

树形结构 {ignore}

[toc]

树是一个类似于链表的二维结构,每个节点可以指向0个或多个其他节点

树具有以下特点:

  1. 单根:如果一个节点A指向了另一个节点B,仅能通过A直接找到B节点,不可能通过其他节点直接找到B节点
  2. 无环:节点的指向不能形成环

树的术语:

  1. 结点的度:某个节点的度 = 该节点子节点的数量
  2. 树的度:一棵树中,最大的节点的度为该树的度
  3. 结点的层:从根开始定义起,根为第1层,根的子结点为第2层,以此类推;
  4. 树的高度或深度:树中结点的最大层次
  5. 叶子节点:度为0的结点称为叶结点;
  6. 分支节点:非叶子节点
  7. 子节点、父节点:相对概念,如果A节点有一个子节点B,则A是B的父节点,B是A的子节点
  8. 兄弟节点:如果两个节点有同一个父节点,则它们互为兄弟节点
  9. 祖先节点:某个节点的祖先节点,是从树的根到该节点本身经过的所有节点
  10. 后代节点:如果A是B的祖先节点,B则是A的后代节点

树的代码表示法:

// 树的代码表示法
        function Node(value){
            this.value = value;  //保存数据
            this.children = [];  //用数组来表示子节点 
        }
        var a = new Node("a");
        var b = new Node("b");
        var c = new Node("c");
        var d = new Node("d");
        var e = new Node("e");
        a.children.push(b,e);
        b.children.push(c,e);
        console.log(a);

二叉树

如果一颗树的度为2,则该树是二叉树

二叉树可以用下面的代码表示

function Node(value){
    this.value = value;
    this.left = null;
    this.right = null;
}

二叉树的相关算法

编写各种函数,实现下面的功能

  1. 对二叉树遍历打印
    1. 前(先)序遍历 DLR
    2. 中序遍历 LDR
    3. 后序遍历 LRD
  2. 根据前序遍历和中序遍历结果,得到一颗二叉树
  3. 计算树的深度
  4. 查询二叉树
    1. 深度优先 Depth First Search
    2. 广度优先 Breadth First Search
  5. 比较两棵二叉树,得到比较的结果
function Node(value) {
    this.value = value;
    this.left = null;
    this.right = null;
}

/**
 * 前序遍历
 * @param {*} root 
 */
function DLR(root) {
    if (!root) return;// 没有节点
    console.log(root.value);
    DLR(root.left);
    DLR(root.right);
}

/**
 * 中序遍历
 * @param {*} root 
 */
function LDR(root) {
    if (!root) return;// 没有节点
    LDR(root.left);
    console.log(root.value);
    LDR(root.right);
}

/**
 * 后序遍历
 * @param {*} root 
 */
function LRD(root) {
    if (!root) return;// 没有节点
    LRD(root.left);
    LRD(root.right);
    console.log(root.value);
}

/**
 * 根据前序遍历,和 中序遍历,得到一棵树的根节点
 * @param {*} dlr 
 * @param {*} ldr 
 */
function getTree(dlr, ldr) {
    dlr = dlr.split("");
    ldr = ldr.split("");
    if (dlr.length !== ldr.length) throw new Error("无效的遍历值");
    if (dlr.length === 0) return null;

    var rootValue = dlr[0]; //取出根节点的值 
    var root = new Node(rootValue);

    var index = ldr.indexOf(rootValue); //找到根节点的值在中序遍历中的位置
    var leftLDR = ldr.slice(0, index).join(""); //左边的中序遍历结果
    var leftDLR = dlr.slice(1, leftLDR.length + 1).join(""); //左边的前序遍历结果
    root.left = getTree(leftDLR, leftLDR);

    var rightLDR = ldr.slice(index + 1).join(""); //右边的中序遍历结果
    var rightDLR = dlr.slice(leftLDR.length + 1).join(""); //右边的前序遍历结果
    root.right = getTree(rightDLR, rightLDR);

    return root;
}

/**
 * 得到一棵树的深度
 * @param {*} root 
 */
function getDeep(root) {
    if (!root) return 0;
    var left = getDeep(root.left);
    var right = getDeep(root.right);
    return Math.max(left, right) + 1;
}

var root = getTree("abcde", "cbdae")
console.log(root)
console.log(getDeep(root));

// var a = new Node("a");
// var b = new Node("b");
// var c = new Node("c");
// var d = new Node("d");
// var e = new Node("e");
// var f = new Node("f");

// a.left = b;
// a.right = e;

// b.left = c;
// b.right = d;

// e.left = f;

// LRD(a);