135 lines
3.2 KiB
JavaScript
135 lines
3.2 KiB
JavaScript
// Copyright (c) 2011, Chris Umbel, James Coglan
|
|
// LinkedList class - required for Polygon class.
|
|
|
|
function LinkedList() {}
|
|
LinkedList.prototype = {
|
|
length: 0,
|
|
first: null,
|
|
last: null,
|
|
|
|
each: function(fn) {
|
|
var node = this.first, n = this.length;
|
|
for (var i = 0; i < n; i++) {
|
|
fn(node, i);
|
|
node = node.next;
|
|
}
|
|
},
|
|
|
|
at: function(i) {
|
|
if (!(i >= 0 && i < this.length)) { return null; }
|
|
var node = this.first;
|
|
while (i--) { node = node.next; }
|
|
return node;
|
|
},
|
|
|
|
randomNode: function() {
|
|
var n = Math.floor(Math.random() * this.length);
|
|
return this.at(n);
|
|
},
|
|
|
|
toArray: function() {
|
|
var arr = [], node = this.first, n = this.length;
|
|
while (n--) {
|
|
arr.push(node.data || node);
|
|
node = node.next;
|
|
}
|
|
return arr;
|
|
}
|
|
};
|
|
|
|
LinkedList.Node = function(data) {
|
|
this.prev = null; this.next = null;
|
|
this.data = data;
|
|
};
|
|
|
|
LinkedList.Circular = function() {};
|
|
LinkedList.Circular.Methods = {
|
|
append: function(node) {
|
|
if (this.first === null) {
|
|
node.prev = node;
|
|
node.next = node;
|
|
this.first = node;
|
|
this.last = node;
|
|
} else {
|
|
node.prev = this.last;
|
|
node.next = this.first;
|
|
this.first.prev = node;
|
|
this.last.next = node;
|
|
this.last = node;
|
|
}
|
|
this.length++;
|
|
},
|
|
|
|
prepend: function(node) {
|
|
if (this.first === null) {
|
|
this.append(node);
|
|
return;
|
|
} else {
|
|
node.prev = this.last;
|
|
node.next = this.first;
|
|
this.first.prev = node;
|
|
this.last.next = node;
|
|
this.first = node;
|
|
}
|
|
this.length++;
|
|
},
|
|
|
|
insertAfter: function(node, newNode) {
|
|
newNode.prev = node;
|
|
newNode.next = node.next;
|
|
node.next.prev = newNode;
|
|
node.next = newNode;
|
|
if (newNode.prev == this.last) { this.last = newNode; }
|
|
this.length++;
|
|
},
|
|
|
|
insertBefore: function(node, newNode) {
|
|
newNode.prev = node.prev;
|
|
newNode.next = node;
|
|
node.prev.next = newNode;
|
|
node.prev = newNode;
|
|
if (newNode.next == this.first) { this.first = newNode; }
|
|
this.length++;
|
|
},
|
|
|
|
remove: function(node) {
|
|
if (this.length > 1) {
|
|
node.prev.next = node.next;
|
|
node.next.prev = node.prev;
|
|
if (node == this.first) { this.first = node.next; }
|
|
if (node == this.last) { this.last = node.prev; }
|
|
} else {
|
|
this.first = null;
|
|
this.last = null;
|
|
}
|
|
node.prev = null;
|
|
node.next = null;
|
|
this.length--;
|
|
},
|
|
|
|
withData: function(data) {
|
|
var nodeFromStart = this.first, nodeFromEnd = this.last, n = Math.ceil(this.length / 2);
|
|
while (n--) {
|
|
if (nodeFromStart.data == data) { return nodeFromStart; }
|
|
if (nodeFromEnd.data == data) { return nodeFromEnd; }
|
|
nodeFromStart = nodeFromStart.next;
|
|
nodeFromEnd = nodeFromEnd.prev;
|
|
}
|
|
return null;
|
|
}
|
|
};
|
|
|
|
LinkedList.Circular.prototype = new LinkedList;
|
|
for (var method in LinkedList.Circular.Methods) {
|
|
LinkedList.Circular.prototype[method] = LinkedList.Circular.Methods[method];
|
|
}
|
|
|
|
LinkedList.Circular.fromArray = function(list, useNodes) {
|
|
var linked = new LinkedList.Circular();
|
|
var n = list.length;
|
|
while (n--) { linked.prepend(useNodes ? new LinkedList.Node(list[n]) : list[n]); }
|
|
return linked;
|
|
};
|
|
|
|
module.exports = LinkedList;
|