JavaScript数据结构之-树

一、它是什么?

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

二、二叉搜索树(BST)

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

2.一、实现二叉搜索树的遍历、新增、查询、删除

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);
复制代码

三、二叉搜索树(BST)优势

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

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

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

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

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

相关文章
相关标签/搜索