Skip to content

Commit 52cb8a2

Browse files
committed
capter 05: [LinkedLists]
1 parent 17cfa43 commit 52cb8a2

18 files changed

+1821
-7
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ Work in Progress.
1616
* 04: [Queues and Deques](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter04)
1717
* 05: [LinkedLists](https://github.com/loiane/javascript-datastructures-algorithms/tree/third-edition/examples/chapter05)
1818

19-
## Thrid Edition Updates
19+
### Third Edition Updates
2020

2121
* Algorithms using ES2015+
22-
* Creation of a Data Structure and Algorithms library that can be used in the browser or with Node.js
22+
* Creation of a Data Structures and Algorithms library that can be used in the browser or with Node.js
2323
* Algorithms tested with Mocha + Chai (test code available in `test` directory)
2424
* TypeScript version of the source code included
2525

examples/PacktDataStructuresAlgorithms.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import { defaultEquals } from '../util';
2+
import LinkedList from './linked-list';
3+
import { Node } from './models/linked-list-models';
4+
5+
export default class CircularLinkedList extends LinkedList {
6+
constructor(equalsFn = defaultEquals) {
7+
super(equalsFn);
8+
}
9+
getLastElement() {
10+
let current = this.head;
11+
for (let i = 2; i <= this.size() && current != null; i++) {
12+
current = current.next;
13+
}
14+
return current;
15+
}
16+
push(element) {
17+
const node = new Node(element);
18+
let current;
19+
if (this.head == null) {
20+
this.head = node;
21+
} else {
22+
current = this.getLastElement();
23+
current.next = node;
24+
}
25+
// set node.next to head - to have circular list
26+
node.next = this.head;
27+
this.count++;
28+
}
29+
insert(element, index) {
30+
if (index >= 0 && index <= this.count) {
31+
const node = new Node(element);
32+
let current = this.head;
33+
if (index === 0) {
34+
if (this.head == null) {
35+
// if no node in list
36+
this.head = node;
37+
node.next = this.head;
38+
} else {
39+
node.next = current;
40+
current = this.getLastElement();
41+
// update last element
42+
this.head = node;
43+
current.next = this.head;
44+
}
45+
} else {
46+
const previous = this.getElementAt(index - 1);
47+
node.next = previous.next;
48+
previous.next = node;
49+
}
50+
this.count++;
51+
return true;
52+
}
53+
return false;
54+
}
55+
removeAt(index) {
56+
if (index >= 0 && index < this.count) {
57+
let current = this.head;
58+
if (index === 0) {
59+
const removed = this.head;
60+
if (this.size() === 1) {
61+
this.head = undefined;
62+
} else {
63+
current = this.getLastElement();
64+
this.head = this.head.next;
65+
current.next = this.head;
66+
current = removed;
67+
}
68+
} else {
69+
// no need to update last element for circular list
70+
const previous = this.getElementAt(index - 1);
71+
current = previous.next;
72+
previous.next = current.next;
73+
}
74+
this.count--;
75+
return current.element;
76+
}
77+
return undefined;
78+
}
79+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import { defaultEquals } from '../util';
2+
import LinkedList from './linked-list';
3+
import { DoublyNode } from './models/linked-list-models';
4+
5+
export default class DoublyLinkedList extends LinkedList {
6+
constructor(equalsFn = defaultEquals) {
7+
super(equalsFn);
8+
}
9+
push(element) {
10+
const node = new DoublyNode(element);
11+
if (this.head == null) {
12+
this.head = node;
13+
this.tail = node; // NEW
14+
} else {
15+
// attach to the tail node // NEW
16+
this.tail.next = node;
17+
node.prev = this.tail;
18+
this.tail = node;
19+
}
20+
this.count++;
21+
}
22+
insert(element, index) {
23+
if (index >= 0 && index <= this.count) {
24+
const node = new DoublyNode(element);
25+
let current = this.head;
26+
if (index === 0) {
27+
if (this.head == null) {
28+
// NEW
29+
this.head = node;
30+
this.tail = node;
31+
} else {
32+
node.next = this.head;
33+
this.head.prev = node; // NEW
34+
this.head = node;
35+
}
36+
} else if (index === this.count) {
37+
// last item // NEW
38+
current = this.tail; // {2}
39+
current.next = node;
40+
node.prev = current;
41+
this.tail = node;
42+
} else {
43+
const previous = this.getElementAt(index - 1);
44+
current = previous.next;
45+
node.next = current;
46+
previous.next = node;
47+
current.prev = node; // NEW
48+
node.prev = previous; // NEW
49+
}
50+
this.count++;
51+
return true;
52+
}
53+
return false;
54+
}
55+
removeAt(index) {
56+
if (index >= 0 && index < this.count) {
57+
let current = this.head;
58+
if (index === 0) {
59+
this.head = this.head.next; // {1}
60+
// if there is only one item, then we update tail as well //NEW
61+
if (this.count === 1) {
62+
// {2}
63+
this.tail = undefined;
64+
} else {
65+
this.head.prev = undefined; // {3}
66+
}
67+
} else if (index === this.count - 1) {
68+
// last item //NEW
69+
current = this.tail; // {4}
70+
this.tail = current.prev;
71+
this.tail.next = undefined;
72+
} else {
73+
current = this.getElementAt(index);
74+
const previous = current.prev;
75+
// link previous with current's next - skip it to remove
76+
previous.next = current.next; // {6}
77+
current.next.prev = previous; // NEW
78+
}
79+
this.count--;
80+
return current.element;
81+
}
82+
return undefined;
83+
}
84+
indexOf(element) {
85+
let current = this.head;
86+
let index = 0;
87+
while (current != null) {
88+
if (this.equalsFn(element, current.element)) {
89+
return index;
90+
}
91+
index++;
92+
current = current.next;
93+
}
94+
return -1;
95+
}
96+
getHead() {
97+
return this.head;
98+
}
99+
getTail() {
100+
return this.tail;
101+
}
102+
clear() {
103+
super.clear();
104+
this.tail = undefined;
105+
}
106+
toString() {
107+
if (this.head == null) {
108+
return '';
109+
}
110+
let objString = `${this.head.element}`;
111+
let current = this.head.next;
112+
while (current != null) {
113+
objString = `${objString},${current.element}`;
114+
current = current.next;
115+
}
116+
return objString;
117+
}
118+
inverseToString() {
119+
if (this.tail == null) {
120+
return '';
121+
}
122+
let objString = `${this.tail.element}`;
123+
let previous = this.tail.prev;
124+
while (previous != null) {
125+
objString = `${objString},${previous.element}`;
126+
previous = previous.prev;
127+
}
128+
return objString;
129+
}
130+
}

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

+105
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { defaultEquals } from '../util';
2+
import { Node } from './models/linked-list-models';
3+
4+
export default class LinkedList {
5+
constructor(equalsFn = defaultEquals) {
6+
this.equalsFn = equalsFn;
7+
this.count = 0;
8+
}
9+
push(element) {
10+
const node = new Node(element);
11+
let current;
12+
if (this.head == null) {
13+
// catches null && undefined
14+
this.head = node;
15+
} else {
16+
current = this.head;
17+
while (current.next != null) {
18+
current = current.next;
19+
}
20+
current.next = node;
21+
}
22+
this.count++;
23+
}
24+
getElementAt(index) {
25+
if (index >= 0 && index <= this.count) {
26+
let node = this.head;
27+
for (let i = 0; i < index && node != null; i++) {
28+
node = node.next;
29+
}
30+
return node;
31+
}
32+
return undefined;
33+
}
34+
insert(element, index) {
35+
if (index >= 0 && index <= this.count) {
36+
const node = new Node(element);
37+
const current = this.head;
38+
if (index === 0) {
39+
node.next = current;
40+
this.head = node;
41+
} else {
42+
const previous = this.getElementAt(index - 1);
43+
node.next = previous.next;
44+
previous.next = node;
45+
}
46+
this.count++;
47+
return true;
48+
}
49+
return false;
50+
}
51+
removeAt(index) {
52+
if (index >= 0 && index < this.count) {
53+
let current = this.head;
54+
if (index === 0) {
55+
this.head = current.next;
56+
} else {
57+
const previous = this.getElementAt(index - 1);
58+
current = previous.next;
59+
previous.next = current.next;
60+
}
61+
this.count--;
62+
return current.element;
63+
}
64+
return undefined;
65+
}
66+
remove(element) {
67+
const index = this.indexOf(element);
68+
return this.removeAt(index);
69+
}
70+
indexOf(element) {
71+
let current = this.head;
72+
for (let i = 0; i < this.size() && current != null; i++) {
73+
if (this.equalsFn(element, current.element)) {
74+
return i;
75+
}
76+
current = current.next;
77+
}
78+
return -1;
79+
}
80+
isEmpty() {
81+
return this.size() === 0;
82+
}
83+
size() {
84+
return this.count;
85+
}
86+
getHead() {
87+
return this.head;
88+
}
89+
clear() {
90+
this.head = undefined;
91+
this.count = 0;
92+
}
93+
toString() {
94+
if (this.head == null) {
95+
return '';
96+
}
97+
let objString = `${this.head.element}`;
98+
let current = this.head.next;
99+
for (let i = 1; i < this.size() && current != null; i++) {
100+
objString = `${objString},${current.element}`;
101+
current = current.next;
102+
}
103+
return objString;
104+
}
105+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export class Node {
2+
constructor(element, next) {
3+
this.element = element;
4+
this.next = next;
5+
}
6+
}
7+
export class DoublyNode extends Node {
8+
constructor(element, next, prev) {
9+
super(element, next);
10+
this.prev = prev;
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Compare, defaultCompare, defaultEquals } from '../util';
2+
import LinkedList from './linked-list';
3+
4+
export default class SortedLinkedList extends LinkedList {
5+
constructor(equalsFn = defaultEquals, compareFn = defaultCompare) {
6+
super(equalsFn);
7+
this.equalsFn = equalsFn;
8+
this.compareFn = compareFn;
9+
}
10+
push(element) {
11+
if (this.isEmpty()) {
12+
super.push(element);
13+
} else {
14+
const index = this.getIndexNextSortedElement(element);
15+
super.insert(element, index);
16+
}
17+
}
18+
insert(element, index = 0) {
19+
if (this.isEmpty()) {
20+
return super.insert(element, index === 0 ? index : 0);
21+
}
22+
const pos = this.getIndexNextSortedElement(element);
23+
return super.insert(element, pos);
24+
}
25+
getIndexNextSortedElement(element) {
26+
let current = this.head;
27+
let i = 0;
28+
for (; i < this.size() && current; i++) {
29+
const comp = this.compareFn(element, current.element);
30+
if (comp === Compare.LESS_THAN) {
31+
return i;
32+
}
33+
current = current.next;
34+
}
35+
return i;
36+
}
37+
}

src/js/index.js

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@ import StackArray from './data-structures/stack-array';
88
import Stack from './data-structures/stack';
99
import { parenthesesChecker } from './others/balanced-symbols';
1010

11+
import * as _util from './util';
12+
13+
export { default as CircularLinkedList } from './data-structures/circular-linked-list';
14+
export { default as DoublyLinkedList } from './data-structures/doubly-linked-list';
15+
export { default as LinkedList } from './data-structures/linked-list';
16+
export { default as SortedLinkedList } from './data-structures/sorted-linked-list';
17+
18+
export const util = _util;
19+
1120
export {
1221
Stack,
1322
StackArray,

0 commit comments

Comments
 (0)