|
2 | 2 | // const Tree = require('../../trees/red-black-tree'); // fast insertion |
3 | 3 | const Tree = require('../../trees/avl-tree'); // fast lookup |
4 | 4 |
|
| 5 | +/** |
| 6 | + * TreeMap is a Map implementation using a self-balanced tree |
| 7 | + * such as AVL Tree or Red-Black tree to guarantee O(log n) operations. |
| 8 | + * |
| 9 | + * Implementing a Map with a tree, TreeMap, |
| 10 | + * has a couple of advantages over a HashMap: |
| 11 | + * • Keys are always sorted. |
| 12 | + * • Statistical data can be easily obtained like median, |
| 13 | + * highest, lowest key. |
| 14 | + * • Collisions are not a concern so in the worst case is |
| 15 | + * still O(log n). |
| 16 | + * • Trees are more space efficient and doesn’t need to |
| 17 | + * allocate memory beforehand (e.g. HashMap’s initial capacity) |
| 18 | + * nor you have to rehash when is getting full. |
| 19 | + * |
| 20 | + */ |
5 | 21 | class TreeMap { |
| 22 | + /** |
| 23 | + * Initialize tree |
| 24 | + */ |
6 | 25 | constructor() { |
7 | 26 | this.tree = new Tree(); |
8 | 27 | } |
9 | 28 |
|
| 29 | + /** |
| 30 | + * Insert a key/value pair into the map. |
| 31 | + * If the key is already there replaces its content. |
| 32 | + * Runtime: O(log n) |
| 33 | + * @param {any} key |
| 34 | + * @param {any} value |
| 35 | + * @returns {TreeNode} Return the Map object to allow chaining |
| 36 | + */ |
10 | 37 | set(key, value) { |
| 38 | + const node = this.tree.get(key); |
| 39 | + if (node) { |
| 40 | + node.data(value); |
| 41 | + return node; |
| 42 | + } |
11 | 43 | return this.tree.add(key).data(value); |
12 | 44 | } |
13 | 45 |
|
| 46 | + /** |
| 47 | + * Size of the map |
| 48 | + */ |
14 | 49 | get size() { |
15 | 50 | return this.tree.size; |
16 | 51 | } |
17 | 52 |
|
| 53 | + /** |
| 54 | + * Gets the value out of the map |
| 55 | + * Runtime: O(log n) |
| 56 | + * @param {any} key |
| 57 | + * @returns {any} value associated to the key, or undefined if there is none. |
| 58 | + */ |
18 | 59 | get(key) { |
19 | 60 | const node = this.tree.get(key) || undefined; |
20 | | - return node && node.getData(); |
| 61 | + return node && node.data(); |
21 | 62 | } |
22 | 63 |
|
| 64 | + /** |
| 65 | + * Search for key and return true if it was found |
| 66 | + * Runtime: O(log n) |
| 67 | + * @param {any} key |
| 68 | + * @returns {boolean} indicating whether an element |
| 69 | + * with the specified key exists or not. |
| 70 | + */ |
23 | 71 | has(key) { |
24 | 72 | return !!this.get(key); |
25 | 73 | } |
26 | 74 |
|
| 75 | + /** |
| 76 | + * Removes the specified element from the map. |
| 77 | + * Runtime: O(log n) |
| 78 | + * @param {*} key |
| 79 | + * @returns {boolean} true if an element in the Map object existed |
| 80 | + * and has been removed, or false if the element did not exist. |
| 81 | + */ |
27 | 82 | delete(key) { |
28 | 83 | return this.tree.remove(key); |
29 | 84 | } |
30 | 85 |
|
| 86 | + /** |
| 87 | + * Default iterator for this map |
| 88 | + */ |
31 | 89 | * [Symbol.iterator]() { |
32 | 90 | yield* this.tree.inOrderTraversal(); |
33 | 91 | } |
34 | 92 |
|
| 93 | + /** |
| 94 | + * Keys for each element in the Map object |
| 95 | + * in order ascending order. |
| 96 | + * @returns {Iterator} keys |
| 97 | + */ |
35 | 98 | * keys() { |
36 | 99 | for (const node of this) { |
37 | 100 | yield node.value; |
38 | 101 | } |
39 | 102 | } |
40 | 103 |
|
| 104 | + /** |
| 105 | + * Values for each element in the Map object |
| 106 | + * in corresponding key ascending order. |
| 107 | + * @returns {Iterator} values without holes (empty spaces of deleted values) |
| 108 | + */ |
41 | 109 | * values() { |
42 | 110 | for (const node of this) { |
43 | | - yield node.getData(); |
| 111 | + yield node.data(); |
44 | 112 | } |
45 | 113 | } |
46 | 114 |
|
| 115 | + /** |
| 116 | + * Contains the [key, value] pairs for each element in the Map object |
| 117 | + * in corresponding key ascending order. |
| 118 | + * @returns {Iterator} |
| 119 | + */ |
47 | 120 | * entries() { |
48 | 121 | for (const node of this) { |
49 | | - yield [node.value, node.getData()]; |
| 122 | + yield [node.value, node.data()]; |
50 | 123 | } |
51 | 124 | } |
52 | 125 | } |
53 | 126 |
|
54 | 127 | // Aliases |
55 | 128 | TreeMap.prototype.containsKey = TreeMap.prototype.has; |
| 129 | +TreeMap.prototype.put = TreeMap.prototype.set; |
56 | 130 |
|
57 | 131 | module.exports = TreeMap; |
0 commit comments