LoginSignup
4
5

More than 5 years have passed since last update.

あなたは何を検索しますか?〜btree.js

Posted at

データベースにも使われるb木をjavascriptで実装しました。
あなたは何を検索したいですか?

私は株情報を検索しています。

btree.js
var bNode = (function () {
    function bNode(barray, isleaf) {
        this.parentNode = null;
        this.barray = barray;
        this.isLeafNode = isleaf;
        this.data = [];
        if(isleaf == true) {
            this.barray.leaf_nodes.push(this);
        }
    }
    bNode.prototype.split = function () {
        var tmp = new bNode(this.barray, this.isLeafNode);
        var m = Math.ceil(this.data.length / 2);
        for(var i = 0; i < m; i++) {
            if(this.data[0].parentNode !== undefined) {
                this.data[0].parentNode = tmp;
            }
            tmp.data.push(this.data.shift());
        }
        var key = tmp.key = tmp.data[tmp.data.length - 1].key;
        if(this.parentNode == null) {
            var p = new bNode(this.barray, false);
            this.parentNode = tmp.parentNode = p;
            this.parentNode.data.push(tmp);
            this.parentNode.data.push(this);
            p.key = p.data[p.data.length - 1].key;
            return p;
        }
        return this.parentNode.insert_node(key, tmp);
    };
    bNode.prototype.insert = function (key, value) {
        var pos = 0;
        for(; pos < this.data.length; pos++) {
            if(this.data[pos].key == key) {
                this.data[pos].value = value;
                return null;
            }
            if(this.data[pos].key > key) {
                break;
            }
        }
        this.data.splice(pos, 0, {
            "key": key,
            "value": value,
            parentNode: this
        });
        this.key = this.data[this.data.length - 1].key;
        if(this.data.length > this.barray.order) {
            return this.split();
        }
        return null;
    };
    bNode.prototype.insert_node = function (key, node) {
        node.parentNode = this;
        var pos = 0;
        for(; pos < this.data.length; pos++) {
            if(this.data[pos].key > key) {
                break;
            }
        }
        this.data.splice(pos, 0, node);
        this.key = this.data[this.data.length - 1].key;
        if(this.data.length > this.barray.order) {
            return this.split();
        }
        return null;
    };
    bNode.prototype.delete = function (obj) {
        obj.node = obj.node.parentNode;
        for(; ; ) {
            if(obj.node.data.length == 1) {
                obj.node = obj.node.parentNode;
                if(obj.node == null) {
                    this.barray.root = null;
                    return;
                }
                obj.trace.shift();
            } else {
                break;
            }
        }
        if(obj.trace[0] == obj.node.data.length - 1) {
            obj.node.key = obj.node.data[obj.node.data.length - 2].key;
        }
        obj.node.data.splice(obj.trace[0], 1);
    };
    return bNode;
})();
var bArray = (function () {
    function bArray(order) {
        this.order = 100;
        this.leaf_nodes = [];
        this.order = order;
        this.root = new bNode(this, true);
    }
    bArray.prototype.restruct = function () {
        if(this.leaf_nodes.length > 10) {
            ;
        }
        var n = Math.floor(this.leaf_nodes.length / 2);
        this.root = new bNode(this, false);
        this.root.insert_node(this.leaf_nodes[0].key, this.leaf_nodes[0]);
        for(var i = 1; i < this.leaf_nodes.length; i++) {
            var leaf_node = this.leaf_nodes[(n + i) * 9998797 % this.leaf_nodes.length];
            var ret = this._search(leaf_node.key).node.parentNode.insert_node(leaf_node.key, leaf_node);
            if(ret != null) {
                this.root = ret;
            }
        }
    };
    bArray.prototype.set = function (key, value) {
        var node = this._search(key).node;
        var ret = node.insert(key, value);
        if(ret != null) {
            this.root = ret;
        }
    };
    bArray.prototype.set_with_array = function (datas) {
        for(var i = 0; i < datas.length; i++) {
            var n = i * 9998797 % datas.length;
            this.set(datas[n].key, datas[i].value);
        }
    };
    bArray.prototype.get = function (key) {
        var node = this._search(key).node;
        for(var i = 0; i < node.data.length; i++) {
            if(node.data[i].key == key) {
                return node.data[i].value;
            }
        }
        return null;
    };
    bArray.prototype.delete = function (key) {
        var node = this._search(key);
        var ret;
        for(var i = 0; i < node.node.data.length; i++) {
            if(node.node.data[i].key == key) {
                if(i == node.node.data.length - 1) {
                    if(node.node.data[0].length == 1) {
                        node.node.delete(node);
                        return node.node.data[0].value;
                    } else {
                        node.node.key = node.node.data[node.node.data.length - 2].key;
                    }
                }
                ret = node.node.data[i].value;
                node.node.data.splice(i, 1);
                return ret;
            }
        }
        return null;
    };
    bArray.prototype.delete_in = function (from, to) {
        var from_node = this._search(from);
        var to_node = this._search(to);
        var array = [];
        var i = 0;
        for(; i < from_node.node.data.length; i++) {
            if(from_node.node.data[i].key > from) {
                break;
            }
        }
        var now = from_node.node;
        for(; ; ) {
            if(now == to_node.node) {
                break;
            }
            now.data.splice(i, now.data.length - i);
            if(now.data.length == 0) {
                from_node.node = now;
                now.delete(from_node);
                from_node.trace[0]--;
            }
            for(; ; ) {
                from_node.trace[0]++;
                if(from_node.trace[0] >= now.parentNode.data.length) {
                    now = now.parentNode;
                    if(now == null) {
                        return array;
                    }
                    from_node.trace.shift();
                } else {
                    now = now.parentNode.data[from_node.trace[0]];
                    break;
                }
            }
            for(; now.isLeafNode == false; ) {
                now = now.data[0];
            }
            i = 0;
        }
        for(; i < to_node.node.data.length; i++) {
            if(i == to_node.node.data.length || to_node.node.data[i].key > to) {
                to_node.node.data.splice(0, i - 1);
                if(to_node.node.data.length == 0) {
                    to_node.node.delete(to_node);
                }
                break;
            }
        }
    };
    bArray.prototype.in = function (from, to) {
        var from_node = this._search(from);
        var to_node = this._search(to);
        var array = [];
        var i = 0;
        for(; i < from_node.node.data.length; i++) {
            if(from_node.node.data[i].key > from) {
                break;
            }
        }
        var now = from_node.node;
        for(; ; ) {
            if(now == to_node.node) {
                break;
            }
            for(; i < now.data.length; i++) {
                array.push(now.data[i].value);
            }
            for(; ; ) {
                from_node.trace[0]++;
                if(from_node.trace[0] >= now.parentNode.data.length) {
                    now = now.parentNode;
                    if(now == null) {
                        return array;
                    }
                    from_node.trace.shift();
                } else {
                    now = now.parentNode.data[from_node.trace[0]];
                    break;
                }
            }
            for(; now.isLeafNode == false; ) {
                now = now.data[0];
                from_node.trace.push(0);
            }
            i = 0;
        }
        for(; i < to_node.node.data.length; i++) {
            if(to_node.node.data[i].key > to) {
                break;
            }
            array.push(to_node.node.data[i].value);
        }
        return array;
    };
    bArray.prototype.getNode = function (key) {
        return this._search(key).node;
    };
    bArray.prototype._search = function (key) {
        var current = this.root;
        var found = false;
        var array = [];
        while(current.isLeafNode == false) {
            found = false;
            var len = current.data.length;
            for(var i = 0; i < len; i++) {
                if(current.data[i].key >= key) {
                    current = current.data[i];
                    found = true;
                    array.unshift(i);
                    break;
                }
            }
            if(found == false) {
                current = current.data[len - 1];
                array.unshift(len - 1);
            }
        }
        return {
            trace: array,
            node: current
        };
    };
    return bArray;
})();

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5