Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial code for doubly linked list implementation.
- Loading branch information
Showing
2 changed files
with
338 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} | ||
}); | ||
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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() { | ||
} | ||
); |