52 # 二叉树的前中后遍历

简介: 52 # 二叉树的前中后遍历

二叉树的遍历

线性数据结构遍历比较简单,可以采用正序遍历、逆序遍历。

遍历树的目的一般是修改树,比如修改树的节点,采用访问者模式

前序遍历

前序遍历(preorder traversal):先访问根节点,前序遍历左子树,前序遍历右子树;遍历 dom 树可以使用

perorderTraversal(visitor) {
    if (visitor == null) return;
    const traversal = (node) => {
        if (node === null) return;
        visitor.visit(node);
        traversal(node.left);
        traversal(node.right);
    };
    traversal(this.root);
}

中序遍历

中序遍历(inorder traversal):中序遍历左子树,根节点,中序遍历右子树;可以顺序打印数据

inorderTraversal(visitor) {
    if (visitor == null) return;
    const traversal = (node) => {
        if (node === null) return;
        traversal(node.left);
        visitor.visit(node);
        traversal(node.right);
    };
    traversal(this.root);
}

后序遍历

后序遍历(postorder traversal):后序遍历左子树,后续遍历右子树,根节点;遍历子节点可使用后序遍历

postorderTraversal(visitor) {
    if (visitor == null) return;
    const traversal = (node) => {
        if (node === null) return;
        traversal(node.left);
        traversal(node.right);
        visitor.visit(node);
    };
    traversal(this.root);
}

层序遍历

层序遍历(level order traversal):从上到下,从左到右依次访问每一个节点

完整代码

实现如下:

// 节点
class Node {
    constructor(element, parent) {
        this.element = element; // 存的数据
        this.parent = parent; // 父节点
        this.left = null; // 左子树
        this.right = null; // 右子树
    }
}
class BST {
    constructor(compare) {
        this.root = null;
        this.size = 0; // 节点个数
        this.compare = compare || this.compare;
    }
    compare(e1, e2) {
        return e1 - e2;
    }
    // 添加节点
    add(element) {
        // 如果根元素不存在
        if (this.root === null) {
            this.root = new Node(element, null);
            this.size++;
            return;
        } else {
            // 如果根元素存在,那么增加的就不是根节点,需要找到 parent
            let currentNode = this.root;
            // 当前比较的结果
            let compare = 0;
            // 先找到需要对比的 parent(当前父节点)
            let parent = null;
            while (currentNode) {
                parent = currentNode;
                compare = this.compare(element, currentNode.element);
                // 如果大于 0 找右树,小于 0 找左树
                if (compare > 0) {
                    currentNode = currentNode.right;
                } else if (compare < 0) {
                    currentNode = currentNode.left;
                } else {
                    // 如果比较后结果一样,由自己决定是否需要覆盖
                    currentNode.element = element; // 覆盖
                    return;
                }
            }
            // 找到了 parent,生成新节点
            let newNode = new Node(element, parent);
            if (compare > 0) {
                parent.right = newNode;
            } else {
                parent.left = newNode;
            }
        }
    }
    // 先序遍历
    perorderTraversal(visitor) {
        if (visitor == null) return;
        const traversal = (node) => {
            if (node === null) return;
            visitor.visit(node);
            traversal(node.left);
            traversal(node.right);
        };
        traversal(this.root);
    }
    // 中序遍历
    inorderTraversal(visitor) {
        if (visitor == null) return;
        const traversal = (node) => {
            if (node === null) return;
            traversal(node.left);
            visitor.visit(node);
            traversal(node.right);
        };
        traversal(this.root);
    }
    // 后序遍历
    postorderTraversal(visitor) {
        if (visitor == null) return;
        const traversal = (node) => {
            if (node === null) return;
            traversal(node.left);
            traversal(node.right);
            visitor.visit(node);
        };
        traversal(this.root);
    }
}
let bst = new BST();
let arr = [10, 8, 19, 6, 15, 22, 20];
arr.forEach((element) => {
    bst.add(element);
});
// 遍历树的目的一般是修改树,比如修改树的节点,采用访问者模式
console.log(
    bst.perorderTraversal({
        visit(node) {
            console.log("visitor.visit---->", node.element);
        },
    })
);
console.log(
    bst.inorderTraversal({
        visit(node) {
            console.log("visitor.visit---->", node.element);
        },
    })
);
console.log(
    bst.postorderTraversal({
        visit(node) {
            console.log("visitor.visit---->", node.element);
        },
    })
);
目录
相关文章
|
9月前
|
传感器 缓存 安全
《分布式软总线:网络丢包下的数据吞吐奇迹》
网络丢包是数据传输中的常见问题,由网络拥堵、物理链路故障或设备缺陷引起,导致视频卡顿、游戏延迟等问题。分布式软总线技术通过极简协议提升传输效率,采用快速丢包恢复策略、智能感知网络变化、多通道并发传输及分布式缓存等创新手段,在丢包情况下仍能保障高吞吐率。其优势在工业自动化和智能交通等领域得以体现,为复杂网络环境下的高效数据传输提供了可靠解决方案,推动未来网络通信发展。
293 10
|
机器学习/深度学习 存储 人工智能
AllData数据中台核心菜单九:元数据管理
杭州奥零数据科技有限公司成立于2023年,专注于数据中台业务,维护开源项目AllData并提供商业版解决方案。AllData提供数据集成、存储、开发、治理及BI展示等一站式服务,支持AI大模型应用,助力企业高效利用数据价值。
|
存储 JSON JavaScript
「offer来了」保姆级巩固你的js知识体系(4.0w字)
该文章提供了JavaScript知识体系的全面复习资料,覆盖了从基础语法到高级特性如闭包、原型链、异步编程等多个方面,并通过大量的面试题和实例代码帮助巩固理解。
「offer来了」保姆级巩固你的js知识体系(4.0w字)
|
前端开发 JavaScript
前端基础(六)_流程控制语句(if、if-else、if-else嵌套、switch)
本文介绍了JavaScript中的流程控制语句,包括if、if-else、if-else嵌套和switch语句。
221 2
前端基础(六)_流程控制语句(if、if-else、if-else嵌套、switch)
|
人工智能 前端开发 开发工具
**.NET技术概览:** 本文探讨.NET的核心优势
【7月更文挑战第4天】**.NET技术概览:** 本文探讨了.NET的核心优势,如统一开发平台、Visual Studio的强大工具、跨平台能力及丰富的类库。它在现代应用中的创新应用包括企业级、Web、移动、云服务和游戏开发。同时,面对性能优化、容器化、AI集成等挑战,.NET正寻求未来机遇,通过开源社区持续发展。开发者应抓住这些趋势,利用.NET推动软件创新。
203 1
leetcode3题解
leetcode3的题解
86 1
|
JavaScript 中间件 PHP
中间件应用程序路由和分发
【5月更文挑战第13天】中间件应用程序路由和分发
175 2
|
域名解析 存储 缓存
DNS服务器域名解析
DNS服务器域名解析
231 0
|
机器学习/深度学习 人工智能 并行计算
微软开源DeepSpeed Chat,人人可快速训练百亿、千亿级ChatGPT大模型(33)
微软开源DeepSpeed Chat,人人可快速训练百亿、千亿级ChatGPT大模型
675 0
|
机器学习/深度学习
Lesson 4.1 逻辑回归模型构建与多分类学习方法
Lesson 4.1 逻辑回归模型构建与多分类学习方法