Skip to content

Commit 1ec54a0

Browse files
author
Nicholas C. Zakas
committed
Classic implementation of a linked list that doesn't store length
1 parent 3b5229f commit 1ec54a0

File tree

2 files changed

+398
-0
lines changed

2 files changed

+398
-0
lines changed
Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
<html>
2+
<head>
3+
<title>Linked List Tests</title>
4+
<!-- Combo-handled YUI CSS files: -->
5+
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/combo?2.7.0/build/logger/assets/logger.css&2.7.0/build/yuitest/assets/testlogger.css">
6+
<!-- Combo-handled YUI JS files: -->
7+
<script type="text/javascript" src="http://yui.yahooapis.com/combo?2.7.0/build/yahoo-dom-event/yahoo-dom-event.js&2.7.0/build/logger/logger-min.js&2.7.0/build/yuitest/yuitest-min.js"></script>
8+
<script type="text/javascript" src="linked-list-classic.js"></script>
9+
10+
11+
</head>
12+
<body>
13+
<h1>Linked List Tests</h1>
14+
<script type="text/javascript">
15+
16+
YAHOO.namespace("test");
17+
18+
YAHOO.test.LinkedList = (function(){
19+
20+
var assert = YAHOO.util.Assert;
21+
22+
//-------------------------------------------------------------------------
23+
// Base Test Suite
24+
//-------------------------------------------------------------------------
25+
26+
var suite = new YAHOO.tool.TestSuite("Linked List Tests");
27+
28+
//-------------------------------------------------------------------------
29+
// Test Case for adding
30+
//-------------------------------------------------------------------------
31+
32+
suite.add(new YAHOO.tool.TestCase({
33+
34+
name : "add() Tests",
35+
36+
setUp: function(){
37+
this.list = new LinkedList();
38+
},
39+
40+
tearDown: function(){
41+
delete this.list;
42+
},
43+
44+
//---------------------------------------------------------------------
45+
// Tests
46+
//---------------------------------------------------------------------
47+
48+
testAddSingle: function(){
49+
this.list.add("Hi");
50+
51+
assert.areEqual(1, this.list.size(), "List should have one item.");
52+
assert.areEqual("Hi", this.list._head.data, "First item should have data of 'Hi'.");
53+
assert.isNull(this.list._head.next, "The next pointer of the first item should be null.");
54+
},
55+
56+
testAddMultiple: function(){
57+
this.list.add("Hi");
58+
this.list.add("Yo");
59+
60+
assert.areEqual(2, this.list.size(), "List should have one item.");
61+
assert.areEqual("Hi", this.list._head.data, "First item should have data of 'Hi'.");
62+
assert.isNull(this.list._head.next.next, "The next pointer of the second item should be null.");
63+
}
64+
}));
65+
66+
//-------------------------------------------------------------------------
67+
// Test Case for retrieving values
68+
//-------------------------------------------------------------------------
69+
70+
suite.add(new YAHOO.tool.TestCase({
71+
72+
name : "item() Tests",
73+
74+
setUp: function(){
75+
this.list = new LinkedList();
76+
this.list.add("Hi");
77+
this.list.add("Yo");
78+
this.list.add("Bye");
79+
},
80+
81+
tearDown: function(){
82+
delete this.list;
83+
},
84+
85+
//---------------------------------------------------------------------
86+
// Tests
87+
//---------------------------------------------------------------------
88+
89+
testGetFirstItem: function(){
90+
var value = this.list.item(0);
91+
assert.areEqual("Hi", value, "First item should be 'Hi'.");
92+
},
93+
94+
testGetMiddleItem: function(){
95+
var value = this.list.item(1);
96+
assert.areEqual("Yo", value, "Second item should be 'Yo'.");
97+
},
98+
99+
testGetLastItem: function(){
100+
var value = this.list.item(2);
101+
assert.areEqual("Bye", value, "Second item should be 'Bye'.");
102+
},
103+
104+
testGetInvalidItem: function(){
105+
var value = this.list.item(5);
106+
assert.isNull(value, "Invalid items should return null.");
107+
},
108+
109+
110+
}));
111+
112+
//-------------------------------------------------------------------------
113+
// Test Case for removing values
114+
//-------------------------------------------------------------------------
115+
116+
suite.add(new YAHOO.tool.TestCase({
117+
118+
name : "remove() Tests",
119+
120+
setUp: function(){
121+
this.list = new LinkedList();
122+
this.list.add("Hi");
123+
this.list.add("Yo");
124+
this.list.add("Bye");
125+
},
126+
127+
tearDown: function(){
128+
delete this.list;
129+
},
130+
131+
//---------------------------------------------------------------------
132+
// Tests
133+
//---------------------------------------------------------------------
134+
135+
testRemoveFirstItem: function(){
136+
var value = this.list.remove(0);
137+
assert.areEqual("Hi", value, "Removed item should be 'Hi'.");
138+
assert.areEqual(2, this.list.size(), "There should only be two items left.");
139+
assert.areEqual("Yo", this.list.item(0), "First item should now be 'Yo'.");
140+
assert.areEqual("Bye", this.list.item(1), "Last item should now be 'Bye'.");
141+
assert.isNull(this.list.item(2), "Item in position 2 should be null.");
142+
},
143+
144+
testRemoveMiddleItem: function(){
145+
var value = this.list.remove(1);
146+
assert.areEqual("Yo", value, "Removed item should be 'Yo'.");
147+
assert.areEqual(2, this.list.size(), "There should only be two items left.");
148+
assert.areEqual("Hi", this.list.item(0), "First item should now be 'Yo'.");
149+
assert.areEqual("Bye", this.list.item(1), "Last item should now be 'Bye'.");
150+
assert.isNull(this.list.item(2), "Item in position 2 should be null.");
151+
},
152+
153+
testRemoveLastItem: function(){
154+
var value = this.list.remove(2);
155+
assert.areEqual("Bye", value, "Removed item should be 'Bye'.");
156+
assert.areEqual(2, this.list.size(), "There should only be two items left.");
157+
assert.areEqual("Hi", this.list.item(0), "First item should now be 'Hi'.");
158+
assert.areEqual("Yo", this.list.item(1), "Last item should now be 'Yo'.");
159+
assert.isNull(this.list.item(2), "Item in position 2 should be null.");
160+
}
161+
}));
162+
163+
//-------------------------------------------------------------------------
164+
// Test Case for converting to an array
165+
//-------------------------------------------------------------------------
166+
167+
suite.add(new YAHOO.tool.TestCase({
168+
169+
name : "toArray() Tests",
170+
171+
setUp: function(){
172+
this.list = new LinkedList();
173+
},
174+
175+
tearDown: function(){
176+
delete this.list;
177+
},
178+
179+
//---------------------------------------------------------------------
180+
// Tests
181+
//---------------------------------------------------------------------
182+
183+
testToArrayForEmptyList: function(){
184+
var value = this.list.toArray();
185+
assert.isInstanceOf(Array, value, "Value should be an array.");
186+
assert.areEqual(0, value.length, "Array should be empty.");
187+
},
188+
189+
testToArrayForOneItemList: function(){
190+
this.list.add("Hi");
191+
var value = this.list.toArray();
192+
assert.isInstanceOf(Array, value, "Value should be an array.");
193+
assert.areEqual(1, value.length, "Array should have 1 item.");
194+
assert.areEqual("Hi", value[0], "The only item should be 'Hi'.");
195+
},
196+
197+
testToArrayForTwoItemList: function(){
198+
this.list.add("Hi");
199+
this.list.add("Yo");
200+
var value = this.list.toArray();
201+
assert.isInstanceOf(Array, value, "Value should be an array.");
202+
assert.areEqual(2, value.length, "Array should have 2 items.");
203+
assert.areEqual("Hi", value[0], "The first item should be 'Hi'.");
204+
assert.areEqual("Yo", value[1], "The second item should be 'Yo'.");
205+
}
206+
207+
208+
}));
209+
210+
//return it
211+
return suite;
212+
213+
})();
214+
215+
(function (){
216+
//create the logger
217+
var logger = new YAHOO.tool.TestLogger();
218+
219+
//add the tests
220+
YAHOO.tool.TestRunner.add(YAHOO.test.LinkedList);
221+
YAHOO.tool.TestRunner.run();
222+
223+
})();
224+
225+
226+
</script>
227+
</body>
228+
</html>
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
/*
2+
* Linked List implementation in JavaScript
3+
* Copyright (c) 2009 Nicholas C. Zakas
4+
* MIT Licensed - see LICENSE for details on license.
5+
*/
6+
7+
/**
8+
* A linked list implementation in JavaScript. This is a more "classic"
9+
* approach that doesn't keep track of the number of items in the list
10+
* and instead calculates the size when necessary.
11+
* @class LinkedList
12+
* @constructor
13+
*/
14+
function LinkedList() {
15+
16+
/**
17+
* Pointer to first item in the list.
18+
* @property _head
19+
* @type Object
20+
* @private
21+
*/
22+
this._head = null;
23+
}
24+
25+
LinkedList.prototype = {
26+
27+
//restore constructor
28+
constructor: LinkedList,
29+
30+
/**
31+
* Appends some data to the end of the list. This method traverses
32+
* the existing list and places the value at the end in a new item.
33+
* @param {variant} data The data to add to the list.
34+
* @return {Void}
35+
* @method add
36+
*/
37+
add: function (data){
38+
39+
//create a new item object, place data in
40+
var node = {
41+
data: data,
42+
next: null
43+
},
44+
45+
//used to traverse the structure
46+
current;
47+
48+
//special case: no items in the list yet
49+
if (this._head === null){
50+
this._head = node;
51+
} else {
52+
current = this._head;
53+
54+
while(current.next){
55+
current = current.next;
56+
}
57+
58+
current.next = node;
59+
}
60+
61+
},
62+
63+
/**
64+
* Retrieves the data in the given position in the list.
65+
* @param {int} index The zero-based index of the item whose value
66+
* should be returned.
67+
* @return {variant} The value in the "data" portion of the given item
68+
* or null if the item doesn't exist.
69+
* @method item
70+
*/
71+
item: function(index){
72+
73+
//check for out-of-bounds values
74+
if (index > -1){
75+
var current = this._head,
76+
i = 0;
77+
78+
while(i++ < index && current){
79+
current = current.next;
80+
}
81+
82+
return (current ? current.data : null);
83+
} else {
84+
return null;
85+
}
86+
},
87+
88+
/**
89+
* Removes the item from the given location in the list.
90+
* @param {int} index The zero-based index of the item to remove.
91+
* @return {variant} The data in the given position in the list or null if
92+
* the item doesn't exist.
93+
* @method remove
94+
*/
95+
remove: function(index){
96+
97+
//check for out-of-bounds values
98+
if (index > -1){
99+
100+
var current = this._head,
101+
previous,
102+
i = 0;
103+
104+
//special case: removing first item
105+
if (index === 0){
106+
this._head = current.next;
107+
} else {
108+
109+
//find the right location
110+
while(i++ < index){
111+
previous = current;
112+
current = current.next;
113+
}
114+
115+
//skip over the item to remove
116+
previous.next = current.next;
117+
}
118+
119+
//return the value
120+
return (current ? current.data : null);
121+
122+
} else {
123+
return null;
124+
}
125+
126+
},
127+
128+
/**
129+
* Returns the number of items in the list.
130+
* @return {int} The number of items in the list.
131+
* @method size
132+
*/
133+
size: function(){
134+
var current = this._head,
135+
count = 0;
136+
137+
while(current){
138+
count++;
139+
current = current.next;
140+
}
141+
142+
return count;
143+
},
144+
145+
/**
146+
* Converts the list into an array.
147+
* @return {Array} An array containing all of the data in the list.
148+
* @method toArray
149+
*/
150+
toArray: function(){
151+
var result = [],
152+
current = this._head;
153+
154+
while(current){
155+
result.push(current.data);
156+
current = current.next;
157+
}
158+
159+
return result;
160+
},
161+
162+
/**
163+
* Converts the list into a string representation.
164+
* @return {String} A string representation of the list.
165+
* @method toString
166+
*/
167+
toString: function(){
168+
return this.toArray().toString();
169+
}
170+
};

0 commit comments

Comments
 (0)