樹形結構

CBD發表於2019-11-26

樹形結構 {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);
複製程式碼

相關文章