Skip to content

Commit 6ccf0f1

Browse files
feat: implement doubly linked list class
1 parent a558272 commit 6ccf0f1

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { DoublyNodeList, INode } from './DoublyNodeList';
2+
3+
export class DoublyLinkedList<T> {
4+
public head: INode<T> | null;
5+
public tail: INode<T> | null;
6+
protected length: number;
7+
8+
constructor(data?: T) {
9+
this.head = new DoublyNodeList(data);
10+
this.tail = this.head;
11+
this.length = 1;
12+
}
13+
14+
public append(data: T): DoublyLinkedList<T> {
15+
// Create a new node
16+
const newNode = new DoublyNodeList(data);
17+
// Add prev property at the end of the list
18+
newNode.prev = this.tail;
19+
// Attach it after the first node
20+
this.tail.next = newNode;
21+
// Update the tail to point the newNode
22+
this.tail = newNode;
23+
// Increment length
24+
this.length++;
25+
// Return the new created list
26+
return this;
27+
}
28+
29+
public prepend(data: T): DoublyLinkedList<T> {
30+
// Create a new node
31+
const newNode = new DoublyNodeList(data);
32+
//Check if there is no head to make a new node
33+
if (!this.head) {
34+
this.head = newNode;
35+
this.tail = newNode;
36+
37+
return this;
38+
}
39+
// Create a pointer to the head of the list
40+
newNode.next = this.head;
41+
// Point prev to new node because it's no longer the head
42+
this.head.prev = newNode;
43+
// Update head reference to the newNode
44+
this.head = newNode;
45+
// Increment length
46+
this.length++;
47+
// Return the new created list
48+
return this;
49+
}
50+
51+
// Prints linked list in array format for better readability
52+
public printList(): Array<T> {
53+
const array: T[] = [];
54+
let currentNode = this.head;
55+
while (currentNode !== null) {
56+
array.push(currentNode.data);
57+
currentNode = currentNode.next;
58+
}
59+
return array;
60+
}
61+
62+
public insert(index: number, data: T) {
63+
// Check params
64+
if (index >= this.length) {
65+
return this.append(data);
66+
}
67+
// Create a new node
68+
const newNode = new DoublyNodeList(data);
69+
// Get the index of previous node
70+
const prevNode = this.traverse(index - 1);
71+
// Temporarily hold the pointer to previous node
72+
const nextNode = prevNode.next;
73+
// Point previous node to the new one
74+
prevNode.next = newNode;
75+
// Point new node to previous
76+
newNode.prev = prevNode;
77+
// Point new node to next one
78+
newNode.next = nextNode;
79+
// Point back nextNode with the new one
80+
nextNode.prev = newNode;
81+
// Increment length
82+
this.length++;
83+
// Print list to the console
84+
return this.printList();
85+
}
86+
87+
public remove(index: number) {
88+
// Get the index of previous node
89+
const prevNode = this.traverse(index - 1);
90+
// Reference node to be removed
91+
const currentNode = prevNode.next;
92+
// Reference previous node with the next after the removed one
93+
prevNode.next = currentNode.next;
94+
// Decrease length
95+
this.length--;
96+
// Print list to the console
97+
return this.printList();
98+
}
99+
100+
private traverse(index: number): INode<T> {
101+
// Check params
102+
let counter = 0;
103+
let currentNode = this.head;
104+
while (counter !== index) {
105+
currentNode = currentNode.next;
106+
counter++;
107+
}
108+
return currentNode;
109+
}
110+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export interface INode<T> {
2+
data: T;
3+
next?: INode<T>;
4+
prev?: INode<T>;
5+
}
6+
7+
export class DoublyNodeList<T> implements INode<T> {
8+
public data: T;
9+
public next?: INode<T>;
10+
public prev?: INode<T>;
11+
12+
constructor(data?: T) {
13+
this.data = data;
14+
this.next = null;
15+
this.prev = null;
16+
}
17+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import { DoublyLinkedList } from '../DoublyLinkedList';
2+
3+
describe('Doubly Linked List', () => {
4+
test('create empty linked list', () => {
5+
const doublyLinkedList = new DoublyLinkedList<string>();
6+
7+
expect(doublyLinkedList.head).toEqual({
8+
data: undefined,
9+
next: null,
10+
prev: null,
11+
});
12+
});
13+
14+
test('append node to linked list', () => {
15+
const doublyLinkedList = new DoublyLinkedList<number>(10);
16+
17+
doublyLinkedList.append(15);
18+
doublyLinkedList.append(20);
19+
20+
expect(doublyLinkedList.head.prev).toBeNull();
21+
expect(doublyLinkedList.head.data).toBe(10);
22+
expect(doublyLinkedList.head.next.data).toBe(15);
23+
expect(doublyLinkedList.tail.data).toBe(20);
24+
expect(doublyLinkedList.tail.prev.data).toBe(15);
25+
expect(doublyLinkedList.tail.next).toBeNull();
26+
});
27+
28+
test('prepend node to linked list', () => {
29+
const doublyLinkedList = new DoublyLinkedList<number>();
30+
31+
doublyLinkedList.prepend(10);
32+
33+
expect(doublyLinkedList.head.data).toBe(10);
34+
expect(doublyLinkedList.tail.prev.data).toBe(10);
35+
36+
doublyLinkedList.append(15);
37+
doublyLinkedList.append(20);
38+
});
39+
40+
test('insert node list in a given index', () => {
41+
const doublyLinkedList = new DoublyLinkedList<object>();
42+
43+
const nodeValue1 = { value: 1, key: 'key1' };
44+
const nodeValue2 = { value: 2, key: 'key2' };
45+
const nodeValue3 = { value: 3, key: 'key3' };
46+
47+
doublyLinkedList
48+
.append(nodeValue3)
49+
.prepend(nodeValue1)
50+
.insert(1, nodeValue2);
51+
52+
expect(doublyLinkedList.head.data).toEqual({ value: 1, key: 'key1' });
53+
expect(doublyLinkedList.head.next.data).toEqual({ value: 2, key: 'key2' });
54+
expect(doublyLinkedList.tail.data).toEqual({ value: 3, key: 'key3' });
55+
});
56+
57+
test('print list in array format', () => {
58+
const doublyLinkedList = new DoublyLinkedList<number>(10);
59+
60+
doublyLinkedList.append(15);
61+
doublyLinkedList.append(20);
62+
doublyLinkedList.append(25);
63+
64+
expect(doublyLinkedList.printList()).toEqual([10, 15, 20, 25]);
65+
});
66+
});
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { DoublyNodeList } from '../DoublyNodeList';
2+
3+
describe('Doubly Linked List Node', () => {
4+
test('create empty node list', () => {
5+
const node = new DoublyNodeList<null>();
6+
7+
expect(node.data).toBeUndefined();
8+
expect(node.next).toBeNull();
9+
expect(node.next).toBeNull();
10+
});
11+
12+
test('create list node with object as a value', () => {
13+
const nodeValue = { key: 'test', value: 1 };
14+
const node = new DoublyNodeList(nodeValue);
15+
16+
expect(node.data.key).toBe('test');
17+
expect(node.data.value).toBe(1);
18+
expect(node.next).toBeNull();
19+
expect(node.prev).toBeNull();
20+
});
21+
});

0 commit comments

Comments
 (0)