Skip to content

Commit f266ebe

Browse files
committed
Added linked list data structure with unit test cases
1 parent fef5000 commit f266ebe

File tree

2 files changed

+186
-9
lines changed

2 files changed

+186
-9
lines changed

src/linked-list/linked-list.js

Lines changed: 89 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ export class Node {
1010
get next() {
1111
return this._next;
1212
}
13+
set next(node) {
14+
this._next = node;
15+
}
1316
}
1417

1518

@@ -22,6 +25,15 @@ export class LinkedList {
2225
this[_head] = null;
2326
}
2427

28+
*[Symbol.iterator]() {
29+
let element = this.head;
30+
31+
while (element !== null) {
32+
yield element.key;
33+
element = element.next;
34+
}
35+
}
36+
2537
get head() {
2638
return this[_head];
2739
}
@@ -34,10 +46,80 @@ export class LinkedList {
3446
return this.size() === 0;
3547
}
3648

37-
search(item) { }
38-
insertLast(item) { }
39-
insertFirst(item) { }
40-
insertBefore(item, before) { }
41-
insertAfter(item, after) { }
42-
remove(item) { }
43-
}
49+
search(item) {
50+
return this._search(item).found;
51+
}
52+
53+
insert(item) {
54+
if(this.isEmpty()) {
55+
this.insertFirst(item);
56+
} else {
57+
this.insertLast(item);
58+
}
59+
this[_size] += 1;
60+
}
61+
62+
insertLast(item) {
63+
let el = this[_head];
64+
while(el && el.next !== null) {
65+
el = el.next;
66+
}
67+
68+
el.next = new Node(item);
69+
}
70+
71+
insertFirst(item) {
72+
this[_head] = new Node(item);
73+
}
74+
75+
insertBefore(item, before) {
76+
const {prev, curr, found} = this._search(before);
77+
78+
if(found) {
79+
const node = new Node(item);
80+
if(prev === null) {
81+
this[_head] = node;
82+
} else {
83+
prev.next = node;
84+
}
85+
node.next = curr;
86+
this[_size] += 1;
87+
}
88+
}
89+
insertAfter(item, after) {
90+
const {curr, next, found} = this._search(after);
91+
92+
if(found) {
93+
curr.next = new Node(item);
94+
curr.next.next = next;
95+
this[_size] += 1;
96+
}
97+
}
98+
remove(item) {
99+
const {prev, next, found} = this._search(item);
100+
if(found) {
101+
if(prev === null) {
102+
this[_head] = next;
103+
} else {
104+
prev.next = next;
105+
}
106+
this[_size] -= 1;
107+
}
108+
}
109+
110+
_search(item) {
111+
let prev = null, curr = this.head, next = null, found = false;
112+
while(curr !== null && !found) {
113+
// TODO: Check for Object and Array as well
114+
if(curr.key === item) {
115+
next = curr.next;
116+
found = true;
117+
break;
118+
}
119+
prev = curr;
120+
curr = curr.next;
121+
}
122+
123+
return {prev, curr, next, found};
124+
}
125+
}

src/linked-list/linked-list.spec.js

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { LinkedList } from './linked-list';
33
describe('Linked List', () => {
44
let list;
55
beforeEach(() => {
6-
list = new LinkedList
6+
list = new LinkedList;
77
});
88

99
it('should create a linked list object', () => {
@@ -12,4 +12,99 @@ describe('Linked List', () => {
1212
expect(list.head).toBe(null);
1313
expect(list.isEmpty()).toBeTruthy();
1414
});
15-
});
15+
16+
it('should insert first item in the linked list', () => {
17+
spyOn(list, 'insertFirst').and.callThrough();
18+
list.insert('firstVal');
19+
20+
expect(list.insertFirst).toHaveBeenCalled();
21+
expect(list.insertFirst).toHaveBeenCalledWith('firstVal');
22+
expect(list.size()).toBe(1);
23+
expect(list.isEmpty()).toBeFalsy();
24+
expect(list.head.key).toContain('firstVal');
25+
expect(list.head.next).toBe(null);
26+
});
27+
28+
describe('When first item is inserted', () => {
29+
beforeEach(() => {
30+
list.insert('firstVal');
31+
});
32+
33+
it('should insert items at the end', () => {
34+
spyOn(list, 'insertLast').and.callThrough();
35+
expect(list.size()).toBe(1);
36+
list.insert('secondVal');
37+
38+
expect(list.insertLast).toHaveBeenCalled();
39+
expect(list.insertLast).toHaveBeenCalledWith('secondVal');
40+
expect(list.size()).toBe(2);
41+
expect(list.head.next.key).toBe('secondVal');
42+
expect(list.head.next.next).toBe(null);
43+
});
44+
45+
it('should insert item after specified item', () => {
46+
list.insertAfter('secondVal', 'firstVal');
47+
expect(list.size()).toBe(2);
48+
expect(list.search('secondVal')).toBeTruthy();
49+
50+
list.insertAfter('thirdVal', 'xyz');
51+
expect(list.size()).toBe(2);
52+
expect(list.search('thirdVal')).toBeFalsy();
53+
54+
list.insertAfter('thirdVal', 'firstVal');
55+
expect(list.size()).toBe(3);
56+
expect(list.search('thirdVal')).toBeTruthy();
57+
58+
expect([...list][1]).toContain('thirdVal');
59+
expect([...list][2]).toContain('secondVal');
60+
});
61+
62+
it('should insert item before specified item', () => {
63+
list.insertBefore('secondVal', 'firstVal');
64+
expect(list.size()).toBe(2);
65+
expect(list.search('secondVal')).toBeTruthy();
66+
67+
list.insertBefore('thirdVal', 'firstVal');
68+
expect(list.size()).toBe(3);
69+
expect(list.search('thirdVal')).toBeTruthy();
70+
71+
list.insertBefore('forthVal', 'xyz');
72+
expect(list.size()).toBe(3);
73+
expect(list.search('forthVal')).toBeFalsy();
74+
});
75+
});
76+
77+
it('should search for item', () => {
78+
expect(list.search('A')).toBeFalsy();
79+
80+
list.insert('A');
81+
list.insert('B');
82+
list.insert('C');
83+
84+
expect(list.search('B')).toBeTruthy();
85+
expect(list.search('C')).toBeTruthy();
86+
expect(list.search('D')).toBeFalsy();
87+
});
88+
89+
it('should remove items from list', () => {
90+
expect(list.size()).toBe(0);
91+
92+
list.insert('A');
93+
list.insert('B');
94+
list.insert('C');
95+
expect(list.size()).toBe(3);
96+
97+
list.remove('B');
98+
expect(list.size()).toBe(2);
99+
expect(list.search('B')).toBeFalsy();
100+
101+
list.remove('A');
102+
expect(list.size()).toBe(1);
103+
expect(list.search('A')).toBeFalsy();
104+
105+
list.remove('C');
106+
expect(list.size()).toBe(0);
107+
expect(list.search('C')).toBeFalsy();
108+
});
109+
110+
});

0 commit comments

Comments
 (0)