Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
        Copyright (c) 2004-2006, The Dojo Foundation
        All Rights Reserved.

        Licensed under the Academic Free License version 2.1 or above OR the
        modified BSD license. For more information on Dojo licensing, see:

                http://dojotoolkit.org/community/licensing.shtml
*/

dojo.provide("dojo.collections.SkipList");
dojo.require("dojo.collections.Collections");
dojo.require("dojo.experimental");
dojo.experimental("dojo.collections.SkipList");
dojo.collections.SkipList = function () {
        function node(height, val) {
                this.value = val;
                this.height = height;
                this.nodes = new nodeList(height);
                this.compare = function (val) {
                        if (this.value > val) {
                                return 1;
                        }
                        if (this.value < val) {
                                return -1;
                        }
                        return 0;
                };
                this.incrementHeight = function () {
                        this.nodes.incrementHeight();
                        this.height++;
                };
                this.decrementHeight = function () {
                        this.nodes.decrementHeight();
                        this.height--;
                };
        }
        function nodeList(height) {
                var arr = [];
                this.height = height;
                for (var i = 0; i < height; i++) {
                        arr[i] = null;
                }
                this.item = function (i) {
                        return arr[i];
                };
                this.incrementHeight = function () {
                        this.height++;
                        arr[this.height] = null;
                };
                this.decrementHeight = function () {
                        arr.splice(arr.length - 1, 1);
                        this.height--;
                };
        }
        function iterator(list) {
                this.element = list.head;
                this.atEnd = function () {
                        return (this.element == null);
                };
                this.get = function () {
                        if (this.atEnd()) {
                                return null;
                        }
                        this.element = this.element.nodes[0];
                        return this.element;
                };
                this.reset = function () {
                        this.element = list.head;
                };
        }
        function chooseRandomHeight(max) {
                var level = 1;
                while (Math.random() < PROB && level < max) {
                        level++;
                }
                return level;
        }
        var PROB = 0.5;
        var comparisons = 0;
        this.head = new node(1);
        this.count = 0;
        this.add = function (val) {
                var updates = [];
                var current = this.head;
                for (var i = this.head.height; i >= 0; i--) {
                        if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) {
                                comparisons++;
                        }
                        while (current.nodes[i] != null && current.nodes[i].compare(val) < 0) {
                                current = current.nodes[i];
                                comparisons++;
                        }
                        updates[i] = current;
                }
                if (current.nodes[0] != null && current.nodes[0].compare(val) == 0) {
                        return;
                }
                var n = new node(val, chooseRandomHeight(this.head.height + 1));
                this.count++;
                if (n.height > this.head.height) {
                        this.head.incrementHeight();
                        this.head.nodes[this.head.height - 1] = n;
                }
                for (i = 0; i < n.height; i++) {
                        if (i < updates.length) {
                                n.nodes[i] = updates[i].nodes[i];
                                updates[i].nodes[i] = n;
                        }
                }
        };
        this.contains = function (val) {
                var current = this.head;
                var i;
                for (i = this.head.height - 1; i >= 0; i--) {
                        while (current.item(i) != null) {
                                comparisons++;
                                var result = current.nodes[i].compare(val);
                                if (result == 0) {
                                        return true;
                                } else {
                                        if (result < 0) {
                                                current = current.nodes[i];
                                        } else {
                                                break;
                                        }
                                }
                        }
                }
                return false;
        };
        this.getIterator = function () {
                return new iterator(this);
        };
        this.remove = function (val) {
                var updates = [];
                var current = this.head;
                for (var i = this.head.height - 1; i >= 0; i--) {
                        if (!(current.nodes[i] != null && current.nodes[i].compare(val) < 0)) {
                                comparisons++;
                        }
                        while (current.nodes[i] != null && current.nodes[i].compare(val) < 0) {
                                current = current.nodes[i];
                                comparisons++;
                        }
                        updates[i] = current;
                }
                current = current.nodes[0];
                if (current != null && current.compare(val) == 0) {
                        this.count--;
                        for (var i = 0; i < this.head.height; i++) {
                                if (updates[i].nodes[i] != current) {
                                        break;
                                } else {
                                        updates[i].nodes[i] = current.nodes[i];
                                }
                        }
                        if (this.head.nodes[this.head.height - 1] == null) {
                                this.head.decrementHeight();
                        }
                }
        };
        this.resetComparisons = function () {
                comparisons = 0;
        };
};