浅黛梨妆こ

文章 评论 浏览 29

浅黛梨妆こ 2022-05-04 13:54:42

上面一段基本是在介绍树相关的概念,接下来配合概念用JS代码实现树的相关操作。

参考:

3.6.1 二叉树与先序/中序/后序遍历

遍历二叉树(Traversing Binary Tree):是指按指定的规律对二叉树中的每个结点访问一次且仅访问一次。
二叉树的遍历主要分三种:

  • 先(根)序遍历:根左右
  • 中(根)序遍历:左根右
  • 后(根)序遍历:左右根
class BinaryTree {
    static from(array) {
        const root = new BinaryTree()
        if (array == null || !Array.isArray(array)) {
            root.level = 1
            root.data = array
            return root
        }
        preOrderTraverse(root, 0, function (node, value, level) {
            node.data = value
            node.level = level
        }, 1)
        return root
        function preOrderTraverse(node, index, visit, level) {
            visit(node, array[index], level)

            if (array[2 * index + 1] != null) {
                preOrderTraverse(node.left = new BinaryTree(), 2 * index + 1, visit, node.level + 1)
            }
            if (array[2 * index + 2] != null) {
                preOrderTraverse(node.right = new BinaryTree(), 2 * index + 2, visit, node.level + 1)
            }
        }
    }
    constructor(data, left, right) {
        this.data = data
        this.left = left
        this.right = right
    }
    toString() {
        return this.toLevelArray().join()
    }
    toLevelArray() {
        const array = []
        this.preOrderTraverse((v, level) => {
            array[level - 1] ? array[level - 1].push(v) : (array[level - 1] = [v])
        })
        return array
    }
    getDepth() {
        let level = 0
        this.preOrderTraverse((v, l) => {
            if (l > level) {
                level = l
            }
        })
        return level
    }
    /**
     * 链式存储结构的递归先序遍历 (根左右)
     * 
     * 若二叉树为空,则遍历结束;否则
     * ⑴ 访问根结点;
     * ⑵ 先序遍历左子树(递归调用本算法);
     * ⑶ 先序遍历右子树(递归调用本算法)。
     */
    preOrderTraverse(visit) {
        visit(this.data, this.level, this)
        if (this.left) this.left.preOrderTraverse(visit)
        if (this.right) this.right.preOrderTraverse(visit)
    }
    /**
     * 链式存储结构的 **非递归** 先序遍历
     */
    preOrderTraverseNR(visit) {
        const stack = []
        stack.push(this)
        while (stack[0]) {
            let p
            // 向左走到尽头
            while ((p = stack[stack.length - 1])) {
                (p.data != null) && visit(p.data, p.level, p)
                stack.push(p.left)
            }
            // 删掉空节点
            stack.pop()
            // 删掉根节点,进栈右节点
            if (stack[0]) {
                p = stack.pop()
                stack.push(p.right)
            }
        }
    }
    /**
     * 递归中序遍历 (左根右)
     * 
     * 若二叉树为空,则遍历结束;否则
     * ⑴ 中序遍历左子树(递归调用本算法);
     * ⑵ 访问根结点;
     * ⑶ 中序遍历右子树(递归调用本算法)。
     */
    inOrderTraverse(visit) {
        if (this.left) this.left.inOrderTraverse(visit)
        visit(this.data, this.level, this)
        if (this.right) this.right.inOrderTraverse(visit)
    }
    /**
     * **非递归** 中序遍历
     */
    inOrderTraverseNR(visit) {
        const stack = []
        stack.push(this)
        while (stack[0]) {
            let p
            // 向左走到尽头
            while ((p = stack[stack.length - 1])) {
                stack.push(p.left)
            }
            // 删除空节点
            stack.pop()
            // 删掉根节点,进栈右节点
            if (stack[0]) {
                p = stack.pop()
                ;(p.data != null) && visit(p.data, p.level, p)
                stack.push(p.right)
            }
        }
    }
    /**
     * 递归后序遍历 (左右根)
     * 
     * 若二叉树为空,则遍历结束;否则
     * ⑴ 后序遍历左子树(递归调用本算法);
     * ⑵ 后序遍历右子树(递归调用本算法) ;
     * ⑶ 访问根结点 。
     */
    postOrderTraverse(visit) {
        if (this.left) this.left.postOrderTraverse(visit)
        if (this.right) this.right.postOrderTraverse(visit)
        visit(this.data, this.level, this)
    }
    /**
     * 非递归后序遍历
     *
     * (1) 根结点入栈,且mark = 0;
     * (2) 若栈不为空,出栈到node;
     *     (3) 若node的mark = 0,修改当前node的mark为1,左子树入栈;
     *     (4) 若node的mark = 1,修改当前node的mark为2,右子树入栈;
     *     (5) 若node的mark = 2,访问当前node结点的值;
     * (6) 直到栈为空结束。
     */
    postOrderTraverseNR(visit) {
        const stack = []
        stack.push([this, 0])
        while (stack[0]) {
            let p = stack.pop()
            let node = p[0]
            switch (p[1]) {
                case 0:
                    stack.push([node, 1])
                    if (node.left) {
                        stack.push([node.left, 0])
                    }
                    break
                case 1:
                    stack.push([node, 2])
                    if (node.right) {
                        stack.push([node.right, 0])
                    }
                    break
                case 2:
                    (node.data != null) && visit(node.data, node.level, node)
                    break
                default:
                    break
            }
        }
    }
}

// const tree = BinaryTree.from([0, 1, 2, 3, 4, 5, 6, null, 8, 9])
// tree.preOrderTraverse(v => console.log(v))

JavaScript 与简单算法

浅黛梨妆こ 2022-05-04 13:15:00

@mingxing9921 大写的尴尬。。。 这篇文章都没写完

从浏览器输入一个 url 到页面渲染以及涉及的知识点及优化点

浅黛梨妆こ 2022-05-03 07:44:13

v-if: Watcher监听数据变化,然后,render函数生成VNode对象,patch方法对比新旧VNode, DOM Diff 算法修改真正的DOM元素

第 147 题:v-if、v-show、v-html 的原理是什么,它是如何封装的?

浅黛梨妆こ 2022-05-02 01:32:13

在vue 中 vue 做了处理
如果我们自己在非vue 中需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数

第 94 题:vue 在 v-for 时给每项元素绑定事件需要用事件代理吗?为什么?

更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文