diff --git a/problem-1/SymbolTableWithArray.js b/problem-1/SymbolTableWithArray.js index 761c9ef..2175530 100644 --- a/problem-1/SymbolTableWithArray.js +++ b/problem-1/SymbolTableWithArray.js @@ -1,4 +1,69 @@ class SymbolTable { + #keys = []; + + #values = []; + + #numberOfItems = 0; + + constructor(count = 20) { + this.#keys = new Array(count); + this.#values = new Array(count); + } + + put(key, value) { + for (let index = 0; index < this.#numberOfItems; index++) { + if (key === this.#keys[index]) { + this.#values[index] = value; + return; + } + } + + this.#keys[this.#numberOfItems] = key; + this.#values[this.#numberOfItems] = value; + this.#numberOfItems += 1; + } + + get(key) { + for (let index = 0; index < this.#numberOfItems; index++) { + if (key === this.#keys[index]) { + return this.#values[index]; + } + } + } + + delete(key) { + for (let index = 0; index < this.#numberOfItems; index++) { + if (key === this.#keys[index]) { + for (let j = index; j < this.#numberOfItems - 1; j++) { + this.#keys[j] = this.#keys[j + 1]; + this.#values[j] = this.#values[j + 1]; + } + + this.#numberOfItems -= 1; + return; + } + } + } + + contains(key) { + return !!this.get(key); + } + + size() { + return this.#numberOfItems; + } + + isEmpty() { + return this.#numberOfItems === 0; + } + + keys() { + return [...this.#keys]; + } + + values() { + return [...this.#values]; + } } module.exports = { diff --git a/problem-2/SymbolTable.js b/problem-2/SymbolTable.js index 6bb3c68..7eea112 100644 --- a/problem-2/SymbolTable.js +++ b/problem-2/SymbolTable.js @@ -106,15 +106,56 @@ class SymbolTable { } contains(key) { + return !!this.get(key); } floor(key) { + if (this.isEmpty()) { + return; + } + + const index = this.rank(key); + + if (index === 0) { + return this.#keys[index] === key ? key : undefined; + } + + if (key === this.#keys[index]) { + return key; + } + + return this.#keys[index - 1]; } ceiling(key) { + if (this.isEmpty()) { + return; + } + + const index = this.rank(key); + + if (index >= this.#n) { + return; + } + + return this.#keys[index]; } keysRange(start, end) { + const startIndex = this.rank(start); + const endIndex = this.rank(end); + + const keys = []; + + for (let index = startIndex; index < endIndex; index++) { + keys.push(this.#keys[index]); + } + + if (end === this.#keys[endIndex]) { + keys.push(end); + } + + return keys; } } diff --git a/problem-3/README.md b/problem-3/README.md index 8a33794..57a0ee5 100644 --- a/problem-3/README.md +++ b/problem-3/README.md @@ -17,7 +17,7 @@ I: 9 O: 10 N: 11 ``` - +![bst.png](bst.png) 2. 트리의 높이를 구하는 height를 구현해 주세요. 이때 2가지 버전의 구현을 만들어 주세요. 첫 번째는 재귀로 실행할 때마다 새로 계산해서 높이를 구하는 버전을 만들어 주세요. 두 번째는 `size()`와 비슷하게 각 노드에 트리의 높이를 담는 diff --git a/problem-3/SymbolTable.js b/problem-3/SymbolTable.js index 8bff19c..5ab683e 100644 --- a/problem-3/SymbolTable.js +++ b/problem-3/SymbolTable.js @@ -9,10 +9,13 @@ class Node { n; - constructor(key, value, n) { + height; + + constructor(key, value, n, height = 0) { this.key = key; this.value = value; this.n = n; + this.height = height; } } @@ -70,6 +73,7 @@ class SymbolTable { } node.n = this.#size(node.left) + this.#size(node.right) + 1; + node.height = 1 + Math.max(this.#height(node.left), this.#height(node.right)); return node; } @@ -181,6 +185,7 @@ class SymbolTable { node.left = this.#deleteMin(node.left); node.n = this.#size(node.left) + this.#size(node.right) + 1; + node.height = 1 + Math.max(this.#height(node.left), this.#height(node.right)); return node; } @@ -213,6 +218,7 @@ class SymbolTable { } node.n = this.#size(node.left) + this.#size(node.right) + 1; + node.height = 1 + Math.max(this.#height(node.left), this.#height(node.right)); return node; } @@ -269,6 +275,18 @@ class SymbolTable { return this.#max(node.right); } + + height() { + return this.#height(this.#root); + } + + #height(node) { + if (node === undefined) { + return -1; + } + + return node.height; + } } module.exports = { diff --git a/problem-3/bst.png b/problem-3/bst.png new file mode 100644 index 0000000..de2754d Binary files /dev/null and b/problem-3/bst.png differ diff --git a/problem-4/2-3tree-01.png b/problem-4/2-3tree-01.png new file mode 100644 index 0000000..7a2a2e2 Binary files /dev/null and b/problem-4/2-3tree-01.png differ diff --git a/problem-4/2-3tree-02.png b/problem-4/2-3tree-02.png new file mode 100644 index 0000000..91ece4f Binary files /dev/null and b/problem-4/2-3tree-02.png differ diff --git a/problem-4/2-3tree-03.png b/problem-4/2-3tree-03.png new file mode 100644 index 0000000..f4fd348 Binary files /dev/null and b/problem-4/2-3tree-03.png differ diff --git a/problem-4/2-3tree-04.png b/problem-4/2-3tree-04.png new file mode 100644 index 0000000..930ffe1 Binary files /dev/null and b/problem-4/2-3tree-04.png differ diff --git a/problem-4/2-3tree-05.png b/problem-4/2-3tree-05.png new file mode 100644 index 0000000..afc1b9f Binary files /dev/null and b/problem-4/2-3tree-05.png differ diff --git a/problem-4/2-3tree-06.png b/problem-4/2-3tree-06.png new file mode 100644 index 0000000..5cfde69 Binary files /dev/null and b/problem-4/2-3tree-06.png differ diff --git a/problem-4/2-3tree-07.png b/problem-4/2-3tree-07.png new file mode 100644 index 0000000..18ebcb4 Binary files /dev/null and b/problem-4/2-3tree-07.png differ diff --git a/problem-4/2-3tree-08.png b/problem-4/2-3tree-08.png new file mode 100644 index 0000000..2fc57e8 Binary files /dev/null and b/problem-4/2-3tree-08.png differ diff --git a/problem-4/2-3tree-09.png b/problem-4/2-3tree-09.png new file mode 100644 index 0000000..b4992f8 Binary files /dev/null and b/problem-4/2-3tree-09.png differ diff --git a/problem-4/2-3tree-10.png b/problem-4/2-3tree-10.png new file mode 100644 index 0000000..f574355 Binary files /dev/null and b/problem-4/2-3tree-10.png differ diff --git a/problem-4/README.md b/problem-4/README.md index fa445ed..333daef 100644 --- a/problem-4/README.md +++ b/problem-4/README.md @@ -5,6 +5,46 @@ ``` E A S Y Q U T I O N ``` +![2-3tree-01.png](2-3tree-01.png) + +![2-3tree-02.png](2-3tree-02.png) + +![2-3tree-03.png](2-3tree-03.png) + +![2-3tree-04.png](2-3tree-04.png) + +![2-3tree-05.png](2-3tree-05.png) + +![2-3tree-06.png](2-3tree-06.png) + +![2-3tree-07.png](2-3tree-07.png) + +![2-3tree-08.png](2-3tree-08.png) + +![2-3tree-09.png](2-3tree-09.png) + +![2-3tree-10.png](2-3tree-10.png) + 2. 이번에는 위의 키 목록을 레드 블랙 트리에 순서대로 추가했을 때 만들어지는 레드 블랙 트리를 그려주세요. + +![red-black-tree-01.png](red-black-tree-01.png) + +![red-black-tree-02.png](red-black-tree-02.png) + +![red-black-tree-03.png](red-black-tree-03.png) + +![red-black-tree-04.png](red-black-tree-04.png) + +![red-black-tree-05.png](red-black-tree-05.png) + +![red-black-tree-06.png](red-black-tree-06.png) + +![red-black-tree-07.png](red-black-tree-07.png) + +![red-black-tree-08.png](red-black-tree-08.png) + +![red-black-tree-09.png](red-black-tree-09.png) + +![red-black-tree-10.png](red-black-tree-10.png) diff --git a/problem-4/red-black-tree-01.png b/problem-4/red-black-tree-01.png new file mode 100644 index 0000000..791fcc7 Binary files /dev/null and b/problem-4/red-black-tree-01.png differ diff --git a/problem-4/red-black-tree-02.png b/problem-4/red-black-tree-02.png new file mode 100644 index 0000000..138b62d Binary files /dev/null and b/problem-4/red-black-tree-02.png differ diff --git a/problem-4/red-black-tree-03.png b/problem-4/red-black-tree-03.png new file mode 100644 index 0000000..ea8e2a6 Binary files /dev/null and b/problem-4/red-black-tree-03.png differ diff --git a/problem-4/red-black-tree-04.png b/problem-4/red-black-tree-04.png new file mode 100644 index 0000000..f7019a8 Binary files /dev/null and b/problem-4/red-black-tree-04.png differ diff --git a/problem-4/red-black-tree-05.png b/problem-4/red-black-tree-05.png new file mode 100644 index 0000000..f4bbfd0 Binary files /dev/null and b/problem-4/red-black-tree-05.png differ diff --git a/problem-4/red-black-tree-06.png b/problem-4/red-black-tree-06.png new file mode 100644 index 0000000..35a6203 Binary files /dev/null and b/problem-4/red-black-tree-06.png differ diff --git a/problem-4/red-black-tree-07.png b/problem-4/red-black-tree-07.png new file mode 100644 index 0000000..7a49833 Binary files /dev/null and b/problem-4/red-black-tree-07.png differ diff --git a/problem-4/red-black-tree-08.png b/problem-4/red-black-tree-08.png new file mode 100644 index 0000000..85eacd4 Binary files /dev/null and b/problem-4/red-black-tree-08.png differ diff --git a/problem-4/red-black-tree-09.png b/problem-4/red-black-tree-09.png new file mode 100644 index 0000000..72a769b Binary files /dev/null and b/problem-4/red-black-tree-09.png differ diff --git a/problem-4/red-black-tree-10.png b/problem-4/red-black-tree-10.png new file mode 100644 index 0000000..f1e1eb8 Binary files /dev/null and b/problem-4/red-black-tree-10.png differ diff --git a/problem-5/LinearProbingHashTable.test.js b/problem-5/LinearProbingHashTable.test.js index e4a1b2b..985fd49 100644 --- a/problem-5/LinearProbingHashTable.test.js +++ b/problem-5/LinearProbingHashTable.test.js @@ -1,7 +1,10 @@ class LinearProbingHashTable { #N = 0; + #M = 0; + #keys = []; + #values = []; constructor(maxCount = 16) { @@ -19,25 +22,85 @@ class LinearProbingHashTable { } hash(key) { - return this.#hash(key) + return this.#hash(key); } get(key) { + for (let i = this.#hash(key); this.#keys[i] !== undefined; i = (i + 1) % this.#M) { + if (this.#keys[i] === key) { + return this.#values[i]; + } + } } put(key, value) { + if (this.#N >= (this.#M / 2)) { + this.#resize(this.#M * 2); + } + + let i; + for (i = this.#hash(key); this.#keys[i] !== undefined; i = (i + 1) % this.#M) { + if (this.#keys[i] === key) { + this.#values[i] = value; + return; + } + } + + this.#keys[i] = key; + this.#values[i] = value; + this.#N++; } delete(key) { + if (!this.contains(key)) { + return; + } + + let i = this.#hash(key); + while (this.#keys[i] !== key) { + i = (i + 1) % this.#M; + } + + this.#keys[i] = undefined; + this.#values[i] = undefined; + + i = (i + 1) % this.#M; + + while (this.#keys[i] !== undefined) { + const keyToRedo = this.#keys[i]; + const valueToRedo = this.#values[i]; + + this.#keys[i] = undefined; + this.#values[i] = undefined; + this.#N--; + this.put(keyToRedo, valueToRedo); + i = (i + 1) % this.#M; + } + + this.#N--; + + if (this.#N > 0 && this.#N < (this.#M / 8)) { + this.#resize(this.#M / 2); + } } contains(key) { + return this.get(key) !== undefined; } keys() { + return this.#keys.filter((key) => key !== undefined); } #resize(capacity) { + const t = new LinearProbingHashTable(capacity); + for (let i = 0; i < this.#M; i++) { + if (this.#keys[i] !== undefined) { + t.put(this.#keys[i], this.#values[i]); + } + } + this.#keys = t.#keys; + this.#values = t.#values; } } @@ -53,7 +116,7 @@ const randomString = (max) => { } return result; -} +}; test('이미 있는 키 값에 값을 추가하면 이전 값을 덮어쓴다', () => { const st = new LinearProbingHashTable(); diff --git a/problem-5/README.md b/problem-5/README.md index 17d1e7f..6e6c741 100644 --- a/problem-5/README.md +++ b/problem-5/README.md @@ -8,12 +8,16 @@ ``` E A S Y Q U T I O N ``` +![seperate-chaining-hash-table.png](seperate-chaining-hash-table.png) + 2. 선형 탐지 해싱 테이블에 위의 주어진 키를 순서대로 삽입했을 때 테이블의 내부 상태를 그림으로 그려 주세요. 초기 상태는 비어 있고 M=5라고 가정합니다. 삽입할 때 공간이 부족하다면 2배씩 테이블을 증가시킵니다. 마찬가지로 키의 알파벳 순서를 k라 할 때 해시 함수 11k % M을 이용하여 테이블의 인덱스로 변환해 주세요. +![linear-probing-hash-table.png](linear-probing-hash-table.png) + 3. 테스트 요구사항에 맞는 개별 체이닝 해시 테이블과 선형 탐지 해싱 테이블을 구현해 주세요. diff --git a/problem-5/SeperateChainingHashTable.test.js b/problem-5/SeperateChainingHashTable.test.js index 6f9e2b1..feabb09 100644 --- a/problem-5/SeperateChainingHashTable.test.js +++ b/problem-5/SeperateChainingHashTable.test.js @@ -1,8 +1,17 @@ +const { SymbolTableWithLinkedList } = require('../problem-1/SymbolTableWithLinkedList'); + class SeperateChainingHashTable { #M; + #st; + constructor(maxCount = 997) { this.#M = maxCount; + + this.#st = new Array(maxCount); + for (let i = 0; i < this.#M; i++) { + this.#st[i] = new SymbolTableWithLinkedList(); + } } #hash(key) { @@ -14,22 +23,37 @@ class SeperateChainingHashTable { } hash(key) { - return this.#hash(key) + return this.#hash(key); } get(key) { + return this.#st[this.#hash(key)].get(key); } put(key, value) { + this.#st[this.#hash(key)].put(key, value); } delete(key, value) { + this.#st[this.#hash(key)].delete(key); } - + contains(key) { + return this.get(key) !== undefined; } keys() { + const keyList = []; + + this.#st.forEach((table) => { + const keys = table.keys(); + + for (const key of keys) { + keyList.push(key); + } + }); + + return keyList; } } @@ -45,7 +69,7 @@ const randomString = (max) => { } return result; -} +}; test('이미 있는 키 값에 값을 추가하면 이전 값을 덮어쓴다', () => { const st = new SeperateChainingHashTable(); diff --git a/problem-5/linear-probing-hash-table.png b/problem-5/linear-probing-hash-table.png new file mode 100644 index 0000000..79ad71b Binary files /dev/null and b/problem-5/linear-probing-hash-table.png differ diff --git a/problem-5/seperate-chaining-hash-table.png b/problem-5/seperate-chaining-hash-table.png new file mode 100644 index 0000000..4efe0ad Binary files /dev/null and b/problem-5/seperate-chaining-hash-table.png differ