zoukankan      html  css  js  c++  java
  • 二叉树的遍历-前中后层序,二叉搜索树

    二叉树-百度百科:

    二叉树(Binary tree)是树形结构的一个重要类型。许多实际问题抽象出来的数据结构往往是二叉树形式,即使是一般的树也能简单地转换为二叉树,而且二叉树的存储结构及其算法都较为简单,因此二叉树显得特别重要。二叉树特点是每个结点最多只能有两棵子树,且有左右之分 。

    二叉树是n个有限元素的集合,该集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点 。

    二叉树

    二叉树的性质:

    • (i)层最多有(2^{i - 1})个节点
    • 二叉树深度为(k),最多有(2^{k - 1})个节点
    • 满二叉树:上图中即为一个满二叉树
    • 完全二叉树:出最后一层外为满二叉树,最后一层叶子节点自左向右依次排列
      完全二叉树
    二叉树的遍历
    //ES6	
    class Node {
        constructor(val){
            this.val = val;
            this.left = null;
            this.right = null;
        }
    }
    class BinaryTree {
        constructor() {
            this.root = null;
        }
    
        addNode(val) {
            let curNode = new Node(val);
            if (!this.root) this.root = curNode;
            else {//层序遍历,找到空节点加入
                let q = [this.root];
                while (q.length) {
                    let cur = q.shift();
                    if(cur.left) {
                        q.push(cur.left);
                    } else {
                        cur.left = curNode;
                        break;
                    }
                    if (cur_right) {
                        q.push(cur_right);
                    } else {
                        cur_right = curNode;
                        break;
                    }
                }
                
            } 
        }
    }
    
    • 前序遍历

      • 节点的访问顺序为: 根节点 --> 左子节点 --> 右子节点
      1. 先访问当前节点
      2. 访问当前节点的左子节点
      3. 重复2,直到当前节点为空,返回上一层状态,访问其右子节点,重复2
      • 递归实现
        preOrder(node) {
            if (node) {
                console.log(node.val);
                this.preOrder(node.left);
                this.preOrder(node.right);
            }
        }
    
      • 非递归实现

        + 利用栈的性质,先进后出,根据前序遍历的顺序 根 -> 左 -> 右
        
        1. 初始化栈,root入栈
        2. 栈顶元素出栈,记录其value
        3. 右子节点存在则入栈
        4. 左子节点存在则入栈
        5. 重复2,3,4直到栈空
        
        preOrder() {
            let goal = [],
                idx = 0,
                sta = [this.root];//stack
            while (sta.length) {
                let cur = sta.pop();
                goal[idx++] = cur.val;
                if (cur.right) sta.push(cur.right);
                if (cur.left) sta.push(cur.left);
            }
            console.log(goal);
        }
    
    • 中序遍历:左子节点 -> 根节点 -> 右子节点

      • 递归写法同上,修改顺序即可
      • 非递归:
      1. 根节点入栈
      2. 判断栈顶元素左子节点是否存在
        1. 存在,继续入栈左子节点
        2. 不存在,弹栈,记录value,若有右子节点存在则入栈
      3. 重复2,直到栈空
        inOrder() {
            let goal = [],
                idx = 0,
                cur = this.root,
                sta = [];//stack
            if (!this.root) console.log("Empty!");
            while (sta.length || cur) {
                while (cur) {//存在则入栈
                    sta.push(cur);
                    cur = cur.left;
                }
                cur = sta.pop();//top
                goal[idx++] = cur.val;
                cur = cur.right;//修改cur为当前节点的右子节点,之后若存在则入栈
            }
            console.log(goal);
        }
    
    • 后序遍历: 左子节点 -> 右子节点 -> 根节点

      • 递归写法同上,修改顺序即可
      • 需要保证在左子树、右子树访问结束后在访问根节点 -- 加标记,记录根节点访问次数, == 2即弹出
      1. 根节点入栈
      2. 左子节点入栈 ...-> 叶子结点
      3. 弹栈,记录叶子结点,叶子结点父节点次数 + 1,右子节点入栈
      4. 栈顶继续2,3
    //待填坑。。。
    
      • 法2:使用双栈,前序遍历压栈顺序为先右后左,其遍历结果为:根 -> 左 -> 右,若压栈顺序为先左后右则遍历结果为:根 -> 右 -> 左,恰好为后序遍历的倒叙,第一次遍历结果使用另一个栈存储,最后弹栈输出即可
        lastOrder() {
            let goal = [],
                sta1 = [this.root],
                sta2 = [];
            console.log("LastOrder:");
            while (sta1.length) {
                let cur = sta1.pop();
                sta2.push(cur.val);
                if (cur.left) sta1.push(cur.left);
                if (cur.right) sta1.push(cur.right);
            }
            while (sta2.length) {
                goal.push(sta2.pop());
            }
            console.log(goal);
        }
    
    • 层序遍历:使用队列即可,先进先出。初始root入队,每次记录队首信息,存储队首的左右子节点即可。
        leverOrder() {
            let goal = [],
                idx = 0,
                q = [this.root];
            console.log("LeverOrder:");
            while (q.length) {
                let cur = q.shift();//取出队首
                //按层遍历记录每次的q.length即为当前层的节点数
                // let len = q.length;
                // for (let i = 0; i < len; i++){
                //     let cur = q.shift();
                //     if(...) ...
                // }
                goal[idx++] = cur.val;
                if (cur.left) q.push(cur.left);
                if (cur.right) q.push(cur.right);
            }
            console.log(goal);
        }
    
    • 二叉搜索树:左子节点的值小于根节点的值,右子节点的值大于根节点的值
    • JavaScript实现
    class BinarySearchTree {
        constructor () {
            this.root = null;
        }
        addNode(data) {//相对于父节点的值,左子节点小,右子节点大
            if (this.root === null) this.root = new Node(data);
            else {
                let curNode = new Node(data);
                let cur = this.root;
                while (true) {
                    if (data < cur.val) {
                        if (!cur.left) {
                            cur.left = curNode;
                            break;
                        } else {
                            cur = cur.left;
                        }
                    } else {
                        if (!cur.right) {
                            cur.right = curNode;
                            break;
                        } else {
                            cur = cur.right;
                        }
                    }
                }
            }
        }
        inOrder() {//二叉搜索树的中序遍历结果为升序
            let cur = this.root,
                st = [],
                book = [];
            while (cur || st.length) {
                while (cur) {
                    st.push(cur);
                    cur = cur.left;
                }
                cur = st.pop();
                book.push(cur.val);
                cur = cur.right;
            }
            console.log(`BST: ${book}`);
        }
    }
    
  • 相关阅读:
    codeforces 1140D(区间dp/思维题)
    区间dp之四边形不等式优化详解及证明
    poj1947
    hdu4044
    poj1155
    poj3162(树形dp+优先队列)
    hdu4003详解(树形dp+多组背包)
    poj1947(树形背包)
    hdu1011(树形背包)(提供一个特殊样例)
    CopyOnWriteArrayList总结
  • 原文地址:https://www.cnblogs.com/honey-cat/p/14655331.html
Copyright © 2011-2022 走看看