Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 53ea385

Browse files
authoredSep 4, 2018
Merge branch 'master' into patch-1
2 parents 04b5a93 + 518dc57 commit 53ea385

File tree

25 files changed

+513
-126
lines changed

25 files changed

+513
-126
lines changed
 

‎.travis.yml

+4-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ dist: trusty
33
language: node_js
44
node_js:
55
- node
6+
install:
7+
- npm install -g codecov
8+
- npm install
69
script:
710
- npm run ci
8-
- npm run codecov
11+
- codecov
912
notifications:
1013
email: false

‎README.zh-CN.md

+9-9
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,21 @@ _Read this in other languages:_
2222

2323
`B` - 初学者, `A` - 进阶
2424

25-
* `B` [链表](src/data-structures/linked-list)
26-
* `B` [双向链表](src/data-structures/doubly-linked-list)
27-
* `B` [队列](src/data-structures/queue)
28-
* `B` [](src/data-structures/stack)
29-
* `B` [哈希表](src/data-structures/hash-table)
30-
* `B` [](src/data-structures/heap)
31-
* `B` [优先队列](src/data-structures/priority-queue)
25+
* `B` [链表](src/data-structures/linked-list/README.zh-CN.md)
26+
* `B` [双向链表](src/data-structures/doubly-linked-list/README.zh-CN.md)
27+
* `B` [队列](src/data-structures/queue/README.zh-CN.md)
28+
* `B` [](src/data-structures/stack/README.zh-CN.md)
29+
* `B` [哈希表](src/data-structures/hash-table/README.zh-CN.md)
30+
* `B` [](src/data-structures/heap/README.zh-CN.md)
31+
* `B` [优先队列](src/data-structures/priority-queue/README.zh-CN.md)
3232
* `A` [字典树](src/data-structures/trie)
33-
* `A` [](src/data-structures/tree)
33+
* `A` [](src/data-structures/tree/README.zh-CN.md)
3434
* `A` [二叉查找树](src/data-structures/tree/binary-search-tree)
3535
* `A` [AVL 树](src/data-structures/tree/avl-tree)
3636
* `A` [红黑树](src/data-structures/tree/red-black-tree)
3737
* `A` [线段树](src/data-structures/tree/segment-tree) - 使用 最小/最大/总和 范围查询示例
3838
* `A` [树状数组](src/data-structures/tree/fenwick-tree) (二叉索引树)
39-
* `A` [](src/data-structures/graph) (有向图与无向图)
39+
* `A` [](src/data-structures/graph/README.zh-CN.md) (有向图与无向图)
4040
* `A` [并查集](src/data-structures/disjoint-set)
4141
* `A` [布隆过滤器](src/data-structures/bloom-filter)
4242

‎package-lock.json

-23
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,7 @@
66
"scripts": {
77
"lint": "eslint ./src/*",
88
"test": "jest",
9-
"ci": "npm run lint && npm run test -- --coverage",
10-
"codecov": "codecov"
9+
"ci": "npm run lint && npm run test -- --coverage"
1110
},
1211
"pre-commit": [
1312
"lint",
@@ -27,7 +26,9 @@
2726
"javascript-algorithms",
2827
"sorting-algorithms",
2928
"graph",
30-
"tree"
29+
"tree",
30+
"interview",
31+
"interview-preparation"
3132
],
3233
"author": "Oleksii Trekhleb (https://www.linkedin.com/in/trekhleb/)",
3334
"license": "MIT",
@@ -39,7 +40,6 @@
3940
"@types/jest": "^23.1.4",
4041
"babel-cli": "^6.26.0",
4142
"babel-preset-env": "^1.7.0",
42-
"codecov": "^3.0.2",
4343
"eslint": "^4.19.1",
4444
"eslint-config-airbnb": "^17.0.0",
4545
"eslint-plugin-import": "^2.13.0",

‎src/algorithms/sets/maximum-subarray/__test__/bfMaximumSubarray.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import bfMaximumSubarray from '../bfMaximumSubarray';
33
describe('bfMaximumSubarray', () => {
44
it('should find maximum subarray using brute force algorithm', () => {
55
expect(bfMaximumSubarray([])).toEqual([]);
6+
expect(bfMaximumSubarray([0, 0])).toEqual([0]);
7+
expect(bfMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]);
8+
expect(bfMaximumSubarray([0, 0, 1, 2])).toEqual([0, 0, 1, 2]);
9+
expect(bfMaximumSubarray([0, 0, -1, 2])).toEqual([2]);
610
expect(bfMaximumSubarray([-1, -2, -3, -4, -5])).toEqual([-1]);
711
expect(bfMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual([1, 2, 3, 2, 3, 4, 5]);
812
expect(bfMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual([4, -1, 2, 1]);

‎src/algorithms/sets/maximum-subarray/__test__/dpMaximumSubarray.test.js

+4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ import dpMaximumSubarray from '../dpMaximumSubarray';
33
describe('dpMaximumSubarray', () => {
44
it('should find maximum subarray using dynamic programming algorithm', () => {
55
expect(dpMaximumSubarray([])).toEqual([]);
6+
expect(dpMaximumSubarray([0, 0])).toEqual([0]);
7+
expect(dpMaximumSubarray([0, 0, 1])).toEqual([0, 0, 1]);
8+
expect(dpMaximumSubarray([0, 0, 1, 2])).toEqual([0, 0, 1, 2]);
9+
expect(dpMaximumSubarray([0, 0, -1, 2])).toEqual([2]);
610
expect(dpMaximumSubarray([-1, -2, -3, -4, -5])).toEqual([-1]);
711
expect(dpMaximumSubarray([1, 2, 3, 2, 3, 4, 5])).toEqual([1, 2, 3, 2, 3, 4, 5]);
812
expect(dpMaximumSubarray([-2, 1, -3, 4, -1, 2, 1, -5, 4])).toEqual([4, -1, 2, 1]);

‎src/algorithms/sets/maximum-subarray/dpMaximumSubarray.js

+29-46
Original file line numberDiff line numberDiff line change
@@ -6,57 +6,40 @@
66
* @return {Number[]}
77
*/
88
export default function dpMaximumSubarray(inputArray) {
9-
// Check if all elements of inputArray are negative ones and return the highest
10-
// one in this case.
11-
let allNegative = true;
12-
let highestElementValue = null;
13-
for (let i = 0; i < inputArray.length; i += 1) {
14-
if (inputArray[i] >= 0) {
15-
allNegative = false;
16-
}
17-
18-
if (highestElementValue === null || highestElementValue < inputArray[i]) {
19-
highestElementValue = inputArray[i];
20-
}
21-
}
22-
23-
if (allNegative && highestElementValue !== null) {
24-
return [highestElementValue];
25-
}
26-
27-
// Let's assume that there is at list one positive integer exists in array.
28-
// And thus the maximum sum will for sure be grater then 0. Thus we're able
29-
// to always reset max sum to zero.
30-
let maxSum = 0;
31-
32-
// This array will keep a combination that gave the highest sum.
33-
let maxSubArray = [];
34-
35-
// Current sum and subarray that will memoize all previous computations.
9+
// We iterate through the inputArray once, using a greedy approach to keep track of the maximum
10+
// sum we've seen so far and the current sum.
11+
//
12+
// The currentSum variable gets reset to 0 every time it drops below 0.
13+
//
14+
// The maxSum variable is set to -Infinity so that if all numbers are negative, the highest
15+
// negative number will constitute the maximum subarray.
16+
17+
let maxSum = -Infinity;
3618
let currentSum = 0;
37-
let currentSubArray = [];
3819

39-
for (let i = 0; i < inputArray.length; i += 1) {
40-
// Let's add current element value to the current sum.
41-
currentSum += inputArray[i];
20+
// We need to keep track of the starting and ending indices that contributed to our maxSum
21+
// so that we can return the actual subarray. From the beginning let's assume that whole array
22+
// is contributing to maxSum.
23+
let maxStartIndex = 0;
24+
let maxEndIndex = inputArray.length - 1;
25+
let currentStartIndex = 0;
26+
27+
inputArray.forEach((currentNumber, currentIndex) => {
28+
currentSum += currentNumber;
29+
30+
// Update maxSum and the corresponding indices if we have found a new max.
31+
if (maxSum < currentSum) {
32+
maxSum = currentSum;
33+
maxStartIndex = currentStartIndex;
34+
maxEndIndex = currentIndex;
35+
}
4236

37+
// Reset currentSum and currentStartIndex if currentSum drops below 0.
4338
if (currentSum < 0) {
44-
// If the sum went below zero then reset it and don't add current element to max subarray.
4539
currentSum = 0;
46-
// Reset current subarray.
47-
currentSubArray = [];
48-
} else {
49-
// If current sum stays positive then add current element to current sub array.
50-
currentSubArray.push(inputArray[i]);
51-
52-
if (currentSum > maxSum) {
53-
// If current sum became greater then max registered sum then update
54-
// max sum and max subarray.
55-
maxSum = currentSum;
56-
maxSubArray = currentSubArray.slice();
57-
}
40+
currentStartIndex = currentIndex + 1;
5841
}
59-
}
42+
});
6043

61-
return maxSubArray;
44+
return inputArray.slice(maxStartIndex, maxEndIndex + 1);
6245
}

‎src/algorithms/sorting/shell-sort/README.md

+5-2
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ After this step, the array should look like this
3737

3838
![Shellsort](https://www.tutorialspoint.com/data_structures_algorithms/images/shell_sort_step_2.jpg)
3939

40+
> UPD: On the picture below there is a typo and result array is supposed to be `[14, 10, 27, 19, 35, 33, 42, 44]`.
41+
4042
Finally, we sort the rest of the array using interval of value 1.
4143
Shell sort uses insertion sort to sort the array.
4244

@@ -50,5 +52,6 @@ Shell sort uses insertion sort to sort the array.
5052

5153
## References
5254

53-
* [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)
54-
* [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
55+
- [Tutorials Point](https://www.tutorialspoint.com/data_structures_algorithms/shell_sort_algorithm.htm)
56+
- [Wikipedia](https://en.wikipedia.org/wiki/Shellsort)
57+
- [YouTube by Rob Edwards](https://www.youtube.com/watch?v=ddeLSDsYVp8&index=79&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)

‎src/algorithms/string/longest-common-substring/__test__/longestCommonSubstring.test.js

+11
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,16 @@ describe('longestCommonSubstring', () => {
77
expect(longestCommonSubstring('', 'ABC')).toBe('');
88
expect(longestCommonSubstring('ABABC', 'BABCA')).toBe('BABC');
99
expect(longestCommonSubstring('BABCA', 'ABCBA')).toBe('ABC');
10+
expect(longestCommonSubstring(
11+
'Algorithms and data structures implemented in JavaScript',
12+
'Here you may find Algorithms and data structures that are implemented in JavaScript',
13+
)).toBe('Algorithms and data structures ');
14+
});
15+
16+
it('should handle unicode correctly', () => {
17+
expect(longestCommonSubstring('𐌵𐌵**ABC', '𐌵𐌵--ABC')).toBe('ABC');
18+
expect(longestCommonSubstring('𐌵𐌵**A', '𐌵𐌵--A')).toBe('𐌵𐌵');
19+
expect(longestCommonSubstring('A买B时', '买B时GD')).toBe('买B时');
20+
expect(longestCommonSubstring('After test买时 case', 'another_test买时')).toBe('test买时');
1021
});
1122
});

‎src/algorithms/string/longest-common-substring/longestCommonSubstring.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
/**
2-
* @param {string} s1
3-
* @param {string} s2
2+
* @param {string} string1
3+
* @param {string} string2
44
* @return {string}
55
*/
6-
export default function longestCommonSubstring(s1, s2) {
6+
export default function longestCommonSubstring(string1, string2) {
7+
// Convert strings to arrays to treat unicode symbols length correctly.
8+
// For example:
9+
// '𐌵'.length === 2
10+
// [...'𐌵'].length === 1
11+
const s1 = [...string1];
12+
const s2 = [...string2];
13+
714
// Init the matrix of all substring lengths to use Dynamic Programming approach.
815
const substringMatrix = Array(s2.length + 1).fill(null).map(() => {
916
return Array(s1.length + 1).fill(null);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# 双向链表
2+
3+
在计算机科学中, 一个 **双向链表(doubly linked list)** 是由一组称为节点的顺序链接记录组成的链接数据结构。每个节点包含两个字段,称为链接,它们是对节点序列中上一个节点和下一个节点的引用。开始节点和结束节点的上一个链接和下一个链接分别指向某种终止节点,通常是前哨节点或null,以方便遍历列表。如果只有一个前哨节点,则列表通过前哨节点循环链接。它可以被概念化为两个由相同数据项组成的单链表,但顺序相反。
4+
5+
![Doubly Linked List](https://upload.wikimedia.org/wikipedia/commons/5/5e/Doubly-linked-list.svg)
6+
7+
两个节点链接允许在任一方向上遍历列表。
8+
9+
在双向链表中进行添加或者删除节点时,需做的链接更改要比单向链表复杂得多。这种操作在单向链表中更简单高效,因为不需要关注一个节点(除第一个和最后一个节点以外的节点)的两个链接,而只需要关注一个链接即可。
10+
11+
12+
13+
## 基础操作的伪代码
14+
15+
### 插入
16+
17+
```text
18+
Add(value)
19+
Pre: value is the value to add to the list
20+
Post: value has been placed at the tail of the list
21+
n ← node(value)
22+
if head = ø
23+
head ← n
24+
tail ← n
25+
else
26+
n.previous ← tail
27+
tail.next ← n
28+
tail ← n
29+
end if
30+
end Add
31+
```
32+
33+
### 删除
34+
35+
```text
36+
Remove(head, value)
37+
Pre: head is the head node in the list
38+
value is the value to remove from the list
39+
Post: value is removed from the list, true; otherwise false
40+
if head = ø
41+
return false
42+
end if
43+
if value = head.value
44+
if head = tail
45+
head ← ø
46+
tail ← ø
47+
else
48+
head ← head.Next
49+
head.previous ← ø
50+
end if
51+
return true
52+
end if
53+
n ← head.next
54+
while n = ø and value = n.value
55+
n ← n.next
56+
end while
57+
if n = tail
58+
tail ← tail.previous
59+
tail.next ← ø
60+
return true
61+
else if n = ø
62+
n.previous.next ← n.next
63+
n.next.previous ← n.previous
64+
return true
65+
end if
66+
return false
67+
end Remove
68+
```
69+
70+
### 反向遍历
71+
72+
```text
73+
ReverseTraversal(tail)
74+
Pre: tail is the node of the list to traverse
75+
Post: the list has been traversed in reverse order
76+
n ← tail
77+
while n = ø
78+
yield n.value
79+
n ← n.previous
80+
end while
81+
end Reverse Traversal
82+
```
83+
84+
## 复杂度
85+
86+
## 时间复杂度
87+
88+
| Access | Search | Insertion | Deletion |
89+
| :-------: | :-------: | :-------: | :-------: |
90+
| O(n) | O(n) | O(1) | O(1) |
91+
92+
### 空间复杂度
93+
94+
O(n)
95+
96+
## 参考
97+
98+
- [Wikipedia](https://en.wikipedia.org/wiki/Doubly_linked_list)
99+
- [YouTube](https://www.youtube.com/watch?v=JdQeNxWCguQ&t=7s&index=72&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#
2+
3+
在计算机科学中, **图(graph)** 是一种抽象数据类型,
4+
旨在实现数学中的无向图和有向图概念,特别是图论领域。
5+
6+
一个图数据结构是一个(由有限个或者可变数量的)顶点/节点/点和边构成的有限集。
7+
8+
如果顶点对之间是无序的,称为无序图,否则称为有序图;
9+
10+
如果顶点对之间的边是没有方向的,称为无向图,否则称为有向图;
11+
12+
如果顶点对之间的边是有权重的,该图可称为加权图。
13+
14+
15+
16+
![Graph](https://www.tutorialspoint.com/data_structures_algorithms/images/graph.jpg)
17+
18+
## 参考
19+
20+
- [Wikipedia](https://en.wikipedia.org/wiki/Graph_(abstract_data_type))
21+
- [Introduction to Graphs on YouTube](https://www.youtube.com/watch?v=gXgEDyodOJU&index=9&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
22+
- [Graphs representation on YouTube](https://www.youtube.com/watch?v=k1wraWzqtvQ&index=10&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# 哈希表
2+
3+
在计算中, 一个 **哈希表(hash table 或hash map)** 是一种实现 *关联数组(associative array)*
4+
的抽象数据;类型, 该结构可以将 *键映射到值*
5+
6+
哈希表使用 *哈希函数/散列函数* 来计算一个值在数组或桶(buckets)中或槽(slots)中对应的索引,可使用该索引找到所需的值。
7+
8+
理想情况下,散列函数将为每个键分配给一个唯一的桶(bucket),但是大多数哈希表设计采用不完美的散列函数,这可能会导致"哈希冲突(hash collisions)",也就是散列函数为多个键(key)生成了相同的索引,这种碰撞必须
9+
以某种方式进行处理。
10+
11+
12+
![Hash Table](https://upload.wikimedia.org/wikipedia/commons/7/7d/Hash_table_3_1_1_0_1_0_0_SP.svg)
13+
14+
通过单独的链接解决哈希冲突
15+
16+
![Hash Collision](https://upload.wikimedia.org/wikipedia/commons/d/d0/Hash_table_5_0_1_1_1_1_1_LL.svg)
17+
18+
## 参考
19+
20+
- [Wikipedia](https://en.wikipedia.org/wiki/Hash_table)
21+
- [YouTube](https://www.youtube.com/watch?v=shs0KM3wKv8&index=4&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)

‎src/data-structures/heap/Heap.js

+19-21
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,17 @@ export default class Heap {
144144

145145
/**
146146
* @param {*} item
147-
* @param {Comparator} [customFindingComparator]
147+
* @param {Comparator} [comparator]
148148
* @return {Heap}
149149
*/
150-
remove(item, customFindingComparator) {
150+
remove(item, comparator = this.compare) {
151151
// Find number of items to remove.
152-
const customComparator = customFindingComparator || this.compare;
153-
const numberOfItemsToRemove = this.find(item, customComparator).length;
152+
const numberOfItemsToRemove = this.find(item, comparator).length;
154153

155154
for (let iteration = 0; iteration < numberOfItemsToRemove; iteration += 1) {
156155
// We need to find item index to remove each time after removal since
157-
// indices are being change after each heapify process.
158-
const indexToRemove = this.find(item, customComparator).pop();
156+
// indices are being changed after each heapify process.
157+
const indexToRemove = this.find(item, comparator).pop();
159158

160159
// If we need to remove last child in the heap then just remove it.
161160
// There is no need to heapify the heap afterwards.
@@ -166,15 +165,14 @@ export default class Heap {
166165
this.heapContainer[indexToRemove] = this.heapContainer.pop();
167166

168167
// Get parent.
169-
const parentItem = this.hasParent(indexToRemove) ? this.parent(indexToRemove) : null;
170-
const leftChild = this.hasLeftChild(indexToRemove) ? this.leftChild(indexToRemove) : null;
168+
const parentItem = this.parent(indexToRemove);
171169

172-
// If there is no parent or parent is in incorrect order with the node
170+
// If there is no parent or parent is in correct order with the node
173171
// we're going to delete then heapify down. Otherwise heapify up.
174172
if (
175-
leftChild !== null
173+
this.hasLeftChild(indexToRemove)
176174
&& (
177-
parentItem === null
175+
!parentItem
178176
|| this.pairIsInCorrectOrder(parentItem, this.heapContainer[indexToRemove])
179177
)
180178
) {
@@ -190,12 +188,11 @@ export default class Heap {
190188

191189
/**
192190
* @param {*} item
193-
* @param {Comparator} [customComparator]
191+
* @param {Comparator} [comparator]
194192
* @return {Number[]}
195193
*/
196-
find(item, customComparator) {
194+
find(item, comparator = this.compare) {
197195
const foundItemIndices = [];
198-
const comparator = customComparator || this.compare;
199196

200197
for (let itemIndex = 0; itemIndex < this.heapContainer.length; itemIndex += 1) {
201198
if (comparator.equal(item, this.heapContainer[itemIndex])) {
@@ -224,9 +221,9 @@ export default class Heap {
224221
* @param {number} [customStartIndex]
225222
*/
226223
heapifyUp(customStartIndex) {
227-
// Take last element (last in array or the bottom left in a tree) in
228-
// a heap container and lift him up until we find the parent element
229-
// that is less then the current new one.
224+
// Take the last element (last in array or the bottom left in a tree)
225+
// in the heap container and lift it up until it is in the correct
226+
// order with respect to its parent element.
230227
let currentIndex = customStartIndex || this.heapContainer.length - 1;
231228

232229
while (
@@ -241,10 +238,11 @@ export default class Heap {
241238
/**
242239
* @param {number} [customStartIndex]
243240
*/
244-
heapifyDown(customStartIndex) {
245-
// Compare the root element to its children and swap root with the smallest
246-
// of children. Do the same for next children after swap.
247-
let currentIndex = customStartIndex || 0;
241+
heapifyDown(customStartIndex = 0) {
242+
// Compare the parent element to its children and swap parent with the appropriate
243+
// child (smallest child for MinHeap, largest child for MaxHeap).
244+
// Do the same for next children after swap.
245+
let currentIndex = customStartIndex;
248246
let nextIndex = null;
249247

250248
while (this.hasLeftChild(currentIndex)) {
+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# 堆 (数据结构)
2+
3+
在计算机科学中, 一个 ** 堆(heap)** 是一种特殊的基于树的数据结构,它满足下面描述的堆属性。
4+
5+
在一个 *最小堆(min heap)* 中, 如果 `P``C` 的一个父级节点, 那么 `P` 的key(或value)应小于或等于 `C` 的对应值.
6+
7+
![最小堆](https://upload.wikimedia.org/wikipedia/commons/6/69/Min-heap.png)
8+
9+
在一个 *最大堆(max heap)* 中, `P` 的key(或value)大于 `C` 的对应值。
10+
11+
![](https://upload.wikimedia.org/wikipedia/commons/3/38/Max-Heap.svg)
12+
13+
14+
在堆“顶部”的没有父级节点的节点,被称之为根节点。
15+
16+
## 参考
17+
18+
- [Wikipedia](https://en.wikipedia.org/wiki/Heap_(data_structure))
19+
- [YouTube](https://www.youtube.com/watch?v=t0Cq6tVNRBA&index=5&t=0s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)

‎src/data-structures/linked-list/README.md

+16-3
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,20 @@ Add(value)
3737
end if
3838
end Add
3939
```
40-
40+
41+
```text
42+
Prepend(value)
43+
Pre: value is the value to add to the list
44+
Post: value has been placed at the head of the list
45+
n ← node(value)
46+
n.next ← head
47+
head ← n
48+
if tail = ø
49+
tail ← n
50+
end
51+
end Prepend
52+
```
53+
4154
### Search
4255

4356
```text
@@ -76,10 +89,10 @@ Remove(head, value)
7689
end if
7790
return true
7891
end if
79-
while n.next = ø and n.next.value = value
92+
while n.next != ø and n.next.value != value
8093
n ← n.next
8194
end while
82-
if n.next = ø
95+
if n.next != ø
8396
if n.next = tail
8497
tail ← n
8598
end if
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# 链表
2+
3+
在计算机科学中, 一个 **链表** 是数据元素的线性集合, 元素的线性顺序不是由它们在内存中的物理位置给出的。 相反, 每个元素指向下一个元素。它是由一组节点组成的数据结构,这些节点一起,表示序列。
4+
5+
在最简单的形式下,每个节点由数据和到序列中下一个节点的引用(换句话说,链接)组成。这种结构允许在迭代期间有效地从序列中的任何位置插入或删除元素。
6+
7+
更复杂的变体添加额外的链接,允许有效地插入或删除任意元素引用。链表的一个缺点是访问时间是线性的(而且难以管道化)。
8+
9+
更快的访问,如随机访问,是不可行的。与链表相比,数组具有更好的缓存位置。
10+
11+
![Linked List](https://upload.wikimedia.org/wikipedia/commons/6/6d/Singly-linked-list.svg)
12+
13+
## 基本操作的伪代码
14+
15+
### 插入
16+
17+
```text
18+
Add(value)
19+
Pre: value is the value to add to the list
20+
Post: value has been placed at the tail of the list
21+
n ← node(value)
22+
if head = ø
23+
head ← n
24+
tail ← n
25+
else
26+
tail.next ← n
27+
tail ← n
28+
end if
29+
end Add
30+
```
31+
32+
### 搜索
33+
34+
```text
35+
Contains(head, value)
36+
Pre: head is the head node in the list
37+
value is the value to search for
38+
Post: the item is either in the linked list, true; otherwise false
39+
n ← head
40+
while n != ø and n.value != value
41+
n ← n.next
42+
end while
43+
if n = ø
44+
return false
45+
end if
46+
return true
47+
end Contains
48+
```
49+
50+
### 删除
51+
52+
```text
53+
Remove(head, value)
54+
Pre: head is the head node in the list
55+
value is the value to remove from the list
56+
Post: value is removed from the list, true, otherwise false
57+
if head = ø
58+
return false
59+
end if
60+
n ← head
61+
if n.value = value
62+
if head = tail
63+
head ← ø
64+
tail ← ø
65+
else
66+
head ← head.next
67+
end if
68+
return true
69+
end if
70+
while n.next = ø and n.next.value = value
71+
n ← n.next
72+
end while
73+
if n.next = ø
74+
if n.next = tail
75+
tail ← n
76+
end if
77+
n.next ← n.next.next
78+
return true
79+
end if
80+
return false
81+
end Remove
82+
```
83+
84+
### 遍历
85+
86+
```text
87+
Traverse(head)
88+
Pre: head is the head node in the list
89+
Post: the items in the list have been traversed
90+
n ← head
91+
while n = 0
92+
yield n.value
93+
n ← n.next
94+
end while
95+
end Traverse
96+
```
97+
98+
### 反向遍历
99+
100+
```text
101+
ReverseTraversal(head, tail)
102+
Pre: head and tail belong to the same list
103+
Post: the items in the list have been traversed in reverse order
104+
if tail = ø
105+
curr ← tail
106+
while curr = head
107+
prev ← head
108+
while prev.next = curr
109+
prev ← prev.next
110+
end while
111+
yield curr.value
112+
curr ← prev
113+
end while
114+
yeild curr.value
115+
end if
116+
end ReverseTraversal
117+
```
118+
119+
## 复杂度
120+
121+
### 时间复杂度
122+
123+
| Access | Search | Insertion | Deletion |
124+
| :-------: | :-------: | :-------: | :-------: |
125+
| O(n) | O(n) | O(1) | O(1) |
126+
127+
### 空间复杂度
128+
129+
O(n)
130+
131+
## 参考
132+
133+
- [Wikipedia](https://en.wikipedia.org/wiki/Linked_list)
134+
- [YouTube](https://www.youtube.com/watch?v=njTh_OwMljA&index=2&t=1s&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8)

‎src/data-structures/linked-list/__test__/LinkedList.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe('LinkedList', () => {
1616
linkedList.append(2);
1717

1818
expect(linkedList.toString()).toBe('1,2');
19+
expect(linkedList.tail.next).toBeNull();
1920
});
2021

2122
it('should prepend node to linked list', () => {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# 优先队列
2+
3+
在计算机科学中, **优先级队列(priority queue)** 是一种抽象数据类型, 它类似于常规的队列或栈, 但每个元素都有与之关联的“优先级”。
4+
5+
在优先队列中, 低优先级的元素之前前面应该是高优先级的元素。 如果两个元素具有相同的优先级, 则根据它们在队列中的顺序是它们的出现顺序即可。
6+
7+
优先队列虽通常用堆来实现,但它在概念上与堆不同。优先队列是一个抽象概念,就像“列表”或“图”这样的抽象概念一样;
8+
9+
正如列表可以用链表或数组实现一样,优先队列可以用堆或各种其他方法实现,例如无序数组。
10+
11+
12+
## 参考
13+
14+
- [Wikipedia](https://en.wikipedia.org/wiki/Priority_queue)
15+
- [YouTube](https://www.youtube.com/watch?v=wptevk0bshY&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=6)

‎src/data-structures/queue/Queue.js

+10-13
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,47 @@ import LinkedList from '../linked-list/LinkedList';
22

33
export default class Queue {
44
constructor() {
5-
// We're going to implement Queue based on LinkedList since this
6-
// structures a quite similar. Namely they both operates mostly with
7-
// with theirs beginning and the end. Compare enqueue/de-queue
8-
// operations of the Queue with append/prepend operations of LinkedList.
5+
// We're going to implement Queue based on LinkedList since the two
6+
// structures are quite similar. Namely, they both operate mostly on
7+
// the elements at the beginning and the end. Compare enqueue/dequeue
8+
// operations of Queue with append/deleteHead operations of LinkedList.
99
this.linkedList = new LinkedList();
1010
}
1111

1212
/**
1313
* @return {boolean}
1414
*/
1515
isEmpty() {
16-
// The queue is empty in case if its linked list don't have tail.
17-
return !this.linkedList.tail;
16+
return !this.linkedList.head;
1817
}
1918

2019
/**
20+
* Read the element at the front of the queue without removing it.
2121
* @return {*}
2222
*/
2323
peek() {
2424
if (!this.linkedList.head) {
25-
// If linked list is empty then there is nothing to peek from.
2625
return null;
2726
}
2827

29-
// Just read the value from the end of linked list without deleting it.
3028
return this.linkedList.head.value;
3129
}
3230

3331
/**
32+
* Add a new element to the end of the queue (the tail of the linked list).
33+
* This element will be processed after all elements ahead of it.
3434
* @param {*} value
3535
*/
3636
enqueue(value) {
37-
// Enqueueing means to stand in the line. Therefore let's just add
38-
// new value at the beginning of the linked list. It will need to wait
39-
// until all previous nodes will be processed.
4037
this.linkedList.append(value);
4138
}
4239

4340
/**
41+
* Remove the element at the front of the queue (the head of the linked list).
42+
* If the queue is empty, return null.
4443
* @return {*}
4544
*/
4645
dequeue() {
47-
// Let's try to delete the last node from linked list (the tail).
48-
// If there is no tail in linked list (it is empty) just return null.
4946
const removedHead = this.linkedList.deleteHead();
5047
return removedHead ? removedHead.value : null;
5148
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# 队列
2+
3+
在计算机科学中, 一个 **队列(queue)** 是一种特殊类型的抽象数据类型或集合。集合中的实体按顺序保存。
4+
5+
队列基本操作有两种: 向队列的后端位置添加实体,称为入队,并从队列的前端位置移除实体,称为出队。
6+
7+
8+
队列中元素先进先出 FIFO (first in, first out)的示意
9+
10+
![Queue](https://upload.wikimedia.org/wikipedia/commons/5/52/Data_Queue.svg)
11+
12+
## 参考
13+
14+
- [Wikipedia](https://en.wikipedia.org/wiki/Queue_(abstract_data_type))
15+
- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#
2+
3+
在计算机科学中, 一个 **栈(stack)** 时一种抽象数据类型,用作表示元素的集合,具有两种主要操作:
4+
5+
* **push**, 添加元素到栈的顶端(末尾);
6+
* **pop**, 移除栈最顶端(末尾)的元素.
7+
8+
以上两种操作可以简单概括为“后进先出(LIFO = last in, first out)”。
9+
10+
此外,应有一个 `peek` 操作用于访问栈当前顶端(末尾)的元素。
11+
12+
"栈"这个名称,可类比于一组物体的堆叠(一摞书,一摞盘子之类的)。
13+
14+
栈的 push 和 pop 操作的示意
15+
16+
![Stack](https://upload.wikimedia.org/wikipedia/commons/b/b4/Lifo_stack.png)
17+
18+
## 参考
19+
20+
- [Wikipedia](https://en.wikipedia.org/wiki/Stack_(abstract_data_type))
21+
- [YouTube](https://www.youtube.com/watch?v=wjI1WNcIntg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=3&)
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
3+
* [二叉搜索树](binary-search-tree)
4+
* [AVL树](avl-tree)
5+
* [红黑树](red-black-tree)
6+
* [线段树](segment-tree) - with min/max/sum range queries examples
7+
* [芬威克树/Fenwick Tree](fenwick-tree) (Binary Indexed Tree)
8+
9+
在计算机科学中, **树(tree)** 是一种广泛使用的抽象数据类型(ADT)— 或实现此ADT的数据结构 — 模拟分层树结构, 具有根节点和有父节点的子树,表示为一组链接节点。
10+
11+
树可以被(本地地)递归定义为一个(始于一个根节点的)节点集, 每个节点都是一个包含了值的数据结构, 除了值,还有该节点的节点引用列表(子节点)一起。
12+
树的节点之间没有引用重复的约束。
13+
14+
一棵简单的无序树; 在下图中:
15+
16+
标记为7的节点具有两个子节点, 标记为2和6;
17+
一个父节点,标记为2,作为根节点, 在顶部,没有父节点。
18+
19+
![Tree](https://upload.wikimedia.org/wikipedia/commons/f/f7/Binary_tree.svg)
20+
21+
## 参考
22+
23+
- [Wikipedia](https://en.wikipedia.org/wiki/Tree_(data_structure))
24+
- [YouTube](https://www.youtube.com/watch?v=oSWTXtMglKE&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=8)

‎src/data-structures/tree/segment-tree/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ and geographic information systems.
4040
Current implementation of Segment Tree implies that you may
4141
pass any binary (with two input params) function to it and
4242
thus you're able to do range query for variety of functions.
43-
In tests you may fins examples of doing `min`, `max` and `sam` range
43+
In tests you may find examples of doing `min`, `max` and `sam` range
4444
queries on SegmentTree.
4545

4646
## References
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# 字典树
2+
3+
在计算机科学中, **字典树(trie,中文又被称为”单词查找树“或 ”键树“)**, 也称为数字树,有时候也被称为基数树或前缀树(因为它们可以通过前缀搜索),它是一种搜索树--一种已排序的数据结构,通常用于存储动态集或键为字符串的关联数组。
4+
5+
与二叉搜索树不同, 树上没有节点存储与该节点关联的键; 相反,节点在树上的位置定义了与之关联的键。一个节点的全部后代节点都有一个与该节点关联的通用的字符串前缀, 与根节点关联的是空字符串。
6+
7+
值对于字典树中关联的节点来说,不是必需的,相反,值往往和相关的叶子相关,以及与一些键相关的内部节点相关。
8+
9+
有关字典树的空间优化示意,请参阅紧凑前缀树
10+
11+
![Trie](https://upload.wikimedia.org/wikipedia/commons/b/be/Trie_example.svg)
12+
13+
## 参考
14+
15+
- [Wikipedia](https://en.wikipedia.org/wiki/Trie)
16+
- [YouTube](https://www.youtube.com/watch?v=zIjfhVPRZCg&list=PLLXdhg_r2hKA7DPDsunoDZ-Z769jWn4R8&index=7&t=0s)

0 commit comments

Comments
 (0)
Please sign in to comment.