mirror of
https://github.moeyy.xyz/https://github.com/trekhleb/javascript-algorithms.git
synced 2024-11-10 11:09:43 +08:00
Merge branch 'master' into linear-search-fix
This commit is contained in:
commit
2781b82940
@ -1,8 +1,10 @@
|
||||
# JavaScript Algorithms and Data Structures
|
||||
|
||||
> 🇺🇦 UKRAINE [IS BEING ATTACKED](https://war.ukraine.ua/) BY RUSSIAN ARMY. CIVILIANS ARE GETTING KILLED. RESIDENTIAL AREAS ARE GETTING BOMBED.
|
||||
> - Help Ukraine via [National Bank of Ukraine](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi)
|
||||
> - Help Ukraine via [SaveLife](https://savelife.in.ua/en/donate-en/) fund
|
||||
> - Help Ukraine via:
|
||||
> - [Serhiy Prytula Charity Foundation](https://prytulafoundation.org/en/)
|
||||
> - [Come Back Alive Charity Foundation](https://savelife.in.ua/en/donate-en/)
|
||||
> - [National Bank of Ukraine](https://bank.gov.ua/en/news/all/natsionalniy-bank-vidkriv-spetsrahunok-dlya-zboru-koshtiv-na-potrebi-armiyi)
|
||||
> - More info on [war.ukraine.ua](https://war.ukraine.ua/) and [MFA of Ukraine](https://twitter.com/MFA_Ukraine)
|
||||
|
||||
<hr/>
|
||||
|
@ -11,7 +11,7 @@ import Comparator from '../../../utils/comparator/Comparator';
|
||||
|
||||
export default function binarySearch(sortedArray, seekElement, comparatorCallback) {
|
||||
// Let's create comparator from the comparatorCallback function.
|
||||
// Comparator object will give us common comparison methods like equal() and lessThen().
|
||||
// Comparator object will give us common comparison methods like equal() and lessThan().
|
||||
const comparator = new Comparator(comparatorCallback);
|
||||
|
||||
// These two indices will contain current array (sub-array) boundaries.
|
||||
|
78
src/data-structures/disjoint-set/DisjointSetAdhoc.js
Normal file
78
src/data-structures/disjoint-set/DisjointSetAdhoc.js
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure
|
||||
* that doesn't have external dependencies and that is easy to copy-paste and
|
||||
* use during the coding interview if allowed by the interviewer (since many
|
||||
* data structures in JS are missing).
|
||||
*
|
||||
* Time Complexity:
|
||||
*
|
||||
* - Constructor: O(N)
|
||||
* - Find: O(α(N))
|
||||
* - Union: O(α(N))
|
||||
* - Connected: O(α(N))
|
||||
*
|
||||
* Where N is the number of vertices in the graph.
|
||||
* α refers to the Inverse Ackermann function.
|
||||
* In practice, we assume it's a constant.
|
||||
* In other words, O(α(N)) is regarded as O(1) on average.
|
||||
*/
|
||||
class DisjointSetAdhoc {
|
||||
/**
|
||||
* Initializes the set of specified size.
|
||||
* @param {number} size
|
||||
*/
|
||||
constructor(size) {
|
||||
// The index of a cell is an id of the node in a set.
|
||||
// The value of a cell is an id (index) of the root node.
|
||||
// By default, the node is a parent of itself.
|
||||
this.roots = new Array(size).fill(0).map((_, i) => i);
|
||||
|
||||
// Using the heights array to record the height of each node.
|
||||
// By default each node has a height of 1 because it has no children.
|
||||
this.heights = new Array(size).fill(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the root of node `a`
|
||||
* @param {number} a
|
||||
* @returns {number}
|
||||
*/
|
||||
find(a) {
|
||||
if (a === this.roots[a]) return a;
|
||||
this.roots[a] = this.find(this.roots[a]);
|
||||
return this.roots[a];
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins the `a` and `b` nodes into same set.
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
* @returns {number}
|
||||
*/
|
||||
union(a, b) {
|
||||
const aRoot = this.find(a);
|
||||
const bRoot = this.find(b);
|
||||
|
||||
if (aRoot === bRoot) return;
|
||||
|
||||
if (this.heights[aRoot] > this.heights[bRoot]) {
|
||||
this.roots[bRoot] = aRoot;
|
||||
} else if (this.heights[aRoot] < this.heights[bRoot]) {
|
||||
this.roots[aRoot] = bRoot;
|
||||
} else {
|
||||
this.roots[bRoot] = aRoot;
|
||||
this.heights[aRoot] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if `a` and `b` belong to the same set.
|
||||
* @param {number} a
|
||||
* @param {number} b
|
||||
*/
|
||||
connected(a, b) {
|
||||
return this.find(a) === this.find(b);
|
||||
}
|
||||
}
|
||||
|
||||
export default DisjointSetAdhoc;
|
@ -19,6 +19,11 @@ _MakeSet_ creates 8 singletons.
|
||||
|
||||
After some operations of _Union_, some sets are grouped together.
|
||||
|
||||
## Implementation
|
||||
|
||||
- [DisjointSet.js](./DisjointSet.js)
|
||||
- [DisjointSetAdhoc.js](./DisjointSetAdhoc.js) - The minimalistic (ad hoc) version of a DisjointSet (or a UnionFind) data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing).
|
||||
|
||||
## References
|
||||
|
||||
- [Wikipedia](https://en.wikipedia.org/wiki/Disjoint-set_data_structure)
|
||||
|
@ -0,0 +1,50 @@
|
||||
import DisjointSetAdhoc from '../DisjointSetAdhoc';
|
||||
|
||||
describe('DisjointSetAdhoc', () => {
|
||||
it('should create unions and find connected elements', () => {
|
||||
const set = new DisjointSetAdhoc(10);
|
||||
|
||||
// 1-2-5-6-7 3-8-9 4
|
||||
set.union(1, 2);
|
||||
set.union(2, 5);
|
||||
set.union(5, 6);
|
||||
set.union(6, 7);
|
||||
|
||||
set.union(3, 8);
|
||||
set.union(8, 9);
|
||||
|
||||
expect(set.connected(1, 5)).toBe(true);
|
||||
expect(set.connected(5, 7)).toBe(true);
|
||||
expect(set.connected(3, 8)).toBe(true);
|
||||
|
||||
expect(set.connected(4, 9)).toBe(false);
|
||||
expect(set.connected(4, 7)).toBe(false);
|
||||
|
||||
// 1-2-5-6-7 3-8-9-4
|
||||
set.union(9, 4);
|
||||
|
||||
expect(set.connected(4, 9)).toBe(true);
|
||||
expect(set.connected(4, 3)).toBe(true);
|
||||
expect(set.connected(8, 4)).toBe(true);
|
||||
|
||||
expect(set.connected(8, 7)).toBe(false);
|
||||
expect(set.connected(2, 3)).toBe(false);
|
||||
});
|
||||
|
||||
it('should keep the height of the tree small', () => {
|
||||
const set = new DisjointSetAdhoc(10);
|
||||
|
||||
// 1-2-6-7-9 1 3 4 5
|
||||
set.union(7, 6);
|
||||
set.union(1, 2);
|
||||
set.union(2, 6);
|
||||
set.union(1, 7);
|
||||
set.union(9, 1);
|
||||
|
||||
expect(set.connected(1, 7)).toBe(true);
|
||||
expect(set.connected(6, 9)).toBe(true);
|
||||
expect(set.connected(4, 9)).toBe(false);
|
||||
|
||||
expect(Math.max(...set.heights)).toBe(3);
|
||||
});
|
||||
});
|
115
src/data-structures/heap/MaxHeapAdhoc.js
Normal file
115
src/data-structures/heap/MaxHeapAdhoc.js
Normal file
@ -0,0 +1,115 @@
|
||||
/**
|
||||
* The minimalistic (ad hoc) version of a MaxHeap data structure that doesn't have
|
||||
* external dependencies and that is easy to copy-paste and use during the
|
||||
* coding interview if allowed by the interviewer (since many data
|
||||
* structures in JS are missing).
|
||||
*/
|
||||
class MaxHeapAdhoc {
|
||||
constructor(heap = []) {
|
||||
this.heap = [];
|
||||
heap.forEach(this.add);
|
||||
}
|
||||
|
||||
add(num) {
|
||||
this.heap.push(num);
|
||||
this.heapifyUp();
|
||||
}
|
||||
|
||||
peek() {
|
||||
return this.heap[0];
|
||||
}
|
||||
|
||||
poll() {
|
||||
if (this.heap.length === 0) return undefined;
|
||||
const top = this.heap[0];
|
||||
this.heap[0] = this.heap[this.heap.length - 1];
|
||||
this.heap.pop();
|
||||
this.heapifyDown();
|
||||
return top;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.heap.length === 0;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.heap.join(',');
|
||||
}
|
||||
|
||||
heapifyUp() {
|
||||
let nodeIndex = this.heap.length - 1;
|
||||
while (nodeIndex > 0) {
|
||||
const parentIndex = this.getParentIndex(nodeIndex);
|
||||
if (this.heap[parentIndex] >= this.heap[nodeIndex]) break;
|
||||
this.swap(parentIndex, nodeIndex);
|
||||
nodeIndex = parentIndex;
|
||||
}
|
||||
}
|
||||
|
||||
heapifyDown() {
|
||||
let nodeIndex = 0;
|
||||
|
||||
while (
|
||||
(
|
||||
this.hasLeftChild(nodeIndex) && this.heap[nodeIndex] < this.leftChild(nodeIndex)
|
||||
)
|
||||
|| (
|
||||
this.hasRightChild(nodeIndex) && this.heap[nodeIndex] < this.rightChild(nodeIndex)
|
||||
)
|
||||
) {
|
||||
const leftIndex = this.getLeftChildIndex(nodeIndex);
|
||||
const rightIndex = this.getRightChildIndex(nodeIndex);
|
||||
const left = this.leftChild(nodeIndex);
|
||||
const right = this.rightChild(nodeIndex);
|
||||
|
||||
if (this.hasLeftChild(nodeIndex) && this.hasRightChild(nodeIndex)) {
|
||||
if (left >= right) {
|
||||
this.swap(leftIndex, nodeIndex);
|
||||
nodeIndex = leftIndex;
|
||||
} else {
|
||||
this.swap(rightIndex, nodeIndex);
|
||||
nodeIndex = rightIndex;
|
||||
}
|
||||
} else if (this.hasLeftChild(nodeIndex)) {
|
||||
this.swap(leftIndex, nodeIndex);
|
||||
nodeIndex = leftIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getLeftChildIndex(parentIndex) {
|
||||
return (2 * parentIndex) + 1;
|
||||
}
|
||||
|
||||
getRightChildIndex(parentIndex) {
|
||||
return (2 * parentIndex) + 2;
|
||||
}
|
||||
|
||||
getParentIndex(childIndex) {
|
||||
return Math.floor((childIndex - 1) / 2);
|
||||
}
|
||||
|
||||
hasLeftChild(parentIndex) {
|
||||
return this.getLeftChildIndex(parentIndex) < this.heap.length;
|
||||
}
|
||||
|
||||
hasRightChild(parentIndex) {
|
||||
return this.getRightChildIndex(parentIndex) < this.heap.length;
|
||||
}
|
||||
|
||||
leftChild(parentIndex) {
|
||||
return this.heap[this.getLeftChildIndex(parentIndex)];
|
||||
}
|
||||
|
||||
rightChild(parentIndex) {
|
||||
return this.heap[this.getRightChildIndex(parentIndex)];
|
||||
}
|
||||
|
||||
swap(indexOne, indexTwo) {
|
||||
const tmp = this.heap[indexTwo];
|
||||
this.heap[indexTwo] = this.heap[indexOne];
|
||||
this.heap[indexOne] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
export default MaxHeapAdhoc;
|
117
src/data-structures/heap/MinHeapAdhoc.js
Normal file
117
src/data-structures/heap/MinHeapAdhoc.js
Normal file
@ -0,0 +1,117 @@
|
||||
/**
|
||||
* The minimalistic (ad hoc) version of a MinHeap data structure that doesn't have
|
||||
* external dependencies and that is easy to copy-paste and use during the
|
||||
* coding interview if allowed by the interviewer (since many data
|
||||
* structures in JS are missing).
|
||||
*/
|
||||
class MinHeapAdhoc {
|
||||
constructor(heap = []) {
|
||||
this.heap = [];
|
||||
heap.forEach(this.add);
|
||||
}
|
||||
|
||||
add(num) {
|
||||
this.heap.push(num);
|
||||
this.heapifyUp();
|
||||
}
|
||||
|
||||
peek() {
|
||||
return this.heap[0];
|
||||
}
|
||||
|
||||
poll() {
|
||||
if (this.heap.length === 0) return undefined;
|
||||
const top = this.heap[0];
|
||||
this.heap[0] = this.heap[this.heap.length - 1];
|
||||
this.heap.pop();
|
||||
this.heapifyDown();
|
||||
return top;
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return this.heap.length === 0;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return this.heap.join(',');
|
||||
}
|
||||
|
||||
heapifyUp() {
|
||||
let nodeIndex = this.heap.length - 1;
|
||||
while (nodeIndex > 0) {
|
||||
const parentIndex = this.getParentIndex(nodeIndex);
|
||||
if (this.heap[parentIndex] <= this.heap[nodeIndex]) break;
|
||||
this.swap(parentIndex, nodeIndex);
|
||||
nodeIndex = parentIndex;
|
||||
}
|
||||
}
|
||||
|
||||
heapifyDown() {
|
||||
let nodeIndex = 0;
|
||||
|
||||
while (
|
||||
(
|
||||
this.hasLeftChild(nodeIndex)
|
||||
&& this.heap[nodeIndex] > this.leftChild(nodeIndex)
|
||||
)
|
||||
|| (
|
||||
this.hasRightChild(nodeIndex)
|
||||
&& this.heap[nodeIndex] > this.rightChild(nodeIndex)
|
||||
)
|
||||
) {
|
||||
const leftIndex = this.getLeftChildIndex(nodeIndex);
|
||||
const rightIndex = this.getRightChildIndex(nodeIndex);
|
||||
const left = this.leftChild(nodeIndex);
|
||||
const right = this.rightChild(nodeIndex);
|
||||
|
||||
if (this.hasLeftChild(nodeIndex) && this.hasRightChild(nodeIndex)) {
|
||||
if (left <= right) {
|
||||
this.swap(leftIndex, nodeIndex);
|
||||
nodeIndex = leftIndex;
|
||||
} else {
|
||||
this.swap(rightIndex, nodeIndex);
|
||||
nodeIndex = rightIndex;
|
||||
}
|
||||
} else if (this.hasLeftChild(nodeIndex)) {
|
||||
this.swap(leftIndex, nodeIndex);
|
||||
nodeIndex = leftIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getLeftChildIndex(parentIndex) {
|
||||
return 2 * parentIndex + 1;
|
||||
}
|
||||
|
||||
getRightChildIndex(parentIndex) {
|
||||
return 2 * parentIndex + 2;
|
||||
}
|
||||
|
||||
getParentIndex(childIndex) {
|
||||
return Math.floor((childIndex - 1) / 2);
|
||||
}
|
||||
|
||||
hasLeftChild(parentIndex) {
|
||||
return this.getLeftChildIndex(parentIndex) < this.heap.length;
|
||||
}
|
||||
|
||||
hasRightChild(parentIndex) {
|
||||
return this.getRightChildIndex(parentIndex) < this.heap.length;
|
||||
}
|
||||
|
||||
leftChild(parentIndex) {
|
||||
return this.heap[this.getLeftChildIndex(parentIndex)];
|
||||
}
|
||||
|
||||
rightChild(parentIndex) {
|
||||
return this.heap[this.getRightChildIndex(parentIndex)];
|
||||
}
|
||||
|
||||
swap(indexOne, indexTwo) {
|
||||
const tmp = this.heap[indexTwo];
|
||||
this.heap[indexTwo] = this.heap[indexOne];
|
||||
this.heap[indexOne] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
export default MinHeapAdhoc;
|
@ -58,6 +58,11 @@ Where:
|
||||
|
||||
> In this repository, the [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js) are examples of the **Binary** heap.
|
||||
|
||||
## Implementation
|
||||
|
||||
- [MaxHeap.js](./MaxHeap.js) and [MinHeap.js](./MinHeap.js)
|
||||
- [MaxHeapAdhoc.js](./MaxHeapAdhoc.js) and [MinHeapAdhoc.js](./MinHeapAdhoc.js) - The minimalistic (ad hoc) version of a MinHeap/MaxHeap data structure that doesn't have external dependencies and that is easy to copy-paste and use during the coding interview if allowed by the interviewer (since many data structures in JS are missing).
|
||||
|
||||
## References
|
||||
|
||||
- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
|
||||
|
91
src/data-structures/heap/__test__/MaxHeapAdhoc.test.js
Normal file
91
src/data-structures/heap/__test__/MaxHeapAdhoc.test.js
Normal file
@ -0,0 +1,91 @@
|
||||
import MaxHeap from '../MaxHeapAdhoc';
|
||||
|
||||
describe('MaxHeapAdhoc', () => {
|
||||
it('should create an empty max heap', () => {
|
||||
const maxHeap = new MaxHeap();
|
||||
|
||||
expect(maxHeap).toBeDefined();
|
||||
expect(maxHeap.peek()).toBe(undefined);
|
||||
expect(maxHeap.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should add items to the heap and heapify it up', () => {
|
||||
const maxHeap = new MaxHeap();
|
||||
|
||||
maxHeap.add(5);
|
||||
expect(maxHeap.isEmpty()).toBe(false);
|
||||
expect(maxHeap.peek()).toBe(5);
|
||||
expect(maxHeap.toString()).toBe('5');
|
||||
|
||||
maxHeap.add(3);
|
||||
expect(maxHeap.peek()).toBe(5);
|
||||
expect(maxHeap.toString()).toBe('5,3');
|
||||
|
||||
maxHeap.add(10);
|
||||
expect(maxHeap.peek()).toBe(10);
|
||||
expect(maxHeap.toString()).toBe('10,3,5');
|
||||
|
||||
maxHeap.add(1);
|
||||
expect(maxHeap.peek()).toBe(10);
|
||||
expect(maxHeap.toString()).toBe('10,3,5,1');
|
||||
|
||||
maxHeap.add(1);
|
||||
expect(maxHeap.peek()).toBe(10);
|
||||
expect(maxHeap.toString()).toBe('10,3,5,1,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(10);
|
||||
expect(maxHeap.toString()).toBe('5,3,1,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(5);
|
||||
expect(maxHeap.toString()).toBe('3,1,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(3);
|
||||
expect(maxHeap.toString()).toBe('1,1');
|
||||
});
|
||||
|
||||
it('should poll items from the heap and heapify it down', () => {
|
||||
const maxHeap = new MaxHeap();
|
||||
|
||||
maxHeap.add(5);
|
||||
maxHeap.add(3);
|
||||
maxHeap.add(10);
|
||||
maxHeap.add(11);
|
||||
maxHeap.add(1);
|
||||
|
||||
expect(maxHeap.toString()).toBe('11,10,5,3,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(11);
|
||||
expect(maxHeap.toString()).toBe('10,3,5,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(10);
|
||||
expect(maxHeap.toString()).toBe('5,3,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(5);
|
||||
expect(maxHeap.toString()).toBe('3,1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(3);
|
||||
expect(maxHeap.toString()).toBe('1');
|
||||
|
||||
expect(maxHeap.poll()).toBe(1);
|
||||
expect(maxHeap.toString()).toBe('');
|
||||
|
||||
expect(maxHeap.poll()).toBe(undefined);
|
||||
expect(maxHeap.toString()).toBe('');
|
||||
});
|
||||
|
||||
it('should heapify down through the right branch as well', () => {
|
||||
const maxHeap = new MaxHeap();
|
||||
|
||||
maxHeap.add(3);
|
||||
maxHeap.add(12);
|
||||
maxHeap.add(10);
|
||||
|
||||
expect(maxHeap.toString()).toBe('12,3,10');
|
||||
|
||||
maxHeap.add(11);
|
||||
expect(maxHeap.toString()).toBe('12,11,10,3');
|
||||
|
||||
expect(maxHeap.poll()).toBe(12);
|
||||
expect(maxHeap.toString()).toBe('11,3,10');
|
||||
});
|
||||
});
|
91
src/data-structures/heap/__test__/MinHeapAdhoc.test.js
Normal file
91
src/data-structures/heap/__test__/MinHeapAdhoc.test.js
Normal file
@ -0,0 +1,91 @@
|
||||
import MinHeapAdhoc from '../MinHeapAdhoc';
|
||||
|
||||
describe('MinHeapAdhoc', () => {
|
||||
it('should create an empty min heap', () => {
|
||||
const minHeap = new MinHeapAdhoc();
|
||||
|
||||
expect(minHeap).toBeDefined();
|
||||
expect(minHeap.peek()).toBe(undefined);
|
||||
expect(minHeap.isEmpty()).toBe(true);
|
||||
});
|
||||
|
||||
it('should add items to the heap and heapify it up', () => {
|
||||
const minHeap = new MinHeapAdhoc();
|
||||
|
||||
minHeap.add(5);
|
||||
expect(minHeap.isEmpty()).toBe(false);
|
||||
expect(minHeap.peek()).toBe(5);
|
||||
expect(minHeap.toString()).toBe('5');
|
||||
|
||||
minHeap.add(3);
|
||||
expect(minHeap.peek()).toBe(3);
|
||||
expect(minHeap.toString()).toBe('3,5');
|
||||
|
||||
minHeap.add(10);
|
||||
expect(minHeap.peek()).toBe(3);
|
||||
expect(minHeap.toString()).toBe('3,5,10');
|
||||
|
||||
minHeap.add(1);
|
||||
expect(minHeap.peek()).toBe(1);
|
||||
expect(minHeap.toString()).toBe('1,3,10,5');
|
||||
|
||||
minHeap.add(1);
|
||||
expect(minHeap.peek()).toBe(1);
|
||||
expect(minHeap.toString()).toBe('1,1,10,5,3');
|
||||
|
||||
expect(minHeap.poll()).toBe(1);
|
||||
expect(minHeap.toString()).toBe('1,3,10,5');
|
||||
|
||||
expect(minHeap.poll()).toBe(1);
|
||||
expect(minHeap.toString()).toBe('3,5,10');
|
||||
|
||||
expect(minHeap.poll()).toBe(3);
|
||||
expect(minHeap.toString()).toBe('5,10');
|
||||
});
|
||||
|
||||
it('should poll items from the heap and heapify it down', () => {
|
||||
const minHeap = new MinHeapAdhoc();
|
||||
|
||||
minHeap.add(5);
|
||||
minHeap.add(3);
|
||||
minHeap.add(10);
|
||||
minHeap.add(11);
|
||||
minHeap.add(1);
|
||||
|
||||
expect(minHeap.toString()).toBe('1,3,10,11,5');
|
||||
|
||||
expect(minHeap.poll()).toBe(1);
|
||||
expect(minHeap.toString()).toBe('3,5,10,11');
|
||||
|
||||
expect(minHeap.poll()).toBe(3);
|
||||
expect(minHeap.toString()).toBe('5,11,10');
|
||||
|
||||
expect(minHeap.poll()).toBe(5);
|
||||
expect(minHeap.toString()).toBe('10,11');
|
||||
|
||||
expect(minHeap.poll()).toBe(10);
|
||||
expect(minHeap.toString()).toBe('11');
|
||||
|
||||
expect(minHeap.poll()).toBe(11);
|
||||
expect(minHeap.toString()).toBe('');
|
||||
|
||||
expect(minHeap.poll()).toBe(undefined);
|
||||
expect(minHeap.toString()).toBe('');
|
||||
});
|
||||
|
||||
it('should heapify down through the right branch as well', () => {
|
||||
const minHeap = new MinHeapAdhoc();
|
||||
|
||||
minHeap.add(3);
|
||||
minHeap.add(12);
|
||||
minHeap.add(10);
|
||||
|
||||
expect(minHeap.toString()).toBe('3,12,10');
|
||||
|
||||
minHeap.add(11);
|
||||
expect(minHeap.toString()).toBe('3,11,10,12');
|
||||
|
||||
expect(minHeap.poll()).toBe(3);
|
||||
expect(minHeap.toString()).toBe('10,11,12');
|
||||
});
|
||||
});
|
155
src/data-structures/linked-list/README.vi-VN.md
Normal file
155
src/data-structures/linked-list/README.vi-VN.md
Normal file
@ -0,0 +1,155 @@
|
||||
# Danh sách liên kết (Linked List)
|
||||
|
||||
_Đọc bằng ngôn ngữ khác:_
|
||||
[_简体中文_](README.zh-CN.md),
|
||||
[_Русский_](README.ru-RU.md),
|
||||
[_日本語_](README.ja-JP.md),
|
||||
[_Português_](README.pt-BR.md),
|
||||
[_한국어_](README.ko-KR.md),
|
||||
[_Español_](README.es-ES.md),
|
||||
[_Türkçe_](README.tr-TR.md),
|
||||
[_Українська_](README.uk-UA.md)
|
||||
|
||||
|
||||
Trong khoa học máy tính, một danh sách liên kết là một bộ sưu tập tuyến tính
|
||||
các phần tử dữ liệu, trong đó thứ tự tuyến tính không được xác định bởi
|
||||
vị trí vật lý của chúng trong bộ nhớ. Thay vào đó, mỗi
|
||||
phần tử trỏ đến phần tử tiếp theo. Đây là một cấu trúc dữ liệu
|
||||
bao gồm một nhóm các nút cùng đại diện cho
|
||||
một chuỗi. Dưới dạng đơn giản nhất, mỗi nút
|
||||
bao gồm dữ liệu và một tham chiếu (nói cách khác,
|
||||
một liên kết) đến nút tiếp theo trong chuỗi. Cấu trúc này
|
||||
cho phép việc chèn hoặc loại bỏ các phần tử một cách hiệu quả
|
||||
từ bất kỳ vị trí nào trong chuỗi trong quá trình lặp.
|
||||
Các biến thể phức tạp hơn thêm các liên kết bổ sung, cho phép
|
||||
việc chèn hoặc loại bỏ một cách hiệu quả từ bất kỳ phần tử nào
|
||||
trong chuỗi dựa trên tham chiếu. Một nhược điểm của danh sách liên kết
|
||||
là thời gian truy cập tuyến tính (và khó điều chỉnh). Truy cập nhanh hơn,
|
||||
như truy cập ngẫu nhiên, là không khả thi. Mảng
|
||||
có độ tương phản cache tốt hơn so với danh sách liên kết.
|
||||
|
||||
![Linked List](./images/linked-list.jpeg)
|
||||
*Được làm từ [okso.app](https://okso.app)*
|
||||
|
||||
## Mã giải (Pseudocode) cho Các Hoạt Động Cơ Bản
|
||||
*head = đầu,
|
||||
*tail = đuôi,
|
||||
*next = kế tiếp,
|
||||
*node = nút,
|
||||
*value = giá trị
|
||||
|
||||
### Chèn (Insert)
|
||||
|
||||
```
|
||||
ThêmGiáTrị(giá trị) (Add(value))
|
||||
Trước(Pre): giá trị là giá trị muốn thêm vào danh sách
|
||||
Sau(Post): giá trị đã được đặt ở cuối danh sách
|
||||
|
||||
n ← node(value)
|
||||
if head = ø
|
||||
head ← n
|
||||
tail ← n
|
||||
else
|
||||
tail.next ← n
|
||||
tail ← n
|
||||
end if
|
||||
end ThêmGiáTrị(Add)
|
||||
```
|
||||
|
||||
```
|
||||
ChènVàoĐầu(giá trị)
|
||||
Trước(Pre): giá trị là giá trị muốn thêm vào danh sách
|
||||
Sau(Post): giá trị đã được đặt ở đầu danh sách
|
||||
|
||||
n ← node(value)
|
||||
n.next ← head
|
||||
head ← n
|
||||
if tail = ø
|
||||
tail ← n
|
||||
end
|
||||
end ChènVàoĐầu
|
||||
```
|
||||
|
||||
### Tìm Kiếm (Search)
|
||||
```
|
||||
Chứa(đầu, giá trị)
|
||||
Trước: đầu là nút đầu trong danh sách
|
||||
giá trị là giá trị cần tìm kiếm
|
||||
Sau: mục đó có thể ở trong danh sách liên kết, true; nếu không, là false
|
||||
n ← head
|
||||
while n != ø and n.value != value
|
||||
n ← n.next
|
||||
end while
|
||||
if n = ø
|
||||
return false
|
||||
end if
|
||||
return true
|
||||
end Contains
|
||||
```
|
||||
|
||||
### Xóa (Delete)
|
||||
```
|
||||
Xóa(đầu, giá trị)
|
||||
Trước: đầu là nút đầu trong danh sách
|
||||
giá trị là giá trị cần xóa khỏi danh sách
|
||||
Sau: giá trị đã được xóa khỏi danh sách, true; nếu không, là false
|
||||
if head = ø
|
||||
return false
|
||||
end if
|
||||
n ← head
|
||||
if n.value = value
|
||||
if head = tail
|
||||
head ← ø
|
||||
tail ← ø
|
||||
else
|
||||
head ← head.next
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
while n.next != ø and n.next.value != value
|
||||
n ← n.next
|
||||
end while
|
||||
if n.next != ø
|
||||
if n.next = tail
|
||||
tail ← n
|
||||
tail.next = null
|
||||
else
|
||||
n.next ← n.next.next
|
||||
end if
|
||||
return true
|
||||
end if
|
||||
return false
|
||||
end Remove
|
||||
```
|
||||
|
||||
### Duyệt(raverse)
|
||||
Duyệt(đầu)
|
||||
Trước: đầu là nút đầu trong danh sách
|
||||
Sau: các mục trong danh sách đã được duyệt
|
||||
n ← head
|
||||
while n != ø
|
||||
yield n.value
|
||||
n ← n.next
|
||||
end while
|
||||
end Traverse
|
||||
|
||||
### Duyệt Ngược (Traverse in Reverse)
|
||||
DuyệtNgược(đầu, đuôi)
|
||||
Trước: đầu và đuôi thuộc cùng một danh sách
|
||||
Sau: các mục trong danh sách đã được duyệt theo thứ tự ngược lại
|
||||
|
||||
## Độ Phức Tạp
|
||||
|
||||
### Độ Phức Tạp Thời Gian (Time Complexity)
|
||||
|
||||
| Access | Search | Insertion | Deletion |
|
||||
| :-------: | :-------: | :-------: | :-------: |
|
||||
| O(n) | O(n) | O(1) | O(n) |
|
||||
|
||||
## Độ Phức Tạp Không Gian (Space Complexity)
|
||||
O(n)
|
||||
|
||||
## Tham Khảo
|
||||
|
||||
- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
|
||||
- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
|
22
src/data-structures/queue/README.vi-VN.md
Normal file
22
src/data-structures/queue/README.vi-VN.md
Normal file
@ -0,0 +1,22 @@
|
||||
# Hàng đợi (Queue)
|
||||
|
||||
_Đọc bằng ngôn ngữ khác:_
|
||||
[_简体中文_](README.zh-CN.md),
|
||||
[_Русский_](README.ru-RU.md),
|
||||
[_日本語_](README.ja-JP.md),
|
||||
[_Português_](README.pt-BR.md),
|
||||
[_한국어_](README.ko-KR.md),
|
||||
[_Українська_](README.uk-UA.md)
|
||||
|
||||
Trong khoa học máy tính, một **hàng đợi** là một loại cụ thể của kiểu dữ liệu trừu tượng hoặc bộ sưu tập trong đó các phần tử trong bộ sưu tập được giữ theo thứ tự và nguyên tắc (hoặc chỉ) các hoạt động trên bộ sưu tập là thêm các phần tử vào vị trí cuối cùng, được gọi là đưa vào hàng đợi (enqueue), và loại bỏ các phần tử từ vị trí đầu tiên, được gọi là đưa ra khỏi hàng đợi (dequeue). Điều này khiến cho hàng đợi trở thành một cấu trúc dữ liệu First-In-First-Out (FIFO). Trong cấu trúc dữ liệu FIFO, phần tử đầu tiên được thêm vào hàng đợi sẽ là phần tử đầu tiên được loại bỏ. Điều này tương đương với yêu cầu rằng sau khi một phần tử mới được thêm vào, tất cả các phần tử đã được thêm vào trước đó phải được loại bỏ trước khi có thể loại bỏ phần tử mới. Thường thì cũng có thêm một hoạt động nhìn hay lấy phần đầu, trả về giá trị của phần tử đầu tiên mà không loại bỏ nó. Hàng đợi là một ví dụ về cấu trúc dữ liệu tuyến tính, hoặc trừu tượng hơn là một bộ sưu tập tuần tự.
|
||||
|
||||
Hàng đợi FIFO (First-In-First-Out) có thể được biểu diễn như sau:
|
||||
|
||||
![Queue](./images/queue.jpeg)
|
||||
|
||||
*Made with [okso.app](https://okso.app)*
|
||||
|
||||
## Tham Khảo
|
||||
|
||||
- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
|
||||
- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
|
27
src/data-structures/stack/README.vi-VN.md
Normal file
27
src/data-structures/stack/README.vi-VN.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Ngăn xếp (stack)
|
||||
|
||||
_Đọc bằng ngôn ngữ khác:_
|
||||
[_简体中文_](README.zh-CN.md),
|
||||
[_Русский_](README.ru-RU.md),
|
||||
[_日本語_](README.ja-JP.md),
|
||||
[_Português_](README.pt-BR.md),
|
||||
[_한국어_](README.ko-KR.md),
|
||||
[_Español_](README.es-ES.md),
|
||||
[_Українська_](README.uk-UA.md)
|
||||
|
||||
Trong khoa học máy tính, một ngăn xếp (stack) là một kiểu dữ liệu trừu tượng phục vụ như một bộ sưu tập các phần tử, với hai hoạt động chính:
|
||||
|
||||
đẩy (push), thêm một phần tử vào bộ sưu tập, và
|
||||
lấy (pop), loại bỏ phần tử được thêm gần nhất mà chưa được loại bỏ.
|
||||
Thứ tự mà các phần tử được lấy ra khỏi ngăn xếp dẫn đến tên gọi thay thế của nó, là LIFO (last in, first out). Ngoài ra, một hoạt động nhìn có thể cung cấp quyền truy cập vào phần trên mà không làm thay đổi ngăn xếp. Tên "ngăn xếp" cho loại cấu trúc này đến từ sự tương tự với một bộ sưu tập các vật phẩm vật lý được xếp chồng lên nhau, điều này làm cho việc lấy một vật phẩm ra khỏi đỉnh của ngăn xếp dễ dàng, trong khi để đến được một vật phẩm sâu hơn trong ngăn xếp có thể đòi hỏi việc lấy ra nhiều vật phẩm khác trước đó.
|
||||
|
||||
Biểu diễn đơn giản về thời gian chạy của một ngăn xếp với các hoạt động đẩy và lấy.
|
||||
|
||||
![Stack](./images/stack.jpeg)
|
||||
|
||||
*Made with [okso.app](https://okso.app)*
|
||||
|
||||
## Tham Khảo
|
||||
|
||||
- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
|
||||
- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
|
@ -23,7 +23,7 @@ together with a list of references to nodes (the "children"),
|
||||
with the constraints that no reference is duplicated, and none
|
||||
points to the root.
|
||||
|
||||
A simple unordered tree; in this diagram, the node labeled 7 has
|
||||
A simple unordered tree; in this diagram, the node labeled 3 has
|
||||
two children, labeled 2 and 6, and one parent, labeled 2. The
|
||||
root node, at the top, has no parent.
|
||||
|
||||
|
19
src/data-structures/trie/README.ko-KO.md
Normal file
19
src/data-structures/trie/README.ko-KO.md
Normal file
@ -0,0 +1,19 @@
|
||||
# Trie
|
||||
|
||||
_Read this in other languages:_
|
||||
[_简体中文_](README.zh-CN.md),
|
||||
[_Русский_](README.ru-RU.md),
|
||||
[_Português_](README.pt-BR.md),
|
||||
[_Українська_](README.uk-UA.md),
|
||||
[_한국어_](README.ko-KO.md)
|
||||
|
||||
컴퓨터 과학에서 **트라이**는 디지털 트리라고도 불리며 때로는 기수 트리 또는 접두사 트리(접두사로 검색할 수 있기 때문에)라고도 불리며 일종의 검색 트리입니다. 키가 보통 문자열인 동적 집합 또는 연관 배열을 저장하는 데 사용되는 순서가 지정된 트리 데이터 구조입니다. 이진 검색 트리와 달리 트리의 어떤 노드도 해당 노드와 연결된 키를 저장하지 않으며 대신 트리의 위치가 해당 노드와 연결된 키를 정의합니다. 노드의 모든 하위 항목은 해당 노드와 연결된 문자열의 공통 접두사를 가지며 루트는 빈 문자열과 연결됩니다. 값은 모든 노드와 반드시 연결되지는 않습니다. 오히려 값은 나뭇잎과 관심 있는 키에 해당하는 일부 내부 노드에만 연결되는 경향이 있습니다. 접두사 트리의 공간에 최적화된 표현은 콤팩트 접두사 트리를 참조하십시오.
|
||||
|
||||
![Trie](./images/trie.jpg)
|
||||
|
||||
_Made with [okso.app](https://okso.app)_
|
||||
|
||||
## 참조
|
||||
|
||||
- [Wikipedia](<https://ko.wikipedia.org/wiki/%ED%8A%B8%EB%9D%BC%EC%9D%B4_(%EC%BB%B4%ED%93%A8%ED%8C%85)>)
|
||||
- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)
|
@ -4,7 +4,8 @@ _Read this in other languages:_
|
||||
[_简体中文_](README.zh-CN.md),
|
||||
[_Русский_](README.ru-RU.md),
|
||||
[_Português_](README.pt-BR.md),
|
||||
[_Українська_](README.uk-UA.md)
|
||||
[_Українська_](README.uk-UA.md),
|
||||
[_한국어_](README.ko-KO.md)
|
||||
|
||||
In computer science, a **trie**, also called digital tree and sometimes
|
||||
radix tree or prefix tree (as they can be searched by prefixes),
|
||||
|
Loading…
Reference in New Issue
Block a user