zoukankan      html  css  js  c++  java
  • 用JS实现二叉搜索树

    二叉树的节点最多只能有两个子节点,一个左侧子节点,一个右侧子节点。

    二叉搜索树(BST),是二叉树的一种,但只允许在左侧节点存储比父节点小的值,在右侧节点存储比父节点大或等于父节点的值。

    1.创建BST

    1.1创建BST类

    首先申明BST类的基本结构

    function BinarySearchTree() {
        var Node = function(key){
            this.key = key;
            this.left = null;
            this.right = null;
        };
    
        var root = null;
    }

    下面我们实现一些基本方法

    1.2 向树中插入一个键

    插入一个键时,有三步:第一步,创建一个表示新节点的Node类实例;第二步,判断是否有根节点,如果没有,则插入节点为根节点;第三步,如果已经有根节点,需要一个辅助方法来判断新节点的

    插入位置,方法如下

    var insertNode = function(node,newNode){
            if (newNode.key < node.key) {
                if (node.left === null) {
                    node.left = newNode;
                }
                else{
                    insertNode(node.left,newNode);
                }
            }
            else{
                if (node.right === null) {
                    node.right = newNode;
                }
                else{
                    insertNode(node.right,newNode);
                }
            }
        }

     以上方法的意思是,先用新节点和根节点作对比,判断根节点左侧(新节点小于根节点)或右侧(新节点大于根节点)子节点是否有值,如果没有则插入,如果有,则继续用新节点和根节点的子节点比

    大小,做递归操作,逐步得到新节点插入位置,下面是插入节点的方法

    this.insert = function(key){
            var newNode = new Node(key);
    
            if (root === null) {
                root = newNode;
            }
            else{
                insertNode(node.left, newNode);
            }
        }

    1.3 遍历树

    遍历一棵树是指访问树的每一个节点,并对它们进行某种操作的过程。访问树的节点有三种方法,中序,先序和后序。

    1.3.1 中序遍历

    以最小到最大的顺序访问所有的节点

    var inOrderTraverseNode = function(node,callback){
            if (node !== null) {
                inOrderTraverseNode(node.left,callback);
                callback(node.key);
                inOrderTraverseNode(node.right,callback);
            }
        }
    this.inOrderTraverse = function(callback){
            inOrderTraverseNode(root,callback);
        }

    以上代码中,inOrderTraverse方法接受一个回掉函数作为参数,来定义对遍历到的每一个节点的操作,这个方法中调用了一个辅助方法inOrderTraverseNode,用来递归遍历所有值,当递归到最后一级

    时,观察辅助函数内部,调用回掉函数依次是左侧子节点,父节点,右侧子节点,所以执行回调函数顺序为按照节点值从小到大。

    1.3.2 先序遍历

    祖先节点优先于后代节点的顺序遍历

    var preOrderTraverseNode = function(node,callback){
            if (node !== null) {
                callback(node.key);
                preOrderTraverseNode(node.left,callback);
                preOrderTraverseNode(node.right,callback);
            }
        };
    
    this.preOrderTraverse = function(callback){
            preOrderTraverseNode(root,callback);
        }

    以上代码中,preOrderTraverse方法接受一个回掉函数作为参数,来定义对遍历到的每一个节点的操作,这个方法中调用了一个辅助方法preOrderTraverseNode,用来递归遍历所有值,当递归到最后一级

    时,观察辅助函数内部,调用回掉函数依次是父节点,左侧子节点,右侧子节点,所以遍历优先祖先节点。

    1.3.3 后序遍历

    先访问节点的后代节点,在访问节点本身

    var postOrderTraverseNode = function(node,callback){
            if (node !== null) {
                callback(node.key);
                postOrderTraverseNode(node.left,callback);
                postOrderTraverseNode(node.right,callback);
            }
        };
    this.postOrderTraverse = function(callback){
            postOrderTraverseNode(root,callback);
        }

    以上代码中,postOrderTraverse方法接受一个回掉函数作为参数,来定义对遍历到的每一个节点的操作,这个方法中调用了一个辅助方法postOrderTraverseNode,用来递归遍历所有值,当递归到最后一级

    时,观察辅助函数内部,调用回掉函数依次是左侧子节点,右侧子节点,父节点,所以遍历优先子节点。

    1.4 搜索树中的值

    1.4.1 最大值最小值

    最大值为搜索树右下角的值,最小值为搜索树左下角的值,下面来看实现

    1.最大值

    var maxNode = function(node){
            if (node) {
                while(node&&node.right !== null){
                    node = node.right;
                }
                return node.key;
            }
            return null;
        };
    this.max = function(){
            return maxNode(root);
        }

    2.最小值

    var minNode = function(node){
            if (node) {
                while(node&&node.left !== null){
                    node = node.left;
                }
                return node.key;
            }
            return null;
        };
    this.min = function(){
            return minNode(root);
        }

    实现最大值最小值,同样的方法,从根节点开始循环,直到右下角或左下角的值,返回回来。

    1.4.2 搜索任意值
    var searchNode = function(node,key){
            if (node === null) {
                return false;
            }
            if (key<node.key) {
                return searchNode(node.left,key)
            }
            else if (key>node.key) {
                return searchNode(node.right,key)
            }
            else{
                return true;
            }
        };
    this.search = function(key){
            return searchNode(root,key);
        }

    逻辑其实很简单,拿给定的节点从根节点开始查找,比根节点大,则继续与根节点右侧子节点比较,比根节点大,则继续与根节点左侧子节点比较,依次递归,直到给定节点与某节点相等,表示找到,

    返回true,如果没找到,返回false

    1.4.3 删除一个节点
    var removeNode = function(node,key){
            if (node === null) {
                return null;
            }
            if (key<node.key) {
                node.left = remove(node.left,key)
            }
            else if (key>node.key) {
                node.left = remove(node.right,key)
            }
            // 键等于node.key
            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;
            }
        }
    this.remove =function(key){
            root = removeNode(root,key);
        }

     上面当删除节点有两个子节点时,需要调用辅助方法findMinNode

    var minNodeSelf = function(node){
            if (node) {
                while(node&&node.left !== null){
                    node = node.left;
                }
                return node;
            }
            return null;
        };
    this.findMinNode = function(){
            return minNodeSelf(node);
        },

    下面是实现BST的完整代码

    function BinarySearchTree() {
        var Node = function(key){
            this.key = key;
            this.left = null;
            this.right = null;
        };
    
        var root = null;
    
        var insertNode = function(node,newNode){
            if (newNode.key < node.key) {
                if (node.left === null) {
                    node.left = newNode;
                }
                else{
                    insertNode(node.left,newNode);
                }
            }
            else{
                if (node.right === null) {
                    node.right = newNode;
                }
                else{
                    insertNode(node.right,newNode);
                }
            }
        };
    
        var inOrderTraverseNode = function(node,callback){
            if (node !== null) {
                inOrderTraverseNode(node.left,callback);
                callback(node.key);
                inOrderTraverseNode(node.right,callback);
            }
        };
    
        var preOrderTraverseNode = function(node,callback){
            if (node !== null) {
                callback(node.key);
                preOrderTraverseNode(node.left,callback);
                preOrderTraverseNode(node.right,callback);
            }
        };
    
        var postOrderTraverseNode = function(node,callback){
            if (node !== null) {
                callback(node.key);
                postOrderTraverseNode(node.left,callback);
                postOrderTraverseNode(node.right,callback);
            }
        };
    
        var maxNode = function(node){
            if (node) {
                while(node&&node.right !== null){
                    node = node.right;
                }
                return node.key;
            }
            return null;
        };
    
        var minNode = function(node){
            if (node) {
                while(node&&node.left !== null){
                    node = node.left;
                }
                return node.key;
            }
            return null;
        };
    
        var minNodeSelf = function(node){
            if (node) {
                while(node&&node.left !== null){
                    node = node.left;
                }
                return node;
            }
            return null;
        };
    
        var searchNode = function(node,key){
            if (node === null) {
                return false;
            }
            if (key<node.key) {
                return searchNode(node.left,key)
            }
            else if (key>node.key) {
                return searchNode(node.right,key)
            }
            else{
                return true;
            }
        };
    
        var removeNode = function(node,key){
            if (node === null) {
                return null;
            }
            if (key<node.key) {
                node.left = remove(node.left,key)
            }
            else if (key>node.key) {
                node.left = remove(node.right,key)
            }
            // 键等于node.key
            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;
            }
        };
    
        this.insert = function(key){
            var newNode = new Node(key);
    
            if (root === null) {
                root = newNode;
            }
            else{
                insertNode(node.left, newNode);
            }
        },
    
        this.inOrderTraverse = function(callback){
            inOrderTraverseNode(root,callback);
        },
    
        this.preOrderTraverse = function(callback){
            preOrderTraverseNode(root,callback);
        },
    
        this.postOrderTraverse = function(callback){
            postOrderTraverseNode(root,callback);
        },
    
        this.max = function(){
            return maxNode(root);
        },
    
        this.min = function(){
            return minNode(root);
        },
    
        this.findMinNode = function(){
            return minNodeSelf(root);
        },
    
        this.search = function(key){
            return searchNode(root,key);
        },
    
        this.remove =function(key){
            root = removeNode(root,key);
        }
    }
  • 相关阅读:
    嵌入式硬件设计时所需考虑的几个问题
    MySQL网络配置
    MySQL数据库操作技术大全
    关于硬件芯片未用引脚的处理方法
    与嵌入式软件开发相关的一些硬件知识
    C语言-联合(union)
    AtCoder Regular Contest 101 D
    AtCoder Regular Contest 101 C
    AtCoder Regular Contest 102 C
    线性基学习
  • 原文地址:https://www.cnblogs.com/Cathamerst/p/7231182.html
Copyright © 2011-2022 走看看