blob: bbb0a0bcce42ce4f2e8570bd3dd0cb5b45558155 [file] [log] [blame]
/*
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;
};
};