遍歷樹算法 - Traverse A Tree

樹的遍歷 Tree Traversals

let root = {
       val: 1,
       left:{
         val: 2,
         left: {
            val: 3,
            left: {
                val: 5
            }
         },
         right: {
            val: 4,
            right: {
                val: 6
            } 
         }
       },
       right:{
           val: 7,
           left: {
               val: 8
           },
           right:{
               val: 9,
               right: {
                   val: 10
               }
           }
       } 
    };

0. 二叉樹的序列化與反序列化

序列化二叉樹:把一棵二叉樹按照某種遍歷方式的結果以某種格式保存爲字符串。須要注意的是,序列化二叉樹的過程當中,若是遇到空節點,須要以某種符號(這裏用#)表示。
反序列化二叉樹:根據某種遍歷順序獲得的序列化字符串,重構二叉樹。具體思路是按前序遍歷「根左右」的順序,根節點位於其左右子節點的前面,即非空(#)的第一個節點是某子樹的根節點,左右子節點在該根節點後,以空節點#爲分隔符。

1. 序列化二叉樹

function serializeTree(root, nodes = []) {
        if (!root) {
            nodes.push("#");
        } else {
            nodes.push(root.val);
            serializeTree(root.left, nodes);
            serializeTree(root.right, nodes);
        }
        return nodes.join(",");
    }
    serializeTree(root); //"1,2,3,5,#,#,#,4,#,6,#,#,7,8,#,#,9,#,10,#,#"

2. 反序列化二叉樹

function deserializeTree(nodeStr){
        if (!nodeStr) {
            return null;
        }
        return deserialize(nodeStr.split(","));
    }
    function deserialize(nodes) {
        let root = null;
        const current = nodes.shift();
        if (current !== "#") {
            root = { val: current };
            root.left = deserialize(nodes);
            root.right = deserialize(nodes);
        }
        return root;
    }
    deserializeTree("1,2,3,5,#,#,#,4,#,6,#,#,7,8,#,#,9,#,10,#,#"); // root

1.廣度優先遍歷 Breadth First Traversal

1. 層級遍歷 Level Order

Algorithm Postorder(tree)
   1. Visit the root. 先訪問根節點
   2. Traverse the deeper level, visit child root. call levelorder(node, depth)
   3. Continue traverse the deeper level, visit child root. call levelorder(node, depth)
   ...
var levelOrder = function(root) {
    var orders= [];
    levelorder(root, 0)
    return orders;
    
    function levelorder(node, depth) {
        if (!node) {
            return;
        }
        orders[depth] = orders[depth] || [];
        orders[depth].push(node.val);
        levelorder(node.left, depth + 1);
        levelorder(node.right, depth + 1);
    }    
};

console.warn("levelOrder", levelOrder(root));
Output: "levelorder": [[1], [2, 7], [3, 4, 8, 9], [5, 6, 10]]

2. 深度優先遍歷 Depth First Traversals

1. 後序遍歷 Postorder (Left, Right, Root)

Algorithm Postorder(tree)
   1. Traverse the left subtree, i.e., call Postorder(left-subtree) 首先遍歷左子樹
   2. Traverse the right subtree, i.e., call Postorder(right-subtree) 而後遍歷右子樹
   3. Visit the root. 最後訪問根節點
var postorderTraversal = function(root) {
      var orders = [];
      postorder(root);
      return orders;
    
      function postorder(node) {
         if (node ) {
                if (isValidValue(node.left)) {
                    postorder(node.left);
                }
        
                if (isValidValue(node.right)) {
                    postorder(node.right);
                }
                
                if (isValidValue(node.val)) {
                    orders.push(node.val);
                } 
            }
        }
        
        function isValidValue(node) {
            return node !== null && node !== undefined && node !== "";
        }
    };
    
    console.warn("postorder", postorderTraversal(root));
Output: "postorder": [5, 3, 6, 4, 2, 8, 10, 9, 7, 1]

2. 中序遍歷 Inorder (Left, Root, Right)

Algorithm Inorder(tree)
   1. Traverse the left subtree, i.e., call Inorder(left-subtree) 首先遍歷左子樹
   2. Visit the root. 而後訪問根節點
   3. Traverse the right subtree, i.e., call Inorder(right-subtree) 最後遍歷右子樹
var inorderTraversal = function(root) {
        var orders = [];
        inorder(root);
        return orders;
    
        function inorder(node) {
            if (node ) {
                if (isValidValue(node.left)) {
                    inorder(node.left);
                }
                
                if (isValidValue(node.val)) {
                    orders.push(node.val);
                }
              
                if (isValidValue(node.right)) {
                    inorder(node.right);
                }
            }
        }
        
        function isValidValue(node) {
            return node !== null && node !== undefined && node !== "";
        }
    };
    
    console.warn("inorder", inorderTraversal(root));
Output: "inorder": [5, 3, 2, 4, 6, 1, 8, 7, 9, 10]

3. 前序遍歷 Preorder (Root, Left, Right)

Algorithm Preorder(tree)
   1. Visit the root. 首先訪問根節點
   2. Traverse the left subtree, i.e., call Preorder(left-subtree) 而後遍歷左子樹
   3. Traverse the right subtree, i.e., call Preorder(right-subtree) 最後遍歷右子樹
``
var preorderTraversal = function(root) {
    var orders = [];
    preorder(root);
    return orders;

    function preorder(node) {
        if (node ) {
            if (isValidValue(node.val)) {
                orders.push(node.val);
            }
     
            if (isValidValue(node.left)) {
                preorder(node.left);
            }
    
            if (isValidValue(node.right)) {
                preorder(node.right);
            }
        }
    }
    
    function isValidValue(node) {
        return node !== null && node !== undefined && node !== "";
    }
};

console.warn("preorder", preorderTraversal(root));
>  Output: "preorder" [1, 2, 3, 5, 4, 6, 7, 8, 9, 10]
相關文章
相關標籤/搜索