树结构_二叉搜索树

二叉搜索树(BST, Binary Search Tree)

  1. 二叉树也是一颗二叉树, 可以为空

  2. 如果不为空,则满足以下条件

                1. 非空左子树的所有键值小于其根节点的键值

                2. 非空右子树的所有键值大于其根节点的键值

                3. 左, 右子树本身也是搜索树

  3. 二叉搜索树的特点

                1. 二叉搜索树中,相对较小的值总包存在左节点上, 嫌贵较大的值总是保存在右节点上

                    注: 这一特性可以保证二叉搜索树高效的送偶所特性

  4. 二叉搜索树的节点的属性

                this.item = item

                this.left = null

                this.right = null 

  5. 二叉搜索树的属性

  6. 二叉搜索树的方法

                1. insertItem(item)                     向树中插入一个新的键

                2. search(key)                          查看树中是否包含指定的键值,若节点存在则返回true,否则返回false

                3. preOrderTravel()                     先序遍历

                4. inOrderTravel()                      中序遍历

                5. postOrderTravel()                    后序遍历

                6.                                      层序遍历

                7. min()                                返回书中最小的值/键

                8. max()                                返回树中最大的值/键

                9. remove(key)                          从树中移除某个键

  7. remove方法思路

                删除的节点分三种情况:

                    1. 被删除的节点为叶节点(即没有子节点)

                    2. 被删除的节点只有一个子节点

                    3. 被删除的节点有两个子节点

  8. 二叉搜索树的嗲马实现

  

    function BinarySarchTree(){
        // 1. 封装节点类
        function Node(item){
            this.item = item;
            this.left = null;
            this.right = null;
        }

        // 2. 二叉搜索树的属性
        this.root = null;

        // // 3. 二叉搜索树的方法
        // 1. 向树中插入一个新的键
        BinarySarchTree.prototype.insertItem = function(key){
            // 1. 首先创建节点
            var newNode = new Node(key);

            // 2. 首先判断根节点是否有值
            if(this.root == null){
                this.root = newNode;
            }else{
                this.insertNode(this.root, newNode);
            }
        }
        // 内部函数——插入节点
        BinarySarchTree.prototype.insertNode = function(node, newNode){
            if(newNode.item < node.item){
                // 向左查找
                if(node.left == null){
                    node.left = newNode;
                }else{
                    this.insertNode(node.left, newNode);
                }
            }else{
                // 向右查找
                if(node.right == null){
                    node.right = newNode;
                }else{
                    this.insertNode(node.right, newNode);
                }
            }
        }

        // 2. 查看树中是否包含指定的键值,若节点存在则返回true,否则返回false
        BinarySarchTree.prototype.search = function(key){
            var node = this.root;
            while(node != null){
                if(key < node.item){
                    node = node.left;
                }else if(key > node.item){
                    node = node.right;
                }else{
                    return true;
                }
            }
            return false;
        }

        // 3. 先序遍历
        /* 
            遍历过程:
                1. 访问根节点
                2. 先序遍历其左子树
                3. 先序遍历其右子树
        */
        BinarySarchTree.prototype.preOrderTravel = function(handler){
            this.preOrderTravelNode(this.root, handler);
        } 
        // 内部函数——先序遍历
        BinarySarchTree.prototype.preOrderTravelNode = function(node, handler){
            // 若节点不为空
            if(node !== null){
                // 1. 调用回调函数
                handler(node.item);

                // 2. 处理左子树
                this.preOrderTravelNode(node.left, handler);

                // 3. 处理右子树
                this.preOrderTravelNode(node.right, handler);
            }
        }

        // 4. 中序遍历
        /*
            遍历过程:
                1. 先序遍历其左子树
                2. 访问根节点
                3. 先序遍历其右子树
        */
        BinarySarchTree.prototype.inOrderTravel = function(handler){
            this.inOrderTravelNode(this.root, handler);
        }
        // 内部函数——先序遍历
        BinarySarchTree.prototype.inOrderTravelNode = function(node, handler){
            // 若节点不为空
            if(node !== null){
                // 1. 处理左子树
                this.inOrderTravelNode(node.left, handler);

                // 2. 调用回调函数
                handler(node.item);

                // 3. 处理右子树
                this.inOrderTravelNode(node.right, handler);
            }
        }

        // 5. 后序遍历
         /*
            遍历过程:
                1. 先序遍历其左子树
                2. 先序遍历其右子树
                3. 访问根节点
        */
        BinarySarchTree.prototype.postOrderTravel = function(handler){
            this.postOrderTravelNode(this.root, handler);
        }
        // 内部函数——先序遍历
        BinarySarchTree.prototype.postOrderTravelNode = function(node, handler){
            // 若节点不为空
            if(node !== null){
                // 1. 处理左子树
                this.postOrderTravelNode(node.left, handler);

                // 2. 处理右子树
                this.postOrderTravelNode(node.right, handler);

                // 3. 调用回调函数
                handler(node.item);
            }
        } 

        // 6. 层序遍历

        // 7. 返回树中最小的值/键
        BinarySarchTree.prototype.min = function(){
            var cur = this.root;
            if(cur == null){
                return null;
            }

            // 依次向左查找
            while(cur.left != null){
                cur = cur.left;
            }
            return cur.item;

        }

        // 8. 返回树中最大的值/键
        BinarySarchTree.prototype.max = function(){
            var cur = this.root;
            if(cur == null){
                return null;
            }

            // 依次向右查找
            while(cur.right != null){
                cur = cur.right;
            }
            return cur.item;
        }


        // 9. 从树中移除某个键
        BinarySarchTree.prototype.remove = function(key){
            // 1. 寻找需要删除的节点
            var cur = this.root;
            var parent = null;
            var isLeft = true;
            if(cur == null){
                return false;
            }else{
                while(key != cur.item){
                    parent = cur;
                    if(key < cur.item){
                        cur = cur.left;
                        isLeft = true;
                    }else{
                        cur = cur.right;
                        isLeft = false;
                    }

                    // 若cur为空,则说明没找到,直接返回
                    if(cur == null){
                        return false;
                    }
                }

                // 能跳出while循环,则说明找到了
                // 找到的节点为cur,其父节点为parent
                // 2. 判断所找到的节点类型
                // 2.1 若被删除的节点为叶节点
                if(cur.left == null && cur.right == null){
                    if(cur == this.root){
                        this.root = null;
                    }else if(isLeft == true){
                        // 若需要删除的叶节点为父节点的左子节点,则将右子节点赋值给左子节点, 然后将右子节点置为空
                        parent.left =  null
                    }
                }

                // 2.2 若被删除的节点只有一个子节点
                else if(cur.left == null){
                    if(cur == this.root){
                        this.root = cur.right;
                    }
                    // cur.left = null 说明cur节点的左节点为空,右节点不为空
                    else if(isLeft == true){
                        parent.left = cur.right;
                    }else{
                        parent.right = cur.right;
                    }
                }else if(cur.right == null){
                    if(cur == this.root){
                        this.root = cur.left;
                    }
                    // cur.right = null 说明cur节点的左节不为空,右节点为空
                    else if(isLeft == true){
                        parent.left = cur.left;
                    }else{
                        parent.right = cur.left;
                    }
                }
            }
        }
    }
View Code

 

posted @ 2020-02-05 12:13  CarreyB  阅读(153)  评论(0编辑  收藏  举报