Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2c8d383

Browse files
Merge pull request #92 from amejiarosario/feat/linkedlist
Feat/linkedlist
2 parents 0d7a14b + ba110e2 commit 2c8d383

File tree

12 files changed

+225
-232
lines changed

12 files changed

+225
-232
lines changed

‎book/content/part02/hash-map.asc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ A Map is a data structure where a `key` is mapped to a `value`. It's used for a
1111

1212
NOTE: Map has many terms depending on the programming language. Here are some other names: Hash Map, Hash Table, Associative Array, Unordered Map, Dictionary.
1313

14-
==== Map Application
14+
==== Map Applications
1515

1616
Maps are one of the most popular data structures because of their fast lookup time.
1717

‎book/content/part02/linked-list.asc

Lines changed: 78 additions & 95 deletions
Large diffs are not rendered by default.

‎book/images/dll-add-first.png

54.7 KB
Loading[フレーム]

‎book/images/dll-add-last.png

57.2 KB
Loading[フレーム]

‎book/images/dll-insert-middle.png

47.5 KB
Loading[フレーム]

‎book/images/dll-remove-first.png

15.9 KB
Loading[フレーム]

‎book/images/dll-remove-last.png

15.6 KB
Loading[フレーム]

‎book/images/dll-remove-middle.png

14.3 KB
Loading[フレーム]

‎book/images/dll.png

9.99 KB
Loading[フレーム]

‎src/data-structures/linked-lists/linked-list.js

Lines changed: 133 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,6 @@ class LinkedList {
1616
}
1717
// end::constructor[]
1818

19-
/**
20-
* Alias for size
21-
*/
22-
get length() {
23-
return this.size;
24-
}
25-
2619
// tag::addFirst[]
2720
/**
2821
* Adds element to the begining of the list. Similar to Array.unshift
@@ -34,9 +27,9 @@ class LinkedList {
3427

3528
newNode.next = this.first;
3629

37-
if (this.first) {
38-
this.first.previous = newNode;
39-
} else {
30+
if (this.first) {// check if first node exists (list not empty)
31+
this.first.previous = newNode;// <1>
32+
} else {// if list is empty, first & last will point to newNode.
4033
this.last = newNode;
4134
}
4235

@@ -59,11 +52,11 @@ class LinkedList {
5952
addLast(value) {
6053
const newNode = new Node(value);
6154

62-
if (this.first) {
55+
if (this.first) {// check if first node exists (list not empty)
6356
newNode.previous = this.last;
6457
this.last.next = newNode;
6558
this.last = newNode;
66-
} else {
59+
} else {// if list is empty, first & last will point to newNode.
6760
this.first = newNode;
6861
this.last = newNode;
6962
}
@@ -78,195 +71,157 @@ class LinkedList {
7871
/**
7972
* Insert new element at the given position (index)
8073
*
74+
* Runtime: O(n)
75+
*
8176
* @param {any} value new node's value
8277
* @param {Number} position position to insert element
83-
* @returns {Node} new node or 'undefined' if the index is out of bound.
78+
* @returns {Node|undefined} new node or 'undefined' if the index is out of bound.
8479
*/
85-
add(value, position = 0) {
86-
if (position === 0) { // <1>
87-
return this.addFirst(value);
88-
}
80+
addAt(value, position = 0) {
81+
if (position === 0) return this.addFirst(value); // <1>
82+
if (position === this.size) return this.addLast(value); // <2>
8983

90-
if (position === this.size) { // <2>
91-
return this.addLast(value);
92-
}
9384
// Adding element in the middle
94-
const current = this.get(position);
95-
if (current) {
96-
const newNode = new Node(value); // <3>
97-
newNode.previous = current.previous; // <4>
98-
newNode.next = current; // <5>
99-
100-
current.previous.next = newNode; // <6>
101-
current.previous = newNode; // <7>
102-
this.size += 1;
103-
return newNode;
104-
}
105-
106-
return undefined; // out of bound index
85+
const current = this.findBy({ index: position }).node;
86+
if (!current) return undefined; // out of bound index
87+
88+
const newNode = new Node(value); // <3>
89+
newNode.previous = current.previous; // <4>
90+
newNode.next = current; // <5>
91+
current.previous.next = newNode; // <6>
92+
current.previous = newNode; // <7>
93+
this.size += 1;
94+
return newNode;
10795
}
10896
// end::addMiddle[]
10997

11098
// tag::searchByValue[]
11199
/**
100+
* @deprecated use findBy
112101
* Search by value. It finds first occurrence of
113-
* the element matching the value.
102+
* the position of element matching the value.
103+
* Similar to Array.indexOf.
104+
*
114105
* Runtime: O(n)
106+
*
115107
* @example: assuming a linked list with: a -> b -> c
116-
* linkedList.indexOf('b') // ↪️ 1
117-
* linkedList.indexOf('z') // ↪️ undefined
108+
* linkedList.getIndexByValue('b') // ↪️ 1
109+
* linkedList.getIndexByValue('z') // ↪️ undefined
118110
* @param {any} value
119111
* @returns {number} return index or undefined
120112
*/
121-
indexOf(value) {
122-
return this.find((current, position) => {
123-
if (current.value === value) {
124-
return position;
125-
}
126-
return undefined;
127-
});
113+
getIndexByValue(value) {
114+
return this.findBy({ value }).index;
128115
}
129116
// end::searchByValue[]
130117

131118
// tag::searchByIndex[]
132119
/**
120+
* @deprecated use findBy directly
133121
* Search by index
134122
* Runtime: O(n)
135123
* @example: assuming a linked list with: a -> b -> c
136124
* linkedList.get(1) // ↪️ 'b'
137125
* linkedList.get(40) // ↪️ undefined
138126
* @param {Number} index position of the element
139-
* @returns {Node} element at the specified position in this list.
127+
* @returns {Node|undefined} element at the specified position in
128+
* this list or undefined if was not found.
140129
*/
141130
get(index = 0) {
142-
return this.find((current, position) => {
143-
if (position === index) {
144-
return current;
145-
}
146-
return undefined;
147-
});
131+
return this.findBy({ index }).node;
148132
}
149133
// end::searchByIndex[]
150134

151135
// tag::find[]
152136
/**
153-
* Iterate through the list until callback returns a truthy value
154-
* @example see #get and #indexOf
155-
* @param {Function} callback evaluates current node and index.
156-
* If any value other than undefined it's returned it will stop the search.
157-
* @returns {any} callbacks's return value or undefined
137+
* Find by index or by value, whichever happens first.
138+
* Runtime: O(n)
139+
* @example
140+
* this.findBy({ index: 10 }).node; // node at index 10.
141+
* this.findBy({ value: 10 }).node; // node with value 10.
142+
* this.findBy({ value: 10 }).index; // node's index with value 10.
143+
*
144+
* @param {Object} params - The search params
145+
* @param {number} params.index - The index/position to search for.
146+
* @param {any} params.value - The value to search for.
147+
* @returns {{node: any, index: number}}
158148
*/
159-
find(callback) {
149+
findBy({ value, index =Infinity}={}) {
160150
for (let current = this.first, position = 0; // <1>
161-
current; // <2>
151+
current&&position<=index; // <2>
162152
position += 1, current = current.next) { // <3>
163-
const result = callback(current, position); // <4>
164-
165-
if (result !== undefined) {
166-
return result; // <5>
153+
if (position === index || value === current.value) { // <4>
154+
return { node: current, index: position }; // <5>
167155
}
168156
}
169-
return undefined; // not found
157+
return {}; // not found
170158
}
171159
// end::find[]
172160

173161

174162
// tag::removeFirst[]
175163
/**
176164
* Removes element from the start of the list (head/root).
177-
* Similar to Array.shift
165+
* Similar to Array.shift().
178166
* Runtime: O(1)
179167
* @returns {any} the first element's value which was removed.
180168
*/
181169
removeFirst() {
170+
if (!this.first) return null; // Check if list is already empty.
182171
const head = this.first;
183172

184-
if (head) {
185-
this.first = head.next;
186-
if (this.first) {
187-
this.first.previous = null;
188-
} else {
189-
this.last = null;
190-
}
191-
this.size -= 1;
173+
this.first = head.next; // move first pointer to the next element.
174+
if (this.first) {
175+
this.first.previous = null;
176+
} else { // if list has size zero, then we need to null out last.
177+
this.last = null;
192178
}
193-
return head && head.value;
179+
this.size -= 1;
180+
return head.value;
194181
}
195182
// end::removeFirst[]
196183

197184
// tag::removeLast[]
198185
/**
199-
* Removes element to the end of the list. Similar to Array.pop
200-
* Using the `last.previous` we can reduce the runtime from O(n) to O(1)
186+
* Removes element to the end of the list.
187+
* Similar to Array.pop().
201188
* Runtime: O(1)
202-
* @returns {value} the last element's value which was removed
189+
* @returns {any} the last element's value which was removed
203190
*/
204191
removeLast() {
192+
if (!this.last) return null; // Check if list is already empty.
205193
const tail = this.last;
206194

207-
if (tail) {
208-
this.last = tail.previous;
209-
if (this.last) {
210-
this.last.next = null;
211-
} else {
212-
this.first = null;
213-
}
214-
this.size -= 1;
195+
this.last = tail.previous;
196+
if (this.last) {
197+
this.last.next = null;
198+
} else { // if list has size zero, then we need to null out first.
199+
this.first = null;
215200
}
216-
return tail && tail.value;
201+
this.size -= 1;
202+
return tail.value;
217203
}
218204
// end::removeLast[]
219205

220206
// tag::removeByPosition[]
221207
/**
222-
* Removes the element at the specified position in this list.
208+
* Removes the element at the given position (index) in this list.
223209
* Runtime: O(n)
224210
* @param {any} position
225211
* @returns {any} the element's value at the specified position that was removed.
226212
*/
227213
removeByPosition(position = 0) {
228-
const current = this.get(position);
229-
230-
if (position === 0) {
231-
this.removeFirst();
232-
} else if (position === this.size - 1) {
233-
this.removeLast();
234-
} else if (current) {
235-
current.previous.next = current.next;
236-
current.next.previous = current.previous;
237-
this.size -= 1;
238-
}
239-
214+
if (position === 0) return this.removeFirst();
215+
if (position === this.size - 1) return this.removeLast();
216+
const current = this.findBy({ index: position }).node;
217+
if (!current) return null;
218+
current.previous.next = current.next;
219+
current.next.previous = current.previous;
220+
this.size -= 1;
240221
return current && current.value;
241222
}
242223
// end::removeByPosition[]
243224

244-
/**
245-
* Removes the first occurrence of the specified elementt
246-
* from this list, if it is present.
247-
* Runtime: O(n)
248-
* @param {any} callbackOrIndex callback or position index to remove
249-
*/
250-
remove(callbackOrIndex) {
251-
if (typeof callbackOrIndex !== 'function') {
252-
return this.removeByPosition(parseInt(callbackOrIndex, 10) || 0);
253-
}
254-
255-
// find desired position to remove using #find
256-
const position = this.find((node, index) => {
257-
if (callbackOrIndex(node, index)) {
258-
return index;
259-
}
260-
return undefined;
261-
});
262-
263-
if (position !== undefined) { // zero-based position.
264-
return this.removeByPosition(position);
265-
}
266-
267-
return false;
268-
}
269-
270225
/**
271226
* Remove element by Node
272227
* O(1)
@@ -302,6 +257,61 @@ class LinkedList {
302257
const parts = [...this]; // see [Symbol.iterator]()
303258
return parts.map((n) => util.inspect(n.node.value)).join(' -> ');
304259
}
260+
261+
/**
262+
* Alias for size
263+
*/
264+
get length() {
265+
return this.size;
266+
}
267+
268+
/**
269+
* @deprecated use findBy
270+
* Iterate through the list until callback returns a truthy value
271+
* @example see #get and #getIndexByValue
272+
* @param {Function} callback evaluates current node and index.
273+
* If any value other than undefined it's returned it will stop the search.
274+
* @returns {any} callbacks's return value or undefined
275+
*/
276+
find(callback) {
277+
for (let current = this.first, position = 0; // <1>
278+
current; // <2>
279+
position += 1, current = current.next) { // <3>
280+
const result = callback(current, position); // <4>
281+
282+
if (result !== undefined) {
283+
return result; // <5>
284+
}
285+
}
286+
return undefined; // not found
287+
}
288+
289+
/**
290+
* @deprecated use removeByNode or removeByPosition
291+
* Removes the first occurrence of the specified elementt
292+
* from this list, if it is present.
293+
* Runtime: O(n)
294+
* @param {any} callbackOrIndex callback or position index to remove
295+
*/
296+
remove(callbackOrIndex) {
297+
if (typeof callbackOrIndex !== 'function') {
298+
return this.removeByPosition(parseInt(callbackOrIndex, 10) || 0);
299+
}
300+
301+
// find desired position to remove using #find
302+
const position = this.find((node, index) => {
303+
if (callbackOrIndex(node, index)) {
304+
return index;
305+
}
306+
return undefined;
307+
});
308+
309+
if (position !== undefined) { // zero-based position.
310+
return this.removeByPosition(position);
311+
}
312+
313+
return false;
314+
}
305315
}
306316

307317
// Aliases

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /