Skip to content

Commit

Permalink
Initial code for doubly linked list implementation.
Browse files Browse the repository at this point in the history
  • Loading branch information
bramstein committed Feb 2, 2010
1 parent 659819e commit c946a6b
Show file tree
Hide file tree
Showing 2 changed files with 338 additions and 0 deletions.
162 changes: 162 additions & 0 deletions src/core/linked-list.js
@@ -0,0 +1,162 @@

function LinkedList() {
this.head = null;
this.tail = null;
this.listSize = 0;
}
(function () {
Object.extend(LinkedList, {
Node: function (data) {
this.prev = null;
this.next = null;
this.data = data;
}
});

function isLinked(list, node) {
return !((node && node.prev === null && node.next === null && list.tail !== node && list.head !== node) || list.isEmpty());
}

Object.extend(LinkedList.prototype, {
size: function () {
return this.listSize;
},

isEmpty: function () {
return this.listSize === 0;
},

// Note that modifying the list during
// iteration is not safe.
forEach: function (fun) {
var node = this.head;
while (node !== null) {
fun(node);
node = node.next;
}
},

contains: function (n) {
var node = this.head;
if (!isLinked(this, n)) {
return false;
}
while (node !== null) {
if (node === n) {
return true;
}
node = node.next;
}
return false;
},

at: function (i) {
var node = this.head, index = 0;

if (i >= this.listLength || i < 0) {
return null;
}

while (node !== null) {
if (i === index) {
return node;
}
node = node.next;
index += 1;
}
return null;
},

insertAfter: function (node, newNode) {
if (!isLinked(this, node)) {
return this;
}
newNode.prev = node;
newNode.next = node.next;
if (node.next === null) {
this.tail = newNode;
} else {
node.next.prev = newNode;
}
node.next = newNode;
this.listSize += 1;
return this;
},

insertBefore: function (node, newNode) {
if (!isLinked(this, node)) {
return this;
}
newNode.prev = node.prev;
newNode.next = node;
if (node.prev === null) {
this.head = newNode;
} else {
node.prev.next = newNode;
}
node.prev = newNode;
this.listSize += 1;
return this;
},

push: function (node) {
if (this.head === null) {
this.unshift(node);
} else {
this.insertAfter(this.tail, node);
}
return this;
},

unshift: function (node) {
if (this.head === null) {
this.head = node;
this.tail = node;
node.prev = null;
node.next = null;
this.listSize += 1;
} else {
this.insertBefore(this.head, node);
}
return this;
},

remove: function (node) {
if (!isLinked(this, node)) {
return this;
}
if (node.prev === null) {
this.head = node.next;
} else {
node.prev.next = node.next;
}
if (node.next === null) {
this.tail = node.prev;
} else {
node.next.prev = node.prev;
}
this.listSize -= 1;
return this;
},

pop: function () {
var node = this.tail;
this.tail.prev.next = null;
this.tail = this.tail.prev;
this.listSize -= 1;
node.prev = null;
node.next = null;
return node;
},

shift: function () {
var node = this.head;
this.head.next.prev = null;
this.head = this.head.next;
this.listSize -= 1;
node.prev = null;
node.next = null;
return node;
}
});
}());
176 changes: 176 additions & 0 deletions test/core/linked-list.test.js
@@ -0,0 +1,176 @@
eval(loadFile("src/core/object.js"));
eval(loadFile("src/core/array.js"));
eval(loadFile("src/core/linked-list.js"));

testCases(test,
function setUp() {
},

function checkCreate() {
var l = new LinkedList();
assert.that(l, not(eq(undefined)));
},

function checkPush() {
var l = new LinkedList();
l.push(new LinkedList.Node(1));
assert.that(l.size(), eq(1));
l.push(new LinkedList.Node(2));
assert.that(l.size(), eq(2));
},

function checkAt() {
var l = new LinkedList();
l.push(new LinkedList.Node(1));
l.push(new LinkedList.Node(2));
l.push(new LinkedList.Node(3));
l.push(new LinkedList.Node(4));
assert.that(l.size(), eq(4));
assert.that(l.at(0).data, eq(1));
assert.that(l.at(3).data, eq(4));
assert.that(l.at(2).data, eq(3));
assert.that(l.at(1).data, eq(2));
assert.that(l.at(-1), eq(null));
assert.that(l.at(5), eq(null));
},

function checkContains() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3);

l.push(n1);
l.push(n2);

assert.that(l.contains(n1), isTrue());
assert.that(l.contains(n2), isTrue());
assert.that(l.contains(n3), isFalse());
},

function checkInsertAfter() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3),
n4 = new LinkedList.Node(4);

l.push(n1);
assert.that(l.size(), eq(1));
assert.that(l.at(0).data, eq(1));

l.insertAfter(n1, n2);
assert.that(l.size(), eq(2));
assert.that(l.at(1).data, eq(2));

l.insertAfter(n1, n3);
assert.that(l.size(), eq(3));
assert.that(l.at(1).data, eq(3));
assert.that(l.at(2).data, eq(2));

// Note that n4 is not part of the list so we shouldn't be able to insert it.
l.insertAfter(n4, n3);
assert.that(l.size(), eq(3));
},

function checkInsertBefore() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3),
n4 = new LinkedList.Node(4);

l.push(n1);
assert.that(l.size(), eq(1));
assert.that(l.at(0).data, eq(1));

l.insertBefore(n1, n2);
assert.that(l.size(), eq(2));
assert.that(l.at(0).data, eq(2));

l.insertBefore(n1, n3);
assert.that(l.size(), eq(3));
assert.that(l.at(0).data, eq(2));
assert.that(l.at(1).data, eq(3));
assert.that(l.at(2).data, eq(1));

// Note that n4 is not part of the list so we shouldn't be able to insert it.
l.insertBefore(n4, n3);
assert.that(l.size(), eq(3));
},

function checkUnshift() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3);
l.unshift(n1);
l.unshift(n2);
l.unshift(n3);

assert.that(l.size(), eq(3));
assert.that(l.at(0).data, eq(3));
assert.that(l.at(1).data, eq(2));
assert.that(l.at(2).data, eq(1));
},

function checkRemove() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3),
n4 = new LinkedList.Node(4);

l.push(n1);
l.push(n2);
l.push(n3);

assert.that(l.size(), eq(3));
l.remove(n2);
assert.that(l.size(), eq(2));
assert.that(l.at(0).data, eq(1));
assert.that(l.at(1).data, eq(3));

l.remove(n4);
assert.that(l.size(), eq(2));
},

function checkShift() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3);

l.push(n1);
l.push(n2);
l.push(n3);
assert.that(l.size(), eq(3));
l.shift();
assert.that(l.size(), eq(2));
assert.that(l.at(0).data, eq(2));
assert.that(l.at(1).data, eq(3));
},


function checkPop() {
var l = new LinkedList(),
n1 = new LinkedList.Node(1),
n2 = new LinkedList.Node(2),
n3 = new LinkedList.Node(3);

l.push(n1);
l.push(n2);
l.push(n3);
assert.that(l.size(), eq(3));
l.pop();
assert.that(l.size(), eq(2));
assert.that(l.at(0).data, eq(1));
assert.that(l.at(1).data, eq(2));
},

function checkForEach() {
},

function tearDown() {
}
);

0 comments on commit c946a6b

Please sign in to comment.