Javascript-BinarySearchTree

二叉搜索树融合了二分查找的高效简洁以及链式数据结构删除元素的优雅。这样一个优秀的数据结构,使用的频率很高。如常见的LRU缓存淘汰算法等, 几乎任何可以想到的查找算法都可以用它来替换。日常工程代码中一般对效率不高,一些常用的查找算法已经可以胜任了。这里把之前写的C语言版的实现转换过来,并扩充一些接口,实现一个完整版本的BST。

基本结构

function BSTree(compare) {
    this.root = null;
    this.compare = compare;
}

function BSTreeNode(k, v, n) {
    this.N = n;
    this.key = k;
    this.value = v;
}

常用接口

查找元素

    BSTree.prototype.get = function(k) {
        function travel(node) {
            if(!node) return null;
            var ret = self.compare(k, node.key);
            if(ret == 0) return node;
            if(ret < 0) {
                return travel(node.right);
            }
            else {
                return travel(node.left);
            }
        }

        var self = this;
        return travel(this.root);
    }

get操作算是BST最基本的操作之一,基于BST左子树小于当前节点、右子树大于当前节点的原则,可以轻易的写出相应的实现。


计算节点个树

BSTree.prototype.size = function() {
    return this._size(this.root);
}

BSTree.prototype._size = function(root) {
    return root ? root.N : 0;
}

计算节点直接返回根节点上N即可。


插入/更新节点

BSTree.prototype.put = function(k, v) {
    function travel(node) {
        if(!node) return new BSTreeNode(k, v, 1);
        var ret = self.compare(k, node.key);
        if(ret == 0) {
            node.value = v;
            return node;
        }
        else if(ret < 0) {
            node.left = travel(node.left);
        }
        else {
            node.right = travel(node.right);
        }
        node.N = self._size(node.left) + self._size(node.right) + 1;
        return node;
    }

    var self = this;
    travel(this.root);
}

put实现的也比较简单,对于这类第归类型的算法考虑几个特殊用例即可。譬如说root不存在即:node==null,此时需要新建一个节点并返回。新节点的键值大于当前节点,所以更新当前节点的右边只树,新节点的键值小于当前节点,更新当前节点的左子树。


最大节点与最小节点

BSTree.prototype.min = function(root) {
    if(!root) root = this.root;

    function travel(root) {
        if(!root) return null;
        if(root.left) {
            return travel(root.left);
        }
        return travel(root);
    }

    return travel(root);
}

BSTree.prototype.max = function(root) {
    if(!root) root = this.root;

    function travel(root) {
        if(!root) return null;
        if(root.right) {
            return travel(root.right);
        }
        return travel(root);
    }

    return travel(root);
}

查找排名为n的节点

BSTree.prototype.select = function(n) {
    function travel(node, n) {
        if(!node) return null;
        var size = self._size(node.left);
        if(size == n) return node;
        if(size > n) return travel(node.left, n);
        else {
            return travale(node.right, n - size - 1);
        }
    }

    var self = this;
    return travel(this.root, n); 
}

查找键值为k的节点排名

    BSTree.prototyoe.rank = function(k) {
        function travel(node) {
            if(!node) return 0;
            var ret = self.compare(k, node.key);
            if(ret == 0) return self._size(node.left) + 1;
            if(ret < 0) { return travel(node.left);}
            else {
                return self._size(node.left) + 1 + travel(node.right);
            }
        }

        var self = this;
        return travel(this.root);
    }

近似节点

BSTree.prototype.floor = function(k) {
    function travel(node) {
        if(!node) return null;
        var ret = self.compare(k, node.key);
        if(ret == 0) {
            return node;
        }
        if(ret < 0) {
            var tmp =  travel(node.left);
            return tmp ? tmp : node;
        }
        else {
            return travel(node.right);
        }
    }

    var self = this;
    return travel(this.root);
}

BSTree.prototype.ceiling = function(k) {
    function travel(node) {
        if(!node) return null;
        var ret = self.compare(k, node.key);
        if(ret == 0) {
            return node;
        }
        if(ret > 0) {
            var tmp =  travel(node.right);
            return tmp ? tmp : node;
        }
        else {
            return travel(node.left);
        }
    }

    var self = this;
    return travel(this.root);
}

floor和ceiling的基本含义与js的Math对象对应的接口基本类似。floor取大于等于指定键值的最小节点。ceiling取小于等于指定节点的最大节点。


查找指定范围内的键值

BSTree.prototype.keys = function(lo, hi) {
    function travel(node) {
        if(!node) return;
        var ret1 = self.compare(lo, node.key);
        var ret2 = self.compare(hi, node.key);

        if(ret1 > 0) {
            return travel(node.right);
        }
        else if(ret2 < 0) {
            return travel(node.left);
        }
        else {
            arr.push(node.key);
        }
    }

    var arr = [];
    var self = this;
    travel(this.root);
    return arr;
}

删除最大/最小节点

BSTree.prototype.deleteMin = function() {
    this.root = this._deleteMin(this.root);
}

BSTree.prototype._deleteMin = function(root) {
    if(!root) return null;

    function travel(node) {
        if(node.left) node.left = travel(node.left);
        else {
            return node.right;
        }
    }

    var self = this;
    return travel(root);    
}

BSTree.prototype.deleteMax = function() {
    this.root = this._deleteMax(this.root);
}

BSTree.prototype._deleteMax = function(root) {
    if(!root) return null;

    function travel(node) {
        if(node.left) node.right = travel(node.right);
        else {
            return node.left;
        }
    }

    var self = this;
    return travel(root);
}

deleteMax和deleteMin的实现刚好相反,这里删除节点的时候只需要修改一个链接比较容易实现。


删除指定节点

BSTree.prototype.delete = function(k) {
    function travel(node) {
        if(!node) return null;
        var ret = self.compare(k, node.key);
        if(ret > 0) return node.right = travel(node.right);
        if(ret < 0) return node.left  = travel(node.left);
        if(ret == 0) {
            if(!node.left) return node.right;
            if(!node.right) return node.left;
            var tmp = node;
            node = self._min(node.right);
            node.left = tmp.left;
            node.right = self._deleteMin(node.right);
        }
        node.N = self._size(node.left) + self._size(node.right) + 1;
        return node;
    }

    var self = this;
    this.root = travel(this.root);
}

删除指定节点需要考虑被删除节点leftright都存在的情况。基本思路就是用该节点的后继节点来替代该节点。


  • that all
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java实现BinarySearchTree的delete方法的示例代码: ``` public class BinarySearchTree { private Node root; private class Node { private int key; private Node left, right; public Node(int key) { this.key = key; } } public void delete(int key) { root = delete(root, key); } private Node delete(Node x, int key) { if (x == null) return null; if (key < x.key) { x.left = delete(x.left, key); } else if (key > x.key) { x.right = delete(x.right, key); } else { if (x.left == null) return x.right; if (x.right == null) return x.left; Node t = x; x = min(t.right); x.right = deleteMin(t.right); x.left = t.left; } return x; } private Node min(Node x) { if (x.left == null) return x; return min(x.left); } private Node deleteMin(Node x) { if (x.left == null) return x.right; x.left = deleteMin(x.left); return x; } } ``` 在该实现中,delete方法首先调用delete(Node x, int key)方法,传入根节点和待删除的键。 delete(Node x, int key)方法递归遍历二叉搜索树,查找要删除的键所对应的节点。如果找到了该节点,就执行删除操作。如果节点有左右子树,就用它的右子树中的最小值节点来替代这个节点,然后删除右子树中的最小值节点。 delete(Node x, int key)方法还调用了min(Node x)和deleteMin(Node x)方法。min(Node x)方法返回以节点x为根的子树中的最小节点,deleteMin(Node x)方法删除以节点x为根的子树中的最小节点,并返回删除后的子树。 注意:以上代码仅供参考,未经完整测试,可能存在错误,请谨慎使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值