JavaScript数据结构之-树

1、它是什么?

树一种分层次的数据结构。它是由一个或者多个节点组成由层次关系的集合。之所以称之为树,是因为看它外形像一颗倒挂的树。根朝上,叶朝下。由若干个节点组成,没有父节点的节点称之为根节点。一个节点只有一个父节点,一个父节点由若干个子节点。

2、二叉搜索树(BST)

节点的左子节点小于父节点,节点的右子节点大于父节点。

2.1、实现二叉搜索树的遍历、新增、查询、删除
function BinarySearchTree(){
        // 根节点初始化
        var root = null;
        // 创建节点类
        var Node = function(key) {
            this.key = key;
            this.left = null;
            this.right = null;
        };
        // 创建节点
        this.insert = function(key) {
            var node = new Node(key);
            if (root === null) {
                root = node;
            } else {
                insertNode(root, node);
            }
        };
        // 查找最小值
        this.min = function() {
            var node = root;
            if (node) {
                while (node && node.left !== null) {
                    node = node.left;
                }
                return node.key;
            }
            return null;
        };
        // 查找最大值
        this.max = function() {
            var node = root;
            if (node) {
                while (node && node.right !== null) {
                    node = node.right;
                }
                return node.key;
            }
            return null;
        };
        // 查找特定的值
        this.search = function(key) {
            return searchNode(root, key);
        };
        // 删除指定节点
        this.remove = function(key) {
            root = removeNode(root, key);
        };
        // 中序遍历
        this.inOrderTraverse = function(callback) {
            inOrderTraverseNode(root, callback);
        };
        // 先序遍历
        this.preOrderTraverse = function(callback) {
            preOrderTraverseNode(root, callback);
        };
        // 后续遍历
        this.postOrderTraverse = function(callback) {
            postOrderTraverseNode(root, callback);
        };
        // 创建节点辅助类
        function insertNode(root, node) {
            if (node.key < root.key) {
                if (root.left === null) {
                    root.left = node;
                } else {
                    insertNode(root.left, node);
                }
            } else {
                if (root.right === null) {
                    root.right = node;
                } else {
                    insertNode(root.right, node);
                }
            }
        }
        // 查找特定值辅助类
        function searchNode(node, key) {
            if (node) {
                if (key < node.key) {
                    return searchNode(node.left, key);
                } else if (key > node.key){
                    return searchNode(node.right, key);
                } else {
                    return true;
                }
            } else {
                return false;
            }
        }
        // 删除指定值辅助类
        function removeNode(node, key) {
            if (node === null) {
                return null;
            }
            if (key < node.key) {
                node.left = removeNode(node.left, key);
                return node;
            } else if (key > node.key) {
                node.right = removeNode(node.right, key);
                return node;
            } else {
                // 第一种情况,删除节点没有子节点
                if(node.left === null && node.right === null) {
                    node = null;
                    return node;
                }
                // 第二章情况,删除节点有一个子节点
                if(node.left === null) {
                    node = node.right;
                    return node;
                } else if (node.right === null) {
                    node = node.left;
                    return node;
                }
                // 第三种情况,删除节点有很多子节点
                // 我们需要找到删除节点,右子节点的最小值,用最小节点去更新删除节点
                var aux = findMinNode(node.right);
                node.key = aux.key;
                node.right = removeNode(node.right, aux.key);
                return node;
            }
        }
        // 查找节点的最小值节点
        function findMinNode(node) {
            while(node && node.left) {
                node = node.left;
            }
            return node;
        }
        // 中序遍历
        function inOrderTraverseNode(node, callback) {
            if(node) { 
                inOrderTraverseNode(node.left, callback);
                callback(node.key);
                inOrderTraverseNode(node.right, callback);
            }
        }
        // 先序遍历
        function preOrderTraverseNode(node, callback) {
            if(node) { 
                callback(node.key);
                preOrderTraverseNode(node.left, callback);
                preOrderTraverseNode(node.right, callback);
            }
        }
        // 后序遍历
        function postOrderTraverseNode(node, callback) {
            if(node) { 
                preOrderTraverseNode(node.left, callback);
                preOrderTraverseNode(node.right, callback);
                callback(node.key);
            }
        }
    }
    var tree = new BinarySearchTree();
    tree.insert(11);
    tree.insert(7);
    tree.insert(15);
    tree.insert(5);
    tree.insert(3);
    tree.insert(9);
    tree.insert(8);
    tree.insert(10);
    tree.insert(10);
    tree.insert(13);
    tree.insert(12);
    tree.insert(14);
    tree.insert(20);
    tree.insert(18);
    tree.insert(25);
    function printNode(value) {
        console.log(value);
    }
    // tree.inOrderTraverse(printNode);
    // tree.preOrderTraverse(printNode);
    // tree.postOrderTraverse(printNode);
    var min = tree.min();
    var max = tree.max();
    var search = tree.search(7);
    tree.remove(10);
    tree.inOrderTraverse(printNode);
复制代码

3、二叉搜索树(BST)优点

二叉树结合了数据查询的优化和链表插入删除的优点。在处理大量动态数据时非常有用。有助于更高效的对数据进行查询、插入、删除。

4、二叉搜索树(BST)缺点

当添加的节点数,可能会出现一条边很深的情况。

5、解决二叉搜索树(BST)缺点,自平衡二叉搜索树(AVL)

自平衡二叉搜索树在进行节点的添加时,计算AVL树的每个节点的左子树的hl,和右子树的高度。如果hr-hl的差值不为1、-1、0三者之一。则需要平衡AVL树。这就是平衡因子。平衡AVL时,采用AVL旋转。来处理不平衡的状态。

转载于:https://juejin.im/post/5d03cad051882509dd57fea3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值