Skip to content

Commit 8f1f740

Browse files
committed
Add doubly linked list implementation
1 parent ba8aaed commit 8f1f740

6 files changed

Lines changed: 7363 additions & 0 deletions

File tree

linked-list/.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# metadata
2+
.exercism
3+
4+
# Dependency directories
5+
node_modules

linked-list/README.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# Linked List
2+
3+
Implement a doubly linked list.
4+
5+
Like an array, a linked list is a simple linear data structure. Several
6+
common data types can be implemented using linked lists, like queues,
7+
stacks, and associative arrays.
8+
9+
A linked list is a collection of data elements called *nodes*. In a
10+
*singly linked list* each node holds a value and a link to the next node.
11+
In a *doubly linked list* each node also holds a link to the previous
12+
node.
13+
14+
You will write an implementation of a doubly linked list. Implement a
15+
Node to hold a value and pointers to the next and previous nodes. Then
16+
implement a List which holds references to the first and last node and
17+
offers an array-like interface for adding and removing items:
18+
19+
* `push` (*insert value at back*);
20+
* `pop` (*remove value at back*);
21+
* `shift` (*remove value at front*).
22+
* `unshift` (*insert value at front*);
23+
24+
To keep your implementation simple, the tests will not cover error
25+
conditions. Specifically: `pop` or `shift` will never be called on an
26+
empty list.
27+
28+
If you want to know more about linked lists, check [Wikipedia](https://en.wikipedia.org/wiki/Linked_list).
29+
30+
## Setup
31+
32+
Go through the setup instructions for Javascript to
33+
install the necessary dependencies:
34+
35+
[https://exercism.io/tracks/javascript/installation](https://exercism.io/tracks/javascript/installation)
36+
37+
## Requirements
38+
39+
Install assignment dependencies:
40+
41+
```bash
42+
$ npm install
43+
```
44+
45+
## Making the test suite pass
46+
47+
Execute the tests with:
48+
49+
```bash
50+
$ npm test
51+
```
52+
53+
In the test suites all tests but the first have been skipped.
54+
55+
Once you get a test passing, you can enable the next one by
56+
changing `xtest` to `test`.
57+
58+
59+
## Source
60+
61+
Classic computer science topic
62+
63+
## Submitting Incomplete Solutions
64+
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

linked-list/linked-list.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
class Node{
2+
constructor(value){
3+
this.value = value;
4+
this.previous = null;
5+
this.next = null;
6+
}
7+
}
8+
9+
export default class LinkedList{
10+
constructor(){
11+
this.head = null;
12+
this.tail = null;
13+
this.length = 0;
14+
}
15+
16+
// Insert value at back
17+
push(value){
18+
const node = new Node(value);
19+
20+
if(!this.head){
21+
this.head = node;
22+
this.tail = node;
23+
} else{
24+
node.previous = this.tail;
25+
this.tail.next = node;
26+
this.tail = node;
27+
}
28+
this.length++;
29+
}
30+
31+
// Remove value at back
32+
pop(){
33+
if(!this.head) return null;
34+
35+
const previousNode = this.tail.previous;
36+
const oldTailValue = this.tail.value;
37+
38+
if(previousNode){
39+
previousNode.next = null;
40+
this.tail = previousNode;
41+
} else{
42+
this.head = null;
43+
this.tail = null;
44+
}
45+
this.length--;
46+
return oldTailValue;
47+
}
48+
49+
// Remove value at front
50+
shift(){
51+
if(!this.head) return null;
52+
53+
const nextNode = this.head.next;
54+
const oldHeadValue = this.head.value;
55+
56+
if(nextNode){
57+
nextNode.previous = null;
58+
this.head = nextNode;
59+
} else{
60+
this.head = null;
61+
this.tail = null;
62+
}
63+
this.length--;
64+
return oldHeadValue;
65+
}
66+
67+
// Insert value at front
68+
unshift(value){
69+
const node = new Node(value);
70+
71+
if(!this.head){
72+
this.head = node;
73+
this.tail = node;
74+
} else{
75+
this.head.previous = node;
76+
node.next = this.head;
77+
this.head = node;
78+
}
79+
this.length++;
80+
}
81+
82+
/*
83+
* Given a specific value,
84+
* finds this value and removes it.
85+
* If can't find it, list remains the same
86+
*/
87+
delete(value){
88+
if(this.head.value == value){
89+
this.shift();
90+
} else if(this.tail.value == value){
91+
this.pop();
92+
} else {
93+
let currentNode = this.head.next;
94+
while(true){
95+
if(currentNode == null) break;
96+
if(currentNode.value == value){
97+
currentNode.next.previous = currentNode.previous;
98+
currentNode.previous.next = currentNode.next;
99+
currentNode.previous = null;
100+
currentNode.next = null;
101+
this.length--;
102+
break;
103+
} else{
104+
currentNode = currentNode.next;
105+
}
106+
}
107+
}
108+
}
109+
110+
// Number of values in doubly linked list
111+
count(){
112+
return this.length;
113+
}
114+
}

linked-list/linked-list.spec.js

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import LinkedList from './linked-list';
2+
3+
describe('LinkedList', () => {
4+
test('add/extract elements to the end of the list with push/pop', () => {
5+
const list = new LinkedList();
6+
list.push(10);
7+
list.push(20);
8+
expect(list.pop()).toBe(20);
9+
expect(list.pop()).toBe(10);
10+
});
11+
test('extract elements from the beginning of the list with shift', () => {
12+
const list = new LinkedList();
13+
list.push(10);
14+
list.push(20);
15+
expect(list.shift()).toBe(10);
16+
expect(list.shift()).toBe(20);
17+
});
18+
test('add/extract elements from the beginning of the list with unshift/shift', () => {
19+
const list = new LinkedList();
20+
list.unshift(10);
21+
list.unshift(20);
22+
expect(list.shift()).toBe(20);
23+
expect(list.shift()).toBe(10);
24+
});
25+
test('unshift/pop', () => {
26+
const list = new LinkedList();
27+
list.unshift(10);
28+
list.unshift(20);
29+
expect(list.pop()).toBe(10);
30+
expect(list.pop()).toBe(20);
31+
});
32+
test('example', () => {
33+
const list = new LinkedList();
34+
list.push(10);
35+
list.push(20);
36+
expect(list.pop()).toBe(20);
37+
list.push(30);
38+
expect(list.shift()).toBe(10);
39+
list.unshift(40);
40+
list.push(50);
41+
expect(list.shift()).toBe(40);
42+
expect(list.pop()).toBe(50);
43+
expect(list.shift()).toBe(30);
44+
});
45+
test('can count its elements', () => {
46+
const list = new LinkedList();
47+
expect(list.count()).toBe(0);
48+
list.push(10);
49+
expect(list.count()).toBe(1);
50+
list.push(20);
51+
expect(list.count()).toBe(2);
52+
});
53+
test('sets head/tail after popping last element', () => {
54+
const list = new LinkedList();
55+
list.push(10);
56+
list.pop();
57+
list.unshift(20);
58+
expect(list.count()).toBe(1);
59+
expect(list.pop()).toBe(20);
60+
});
61+
test('sets head/tail after shifting last element', () => {
62+
const list = new LinkedList();
63+
list.unshift(10);
64+
list.shift();
65+
list.push(20);
66+
expect(list.count()).toBe(1);
67+
expect(list.shift()).toBe(20);
68+
});
69+
test('deletes the element with the specified value from the list', () => {
70+
const list = new LinkedList();
71+
list.push(10);
72+
list.push(20);
73+
list.push(30);
74+
list.delete(20);
75+
expect(list.count()).toBe(2);
76+
expect(list.pop()).toBe(30);
77+
expect(list.shift()).toBe(10);
78+
});
79+
test('deletes the only element', () => {
80+
const list = new LinkedList();
81+
list.push(10);
82+
list.delete(10);
83+
expect(list.count()).toBe(0);
84+
});
85+
test('deletes the first of two elements', () => {
86+
const list = new LinkedList();
87+
list.push(10);
88+
list.push(20);
89+
list.delete(10);
90+
expect(list.count()).toBe(1);
91+
expect(list.pop()).toBe(20);
92+
});
93+
test('deletes the second of two elements', () => {
94+
const list = new LinkedList();
95+
list.push(10);
96+
list.push(20);
97+
list.delete(20);
98+
expect(list.count()).toBe(1);
99+
expect(list.pop()).toBe(10);
100+
});
101+
test('delete does not modify the list if the element is not found', () => {
102+
const list = new LinkedList();
103+
list.push(10);
104+
list.delete(20);
105+
expect(list.count()).toBe(1);
106+
});
107+
});

0 commit comments

Comments
 (0)