First commit
This commit is contained in:
commit
57cfa8ad19
4
package.json
Normal file
4
package.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"type": "module",
|
||||||
|
"main": "./src/usage.js"
|
||||||
|
}
|
118
src/structures/binary-search-tree.js
Normal file
118
src/structures/binary-search-tree.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
const root = Symbol("root");
|
||||||
|
|
||||||
|
class BinarySearchTreeNode {
|
||||||
|
constructor (value) {
|
||||||
|
this.value = value;
|
||||||
|
this.left = null;
|
||||||
|
this.right = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BinarySearchTree {
|
||||||
|
constructor () {
|
||||||
|
this[root] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
add (value) {
|
||||||
|
const node = new BinarySearchTreeNode(value);
|
||||||
|
let current = null;
|
||||||
|
|
||||||
|
// No items in tree
|
||||||
|
if (this[root] === null) {
|
||||||
|
this[root] = node;
|
||||||
|
} else {
|
||||||
|
current = this[root];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (value < current.value) {
|
||||||
|
// If there's no left, insert
|
||||||
|
if (current.left === null) {
|
||||||
|
current.left = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.left;
|
||||||
|
|
||||||
|
} else if (value > current.value) {
|
||||||
|
if (current.right === null) {
|
||||||
|
current.right = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.right;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contains (value) {
|
||||||
|
let found = false;
|
||||||
|
let current = this[root];
|
||||||
|
|
||||||
|
while ( ! found && current !== null) {
|
||||||
|
if (value < current.value) {
|
||||||
|
current = current.left;
|
||||||
|
} else if (value > current.value) {
|
||||||
|
current = current.right;
|
||||||
|
} else if (value === current.value) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size () {
|
||||||
|
let length = 0;
|
||||||
|
|
||||||
|
this.traverse(() => {
|
||||||
|
length++;
|
||||||
|
});
|
||||||
|
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
traverse (process) {
|
||||||
|
const inOrder = (node) => {
|
||||||
|
if ( ! node) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// traverse the left subtree
|
||||||
|
if (node.left !== null) {
|
||||||
|
inOrder(node.left);
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle the current node
|
||||||
|
process.call(this, node);
|
||||||
|
|
||||||
|
// traverse the right subtree
|
||||||
|
if (node.right !== null) {
|
||||||
|
inOrder(node.right);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// start with the root
|
||||||
|
inOrder(this[root]);
|
||||||
|
}
|
||||||
|
|
||||||
|
toArray () {
|
||||||
|
let result = [];
|
||||||
|
|
||||||
|
this.traverse((node) => {
|
||||||
|
result.push(node.value);
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
toString () {
|
||||||
|
return this.toArray().toString();
|
||||||
|
}
|
||||||
|
}
|
131
src/structures/circular-doubly-linked-list.js
Normal file
131
src/structures/circular-doubly-linked-list.js
Normal file
@ -0,0 +1,131 @@
|
|||||||
|
const head = Symbol("head");
|
||||||
|
const tail = Symbol("tail");
|
||||||
|
|
||||||
|
class CircularDoublyLinkedListNode {
|
||||||
|
constructor (data) {
|
||||||
|
this.data = data;
|
||||||
|
this.next = null;
|
||||||
|
this.previous = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CircularDoublyLinkedList {
|
||||||
|
constructor () {
|
||||||
|
this[head] = null;
|
||||||
|
this[tail] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
add (data) {
|
||||||
|
const newNode = new CircularDoublyLinkedListNode(data);
|
||||||
|
|
||||||
|
// Special case: no items in the list
|
||||||
|
if (this[head] === null) {
|
||||||
|
this[head] = newNode;
|
||||||
|
newNode.next = newNode;
|
||||||
|
newNode.previous = newNode;
|
||||||
|
} else {
|
||||||
|
const tail = this[head].previous;
|
||||||
|
|
||||||
|
tail.next = newNode;
|
||||||
|
newNode.previous = tail;
|
||||||
|
newNode.next = this[head];
|
||||||
|
this[head].previous = newNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get (index) {
|
||||||
|
if ( ! Number(index) < 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = this[head];
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if (i === index) {
|
||||||
|
return current.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
current = current.next;
|
||||||
|
i++;
|
||||||
|
} while ((current !== this[head]) && (i <= index));
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (index) {
|
||||||
|
if ((this[head] === null) || (index < 0)) {
|
||||||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = this[head];
|
||||||
|
|
||||||
|
// Removing the first node
|
||||||
|
if (index === 0) {
|
||||||
|
if (current.next === this[head]) {
|
||||||
|
this[head] = null;
|
||||||
|
} else {
|
||||||
|
const tail = this[head].previous;
|
||||||
|
|
||||||
|
// Set the tail to point to the second item in the list
|
||||||
|
// and point the new item to the tail
|
||||||
|
tail.next = current.next;
|
||||||
|
current.next.previous = tail;
|
||||||
|
|
||||||
|
this[head] = tail.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
current = current.next;
|
||||||
|
i++;
|
||||||
|
} while ((current !== this[head]) && (i < index));
|
||||||
|
|
||||||
|
if (current !== this[head]) {
|
||||||
|
// skip over the node to remove it
|
||||||
|
current.previous.next = current.next;
|
||||||
|
current.next.previous = current.previous;
|
||||||
|
|
||||||
|
return current.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
*values () {
|
||||||
|
// list is empty
|
||||||
|
if (this[head] !== null) {
|
||||||
|
// only one node
|
||||||
|
if (this[head].next === this[head]) {
|
||||||
|
yield this[head].data;
|
||||||
|
} else {
|
||||||
|
let current = this[head];
|
||||||
|
|
||||||
|
do {
|
||||||
|
yield current.data;
|
||||||
|
current = current.next;
|
||||||
|
} while (current !== this[head]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*circularValues () {
|
||||||
|
if (this[head] !== null) {
|
||||||
|
let current = this[head];
|
||||||
|
|
||||||
|
// infinite loop
|
||||||
|
while (true) {
|
||||||
|
yield current.data;
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator] () {
|
||||||
|
return this.values();
|
||||||
|
}
|
||||||
|
}
|
117
src/structures/doubly-linked-list.js
Normal file
117
src/structures/doubly-linked-list.js
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
const head = Symbol("head");
|
||||||
|
const tail = Symbol("tail");
|
||||||
|
|
||||||
|
class DoublyLinkedListNode {
|
||||||
|
constructor (data) {
|
||||||
|
this.data = data;
|
||||||
|
this.next = null;
|
||||||
|
this.previous = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DoublyLinkedList {
|
||||||
|
constructor () {
|
||||||
|
this[head] = null;
|
||||||
|
this[tail] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
add (data) {
|
||||||
|
const newNode = new DoublyLinkedListNode(data);
|
||||||
|
|
||||||
|
// special case: no nodes
|
||||||
|
if (this[head] === null) {
|
||||||
|
this[head] = newNode;
|
||||||
|
} else {
|
||||||
|
// link the current tail and new tail
|
||||||
|
this[tail].next = newNode;
|
||||||
|
newNode.previous = this[tail];
|
||||||
|
}
|
||||||
|
|
||||||
|
// re-assign the tail
|
||||||
|
this[tail] = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
get (index) {
|
||||||
|
if ( ! Number(index) < 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = this[head];
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while ((current !== null) && (i < index)) {
|
||||||
|
current = current.next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current !== null
|
||||||
|
? current.data
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (index) {
|
||||||
|
if ((this[head] === null) || (index < 0)) {
|
||||||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// special case: removing the first node
|
||||||
|
if (index === 0) {
|
||||||
|
const data = this[head].data;
|
||||||
|
this[head] = this[head].next;
|
||||||
|
|
||||||
|
// Only one node
|
||||||
|
if (this[head] === null) {
|
||||||
|
this[tail] = null;
|
||||||
|
} else {
|
||||||
|
this[head].previous = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = this[head];
|
||||||
|
let i = 0;
|
||||||
|
while ((current !== null) && (i < index)) {
|
||||||
|
current = current.next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If node was found remove it
|
||||||
|
if (current !== null) {
|
||||||
|
current.previous.next = current.next;
|
||||||
|
|
||||||
|
// last node
|
||||||
|
if (this[tail] === current) {
|
||||||
|
this[tail] = current.previous;
|
||||||
|
} else {
|
||||||
|
current.next.previous = current.previous;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
*values () {
|
||||||
|
let current = this[head];
|
||||||
|
|
||||||
|
while (current !== null) {
|
||||||
|
yield current.data;
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*reverse () {
|
||||||
|
let current = this[tail];
|
||||||
|
|
||||||
|
while (current !== null) {
|
||||||
|
yield current.data;
|
||||||
|
current = current.previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator] () {
|
||||||
|
return this.values();
|
||||||
|
}
|
||||||
|
}
|
9
src/structures/index.js
Normal file
9
src/structures/index.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { CircularDoublyLinkedList } from "./circular-doubly-linked-list";
|
||||||
|
import { DoublyLinkedList } from "./doubly-linked-list";
|
||||||
|
import { LinkedList } from "./linked-list";
|
||||||
|
|
||||||
|
export {
|
||||||
|
CircularDoublyLinkedList,
|
||||||
|
DoublyLinkedList,
|
||||||
|
LinkedList,
|
||||||
|
};
|
103
src/structures/linked-list.js
Normal file
103
src/structures/linked-list.js
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
const head = Symbol("head");
|
||||||
|
|
||||||
|
class LinkedListNode {
|
||||||
|
constructor (data) {
|
||||||
|
this.data = data;
|
||||||
|
this.next = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LinkedList {
|
||||||
|
constructor () {
|
||||||
|
this[head] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
add (data) {
|
||||||
|
const newNode = new LinkedListNode(data);
|
||||||
|
|
||||||
|
if (this[head] === null) {
|
||||||
|
this[head] = newNode;
|
||||||
|
} else {
|
||||||
|
let current = this[head];
|
||||||
|
|
||||||
|
// Go to the end of the list
|
||||||
|
while (current.next !== null) {
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// On the last node, add the new node
|
||||||
|
current.next = newNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get (index) {
|
||||||
|
if ( ! Number(index) < 0) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = this[head];
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while ((current !== null) && (i < index)) {
|
||||||
|
current = current.next;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return current !== null
|
||||||
|
? current.data
|
||||||
|
: undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove (index) {
|
||||||
|
// Invalid index?
|
||||||
|
if ((this[head] === null) || (index < 0)) {
|
||||||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the first node
|
||||||
|
if (index === 0) {
|
||||||
|
const data = this[head].data;
|
||||||
|
|
||||||
|
// Replace the head with the next node
|
||||||
|
this[head] = this[head].next;
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = this[head];
|
||||||
|
let previous = null;
|
||||||
|
let i = 0;
|
||||||
|
|
||||||
|
while ((current !== null) && (i < index)) {
|
||||||
|
// Save the current value
|
||||||
|
previous = current;
|
||||||
|
|
||||||
|
current = current.next;
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the node if found
|
||||||
|
if (current !== null) {
|
||||||
|
// skip over the node to "remove" it
|
||||||
|
previous.next = current.next;
|
||||||
|
|
||||||
|
return current.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new RangeError(`Index ${index} does not exist in the list.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
*values () {
|
||||||
|
let current = this[head];
|
||||||
|
|
||||||
|
while (current !== null) {
|
||||||
|
yield current.data;
|
||||||
|
current = current.next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Symbol.iterator] () {
|
||||||
|
return this.values();
|
||||||
|
}
|
||||||
|
}
|
83
src/usage.js
Normal file
83
src/usage.js
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
import {
|
||||||
|
CircularDoublyLinkedList,
|
||||||
|
DoublyLinkedList,
|
||||||
|
LinkedList,
|
||||||
|
} from "./structures/index.js";
|
||||||
|
|
||||||
|
function useLinkedList () {
|
||||||
|
console.log('-----------------------------------------------------------------------------------------------------');
|
||||||
|
console.log('Linked List');
|
||||||
|
console.log('-----------------------------------------------------------------------------------------------------');
|
||||||
|
const list = new LinkedList();
|
||||||
|
list.add("red");
|
||||||
|
list.add("orange");
|
||||||
|
list.add("yellow");
|
||||||
|
|
||||||
|
// get the second item in the list
|
||||||
|
console.log('Index 1 in list', list.get(1));
|
||||||
|
|
||||||
|
// print out all the items
|
||||||
|
for (const color of list) {
|
||||||
|
console.log(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the second item in the list
|
||||||
|
console.log('Removing list item with index 1', list.remove(1));
|
||||||
|
|
||||||
|
// get the item now with index 1
|
||||||
|
console.log('New list item with index 1', list.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function useDoublyLinkedList () {
|
||||||
|
console.log('-----------------------------------------------------------------------------------------------------');
|
||||||
|
console.log('Doubly-Linked List');
|
||||||
|
console.log('-----------------------------------------------------------------------------------------------------');
|
||||||
|
const list = new DoublyLinkedList();
|
||||||
|
list.add("red");
|
||||||
|
list.add("orange");
|
||||||
|
list.add("yellow");
|
||||||
|
|
||||||
|
console.log('Index 1 in list',list.get(1));
|
||||||
|
|
||||||
|
for (const color of list.reverse()) {
|
||||||
|
console.log(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the second item in the list
|
||||||
|
console.log('Removing list item with index 1', list.remove(1));
|
||||||
|
|
||||||
|
// get the item now with index 1
|
||||||
|
console.log('New list item with index 1', list.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
function useCircularDoublyLinkedList () {
|
||||||
|
console.log('-----------------------------------------------------------------------------------------------------');
|
||||||
|
console.log('Circular Doubly-Linked List');
|
||||||
|
console.log('-----------------------------------------------------------------------------------------------------');
|
||||||
|
|
||||||
|
const list = new CircularDoublyLinkedList();
|
||||||
|
list.add("red");
|
||||||
|
list.add("orange");
|
||||||
|
list.add("yellow");
|
||||||
|
|
||||||
|
// get the second item in the list
|
||||||
|
console.log('Index 1 in list', list.get(1)); // "orange"
|
||||||
|
|
||||||
|
for (const color of list.values()) {
|
||||||
|
console.log(color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the second item in the list
|
||||||
|
console.log('Removing list item with index 1', list.remove(1));
|
||||||
|
|
||||||
|
// get the item now with index 1
|
||||||
|
console.log('New list item with index 1', list.get(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
(() => {
|
||||||
|
useLinkedList();
|
||||||
|
console.log('');
|
||||||
|
useDoublyLinkedList();
|
||||||
|
console.log('');
|
||||||
|
useCircularDoublyLinkedList();
|
||||||
|
})();
|
Loading…
Reference in New Issue
Block a user