├── .gitignore ├── README.md ├── binarySearchTree.js ├── deque.js ├── graph.js ├── hashtable.js ├── heap.js ├── images ├── Time_complexity.png ├── binarysearchtree.png ├── binarysearchtree_img.png ├── etc.png ├── heap.png ├── linkedlist.png ├── stack_queue.png ├── tree_traversal.png └── treeandbinarytree.png ├── linkedList.js ├── package.json ├── priorityQueue.js ├── queue.js ├── stack.js ├── test.html ├── traversal.js └── tree.js /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # data-structure 2 | [양아름님](https://github.com/yangareum1818/data-structure)께서 3 | 이 강좌를 듣고 너무나 정리를 잘 해주셔서 강의 교안을 거의 그대로 사용합니다. 4 | 5 | ## 시간복잡도 6 | 7 | ![시간복잡도](/images/Time_complexity.png) 8 | 9 | ## 연결리스트 10 | 11 | ![연결리스트](/images/linkedlist.png) 12 | 13 | ## 스택과 큐 14 | 15 | ![스택과 큐](/images/stack_queue.png) 16 | 17 | ## 트리와 이진트리 종류 18 | 19 | ![트리와 이진틀리 종류](/images/treeandbinarytree.png) 20 | 21 | ## __⭐️이진탐색트리⭐️ : 재귀함수, 주석, 트리, 코드를 보면서 흐름을 파악해야한다.__ 22 | 23 | ![이진탐색트리](/images/binarysearchtree.png) 24 | 25 | --- 26 | ![이진탐색트리 삽입](/images/binarysearchtree_img.png) 27 | >5, 9, 4, 14, 19, 23, 7, 11, 8, 2, 16 28 | 29 |
30 | 31 | ### 1. 삽입에 대한 정리. `insert()` 32 | 33 | 1. 어떤 값을 넣으려고할 때, 일단 어디에 넣을지 모르겠다. 34 | 2. 그래서 왼쪽, 오른쪽에게 위임한다. ( 맡긴다, 처리하라고 한다. ) 35 | 3. 근데 만약, 왼쪽 또는 오른쪽이 없다면 그 자리에 삽입한다. 36 | 37 | >5입장에서 11을 넣으려고 할 때, 9와 14에게 위임한 뒤, 11을 추가할 수 있다.
38 | 14에게 위임할 때, 왼쪽을 찾으려고 했더니 왼쪽이 없는 상황이다.
39 | 11을 넣고자 하는 상황에 왼쪽이 비어있다는 것을 인지한다. 40 | 41 | 1. 상위 값보다 넣으려는 값이 큰지, 작은지를 인지(조건문)하고 값을 넣는다.
42 | __깔끔하고 명확하게 넣어줘야하기 때문에__ 추가적으로, 그 자리에 값이 있는지 없는지를 판단하는 조건을 추가한다. 43 | 2. 있다면 다시 재귀함수를 호출한다. 44 | 3. 없다면( 비어있다면 ), 그 자리에 값을 삽입한다.
45 | (이것이 __재귀함수를 사용하는 것__ 이다.) 46 | 47 | ```javascript 48 | #insert(node, value) { 49 | if (node.value > value) { 50 | // 상위 값보다 넣으려고 하는 값이 작으면, 왼쪽 51 | if (node.left) { 52 | // 왼쪽에 값이 있으면, 왼쪽에 있는 값에게 처리를 넘김 53 | this.#insert(node.left, value); 54 | } else { 55 | // 만약 왼쪽이 비어있다면? 왼쪽에 추가 56 | node.left = new Node(value); 57 | } 58 | } else { 59 | // 상위 값보다 넣으려고 하는 값이 크면, 오른쪽 60 | if (node.right) { 61 | // 오른쪽에 값이 있으면, 오른쪽에 있는 값에게 처리를 넘김 62 | this.#insert(node.right, value); 63 | } else { 64 | // 만약 오른쪽이 비어있다면? 오른쪽에 추가 65 | node.right = new Node(value); 66 | } 67 | } 68 | } 69 | ``` 70 | 71 |
72 | 73 | ### 2. 검색(조회)에 대한 정리 `search()` 74 | 75 | * 해당 값을 검사하고 찾아 처리해줘야하기 때문에, 모든 값을 `return` 해줘야한다. 76 | * 수정은 검색(조회)를 활용한다. 77 | * `#insert()`재귀함수와 동일한 조건의 틀을 가진다. 78 | * 찾는 값과 해당 node가 같은지(조건)와 결과를 `return`을 해줘야하는 부분만 다르다. 79 | 80 | 1. 11을 찾는다고 가정하고 코드의 흐름을 따라간다. 81 | 2. 또, 없는 값을 생각하고 어떻게 코드가 흐르는지도 파악한다. ( 어떻게 해서 `null`을 `return` 하는지 ) 82 | 83 |
84 | 85 | ### 3. 삭제(제거)에 대한 정리 `remove()` 86 | 87 | >__조건 : 제거하려는 값(`value`)과 트리 내부의 존재하는 값(`node.value or root`)이 동일한 경우__ 88 | 89 | 1. `leaf`일 경우
90 | 결과 : `null`을 `return`한다. 91 | 2. 자식 `Node`가 1개일 경우
92 | 2-1. 왼쪽 `Node`만 있을 경우
93 | 결과 : (오른쪽 `Node`가 없을 경우) 왼쪽 `Node`를 `return`한다.
94 | 2-2. 오른쪽 `Node`만 있을 경우
95 | 결과 : (왼쪽 `Node`가 없을 경우) 오른쪽 `Node`를 `return`한다.
96 | 97 | 3. 자식 `Node`가 2개일 경우 98 | 99 | * 만약, 어떠한 값을 제거한다면? ( `root`를 제거한다면 )
100 | 3-1. 자신의 왼쪽 `Node`로부터 오른쪽 `Node` 중 가장 큰 수가 `root`자리로 오게된다.
101 | 3-2. 그 후, `root`자리로 온 숫자의 자리로 원래 `root`였던 수가 들어간다.
102 | 3-3. 그리고 제거된다. 103 | 104 | * 풀이. 105 | 1. 왼쪽 `Node`를 변수에 담아준다. 106 | 2. 그 후, 최대한 오른쪽에 있는 `Node`를 찾아야한다. (`node.left.right.right.right`)
107 | 2-1. 그렇기 위해선 `while()`문을 사용한다.
108 | 2-2. 조건 : 오른쪽이 없을 때까지 계속 오른쪽으로 가야한다. ( 한글과 반대로 조건을 걸어준다. : 오른쪽에 `Node`가 있을 때까지 ) 109 | 2-3. 찾은 `Node`를 만든 왼쪽 `Node`변수에 담는다. 110 | 3. 상위 `Node`와 찾은 오른쪽 가장 큰 수 `Node`를 바꿔준다.
111 | 3-1. 중간역할을 위해 바뀔 값(`node.value`)을 변수(`temp`)에 담는다.
112 | 3-2. 바뀔 값과 바꿀 값과 바꾼다. (`node.value = 왼쪽 Node를 담은 변수의 value`) 113 | 3-3. 왼쪽 `Node`를 담은 변수의 `value`값에 변수`temp`을 담는다. 114 | 4. 바꿔줬다면, `node.left`에 담아 재귀함수를 호출한다. 115 | 5. 마지막으로, 부모의 값을 유지해줘야하므로, `node`를 `return`한다. 116 | 117 |
118 | 119 | >__조건 : 제거하려는 값(`value`)과 트리 내부의 존재하는 값(`node.value or root`)이 동일하지 않은 경우__ 120 | 121 | * 지울 값을 찾지 못했을 경우, 좌우 `Node`에게 물어본다. 122 | * 만약, 부모값이 삭제하려는 값보다 작을 때 123 | * 왼쪽 `Node`에 재귀함수를 호출한다. 124 | * 만약, 부모값이 삭제하려는 값보다 클 때 125 | * 오른쪽 `Node`에 재귀함수를 호출한다. 126 | * __마지막으로, 부모의 값을 유지하고 있어야해서 `node`를 `return`한다.__ 127 | 128 |
129 | 130 | >__예외처리 : `null`을 `return`한다.__ 131 | 132 | 1. 찾으려는 숫자가 존재하지 않은 경우 133 | 2. `leaf`일 경우 ( 자식 `Node`가 0개일 경우 or 트리에 `Node`가 하나일 때 삭제하는 경우 ) 134 | 135 |
136 | 137 | >__`return node`가 왜 필요한가 ? 꼭 ! 정리한 이미지, 코드, 트리보고 흐름파악__ 138 | 139 |
140 | 141 | ## 힙 142 | 143 | ![힙트리](/images/heap.png) 144 | 145 |
146 | 147 | ## 우선순위 큐 & 그래프 & 해시테이블 148 | 149 | ![우선순위 큐, 그래프, 해시테이블](/images/etc.png) 150 | 151 | >`keypoint` 152 | 153 | 1. __성능에 따라 시간복잡도가 변한다.__
154 | Hash함수가 얼마나 잘 짜여졌는지(분배해 넣어주는 거)에 따라 각 메소드의 시간복잡도가 O(1), O(logn), O(n)이 될 수도 있다. 155 | 2. 해시함수를 짤 때는 해시함수만 생각하지않고, 데이터의 분포도 잘 파악해야한다.
156 | (데이터칸에 `key`와 `value`가 골고루 분포하도록.) 157 | 3. `key`값과 `capa`값을 나눠서 나머지 값을 구하는 법이 가장 간단한 `hash`함수 구현법이다. 158 | 159 | ## 트리순회 & BFS & DFS 160 | 161 | ![트리순회 & BFS & DFS](/images/tree_traversal.png) -------------------------------------------------------------------------------- /binarySearchTree.js: -------------------------------------------------------------------------------- 1 | export class BinarySearchTree { 2 | root = null; 3 | length = 0; 4 | 5 | #insert(node, value) { 6 | if (node.value > value) { 7 | // 루트노드보다 작은 값이면 8 | if (node.left) { 9 | this.#insert(node.left, value); 10 | } else { 11 | node.left = new Node(value); 12 | } 13 | } else { 14 | // 루트노드보다 큰 값이면 15 | if (node.right) { 16 | this.#insert(node.right, value); 17 | } else { 18 | node.right = new Node(value); 19 | } 20 | } 21 | } 22 | insert(value) { 23 | // 어떤 값을 넣으려할때, 일단 어디에 넣을지 모르겠다. 24 | // 그래서 왼팔, 오른팔한테 맡긴다. 25 | // 근데 만약 왼팔 오른팔이 없으면 거기다가 넣는다. 26 | if (!this.root) { 27 | this.root = new Node(value); 28 | } else { 29 | this.#insert(this.root, value); 30 | } 31 | // 숙제: 이미 넣은 값을 넣은 경우 에러 처리(alert, throw) 32 | } 33 | #search(node, value) { 34 | if (node.value > value) { 35 | // 더 작은값 찾을때 36 | if (!node.left) { 37 | return null; 38 | } 39 | if (node.left.value === value) { 40 | return node.left; 41 | } 42 | return this.#search(node.left, value); 43 | } else { 44 | if (!node.right) { 45 | return null; 46 | } 47 | if (node.right.value === value) { 48 | return node.right; 49 | } 50 | return this.#search(node.right, value); 51 | } 52 | 53 | } 54 | search(value) { 55 | // 어떤 값을 찾으려할때, 일단 어디에 있는지 모르겠다. 56 | // 그래서 왼팔, 오른팔한테 맡긴다. 57 | // 찾으면 그 노드 return, 못찾으면 null return 58 | if (!this.root) { 59 | return null; 60 | } 61 | if (this.root.value === value) { 62 | return this.root; 63 | } 64 | return this.#search(this.root, value); 65 | } 66 | #remove(node, value) { 67 | if (!node) { 68 | // 제거할 값이 bst에 존재하지 않는 경우 69 | return null; // 지울 값이 존재 안 하면 false return 70 | } 71 | if (node.value === value) { // 자식 입장 72 | // 지울 값을 찾은 경우 73 | if (!node.left && !node.right) { 74 | // leaf 75 | return null; 76 | } else if (!node.left) { // 왼팔만 없는 경우 77 | return node.right; 78 | } else if (!node.right) { // 오른팔만 없는 경우 79 | return node.left; 80 | } else { // 양팔 다 있는 경우 81 | let exchange = node.left; 82 | while (exchange.right) { 83 | exchange = exchange.right; 84 | } 85 | const temp = node.value; 86 | node.value = exchange.value; 87 | exchange.value = temp; 88 | node.left = this.#remove(node.left, temp); 89 | return node; 90 | } 91 | } else { // 부모 입장 92 | if (node.value > value) { 93 | node.left = this.#remove(node.left, value) 94 | return node; 95 | } else { 96 | node.right = this.#remove(node.right, value); 97 | return node; 98 | } 99 | } 100 | } 101 | remove(value) { 102 | // 1. leaf(양팔 다 없음) -> 제거 103 | // 2. leaf x, 왼팔이 없다 -> 오른팔 끌어올린다 104 | // 3. leaf x, 오른팔이 없다 -> 왼팔 끌어올린다 105 | // 4. leaf x, 양팔 다 있다 -> 왼팔에서 가장 큰 애와 바꾼다,leaf를 지운다 106 | this.root = this.#remove(this.root, value); 107 | return // 숙제로 length return하게 108 | } 109 | } 110 | class Node { 111 | left = null; 112 | right = null; 113 | constructor(value) { 114 | this.value = value; 115 | } 116 | } 117 | 118 | // const bst = new BinarySearchTree(); 119 | // bst.insert(8); 120 | // bst.insert(10); 121 | // bst.insert(3); 122 | // bst.insert(1); 123 | // bst.insert(14); 124 | // bst.insert(6); 125 | // bst.insert(7); 126 | // bst.insert(4); 127 | // bst.insert(13); 128 | // console.log(bst.search(7)); 129 | // console.log(bst.search(5)); 130 | // bst.remove(8); 131 | // console.log(bst.remove(15)); // false 132 | // bst.remove(4); 133 | // bst; 134 | 135 | // const bst2 = new BinarySearchTree(); 136 | // bst2.insert(50); 137 | // bst2.remove(50); 138 | // bst2.root; // null -------------------------------------------------------------------------------- /deque.js: -------------------------------------------------------------------------------- 1 | class Deque { 2 | arr = []; 3 | 4 | push(value) { 5 | return this.arr.push(value); 6 | } 7 | 8 | pop() { 9 | return this.arr.pop(); 10 | } 11 | 12 | shift() { 13 | return this.arr.shift(); 14 | } 15 | 16 | unshift(value) { 17 | return this.arr.unshift(value); 18 | } 19 | 20 | peek() { 21 | return this.arr.at(0); 22 | } 23 | 24 | get length() { 25 | return this.arr.length; 26 | } 27 | } 28 | 29 | const deque = new Deque(); 30 | deque.push(1); 31 | deque.push(3); 32 | deque.push(5); 33 | deque.unshift(2); 34 | deque.unshift(4); // 5 35 | // 4, 2, 1, 3, 5 36 | console.log(deque.length); // 5 37 | deque.pop(); // 5 38 | deque.shift(); // 4 39 | console.log(deque.peek()); // 2; -------------------------------------------------------------------------------- /graph.js: -------------------------------------------------------------------------------- 1 | class Graph { 2 | vertices = []; 3 | matrix = []; 4 | 5 | insertVertex(name) { 6 | // name 겹치는지 중복검사 7 | this.vertices.push(new Vertex(name)); 8 | this.matrix.push([]); 9 | } 10 | #searchVertex(name) { 11 | for (let i = 0; i < this.vertices.length; i++) { 12 | if (this.vertices[i].name === name) { 13 | return i; 14 | } 15 | } 16 | return null; 17 | } 18 | insertArc(from, to, value, capacity) { 19 | const fromV = this.#searchVertex(from); 20 | const toV = this.#searchVertex(to); 21 | if (fromV === null || toV === null) { 22 | throw '찾는 버텍스가 없습니다.'; 23 | } 24 | this.matrix[fromV][toV] = new Arc(value, capacity); 25 | } 26 | } 27 | class Vertex { 28 | constructor(name) { 29 | this.name = name; 30 | } 31 | } 32 | class Arc { 33 | constructor(value, capacity) { 34 | this.value = value; 35 | this.capacity = capacity; 36 | } 37 | } 38 | 39 | const g = new Graph(); 40 | g.insertVertex('a'); 41 | g.insertVertex('b'); 42 | g.insertVertex('c'); 43 | g.insertArc('a', 'b', 3); 44 | g.insertArc('a', 'c', 2); 45 | g.insertArc('c', 'a', 4); 46 | g.insertArc('b', 'c', 1); 47 | g; -------------------------------------------------------------------------------- /hashtable.js: -------------------------------------------------------------------------------- 1 | class Hashtable { 2 | data = []; // capa로 제한 3 | constructor(capa) { // 공간복잡도(O(N)) 4 | this.capa = capa; 5 | } 6 | insert(key, value) { // 시간복잡도(O(1)) 7 | const hash = hashF(key, this.capa); 8 | if (!this.data[hash]) { 9 | this.data[hash] = []; 10 | } 11 | this.data[hash].push({ key, value }); 12 | } 13 | search(key) { // 시간복잡도 O(N/hash) 14 | const hash = hashF(key, this.capa); 15 | if (this.data[hash]) { 16 | for (let i = 0; i < this.data[hash].length; i++) { 17 | if (this.data[hash][i].key === key) { 18 | return this.data[hash][i].value; 19 | } 20 | } 21 | } 22 | return null; 23 | } 24 | update(key, value) { // 시간복잡도 O(N/hash) 25 | const hash = hashF(key, this.capa); 26 | if (this.data[hash]) { 27 | for (let i = 0; i < this.data[hash].length; i++) { 28 | if (this.data[hash][i].key === key) { 29 | this.data[hash][i].value = value; 30 | } 31 | } 32 | } 33 | } 34 | delete(key) { // 시간복잡도 O(N/hash) 35 | const hash = hashF(key, this.capa); 36 | if (this.data[hash]) { 37 | for (let i = 0; i < this.data[hash].length; i++) { 38 | if (this.data[hash][i].key === key) { 39 | this.data[hash].splice(i, 1); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | function hashF(key, mod) { 46 | if (typeof key === 'string') { 47 | return key.split('').reduce((a, c) => a + c.charCodeAt(), 0) % mod 48 | // ['a', 'b', 'c'] -> [97, 98, 99] -> 294 -> 24 49 | } 50 | if (typeof key === 'number') { 51 | return key % mod; 52 | } 53 | } 54 | 55 | const ht = new Hashtable(30); 56 | ht.insert('abc', 'hello') 57 | ht.insert(31, 'hello') 58 | ht.insert(61, 'bye'); 59 | ht.insert(83, true); 60 | ht.insert(115, 135); 61 | console.log(ht.search(61)); // 'bye' 62 | console.log(ht.search(99)); // null 63 | ht.update(83, false); 64 | ht.delete(31); 65 | ht; 66 | 67 | 68 | 1, 2, 3 69 | 31, 32, 33 70 | 61, 62, 63 71 | 91, 92, 93 -------------------------------------------------------------------------------- /heap.js: -------------------------------------------------------------------------------- 1 | class MaxHeap { // 최대힙 2 | arr = [] 3 | 4 | #reheapUp(index) { 5 | if (index > 0) { 6 | const parentIndex = Math.floor((index - 1) / 2); 7 | if (this.arr[index] > this.arr[parentIndex]) { 8 | // 값 바꾸기 9 | const temp = this.arr[index]; 10 | this.arr[index] = this.arr[parentIndex]; 11 | this.arr[parentIndex] = temp; 12 | this.#reheapUp(parentIndex); 13 | } 14 | } 15 | } 16 | insert(value) { 17 | const index = this.arr.length; 18 | this.arr[index] = value; 19 | this.#reheapUp(index); 20 | } 21 | #reheapDown(index) { 22 | const leftIndex = index * 2 + 1; 23 | if (leftIndex < this.arr.length) { 24 | const rightIndex = index * 2 + 2; 25 | const bigger = this.arr[leftIndex] > this.arr[rightIndex] ? leftIndex : rightIndex; 26 | if (this.arr[index] < this.arr[bigger]) { 27 | const temp = this.arr[index]; 28 | this.arr[index] = this.arr[bigger]; 29 | this.arr[bigger] = temp; 30 | this.#reheapDown(bigger); 31 | } 32 | } 33 | } 34 | remove() { // 루트 삭제 35 | if (this.arr.length === 0) { 36 | return false; 37 | } 38 | if (this.arr.length === 1) { 39 | return this.arr.pop(); 40 | } 41 | const root = this.arr[0]; 42 | this.arr[0] = this.arr.pop(); 43 | this.#reheapDown(0); 44 | return root; 45 | } 46 | sort() { // 힙 정렬 47 | const sortedArray = []; 48 | while (this.arr.length > 0) { 49 | sortedArray.push(this.remove()); 50 | } 51 | return sortedArray; 52 | } 53 | search(value) { 54 | for (let i = 0; i < this.arr.length; i++) { 55 | if (this.arr[i] === value) { 56 | return i; 57 | } 58 | } 59 | return null; 60 | } 61 | update(value, newValue) { 62 | const index = this.search(value); 63 | if (index === null) { 64 | return false; 65 | } 66 | this.arr[index] = newValue; 67 | for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // O(1/2n) 68 | this.#heapify(i); // O(1) 69 | } 70 | } 71 | removeValue(value) { // 특정 값 삭제 72 | const index = this.search(value); 73 | if (index === null) { 74 | return false; 75 | } 76 | this.arr.splice(index, 1); 77 | for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // O(1/2n) 78 | this.#heapify(i); // O(1) 79 | } 80 | } 81 | #heapify(index) { 82 | const leftIndex = index * 2 + 1; 83 | const rightIndex = index * 2 + 2; 84 | const bigger = (this.arr[leftIndex] || 0) > (this.arr[rightIndex] || 0) 85 | ? leftIndex : rightIndex; 86 | console.log(index, this.arr[index], this.arr[bigger]); 87 | if (this.arr[index] < this.arr[bigger]) { 88 | const temp = this.arr[index]; 89 | this.arr[index] = this.arr[bigger]; 90 | this.arr[bigger] = temp; 91 | this.#heapify(bigger); 92 | } 93 | } 94 | } 95 | 96 | const heap = new MaxHeap(); 97 | heap.insert(8); 98 | heap.insert(19); 99 | heap.insert(23); 100 | heap.insert(32); 101 | heap.insert(45); 102 | heap.insert(56); 103 | heap.insert(78); 104 | heap.removeValue(32); 105 | heap; 106 | -------------------------------------------------------------------------------- /images/Time_complexity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/Time_complexity.png -------------------------------------------------------------------------------- /images/binarysearchtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/binarysearchtree.png -------------------------------------------------------------------------------- /images/binarysearchtree_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/binarysearchtree_img.png -------------------------------------------------------------------------------- /images/etc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/etc.png -------------------------------------------------------------------------------- /images/heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/heap.png -------------------------------------------------------------------------------- /images/linkedlist.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/linkedlist.png -------------------------------------------------------------------------------- /images/stack_queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/stack_queue.png -------------------------------------------------------------------------------- /images/tree_traversal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/tree_traversal.png -------------------------------------------------------------------------------- /images/treeandbinarytree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ZeroCho/cs-datastructure/7feb3036486097a465ea4c6fc4b8609ecb2e61e6/images/treeandbinarytree.png -------------------------------------------------------------------------------- /linkedList.js: -------------------------------------------------------------------------------- 1 | class LinkedList { 2 | length = 0; 3 | head = null; 4 | 5 | add(value) { 6 | if (this.head) { 7 | let current = this.head; 8 | while (current.next) { 9 | current = current.next; 10 | } 11 | current.next = new Node(value); 12 | } else { 13 | this.head = new Node(value); 14 | } 15 | this.length++; 16 | return this.length; 17 | } 18 | search(index) { 19 | return this.#search(index)[1]?.value; 20 | } 21 | #search(index) { 22 | let count = 0; 23 | let prev; 24 | let current = this.head; 25 | while (count < index) { 26 | prev = current; 27 | current = current?.next; 28 | count++; 29 | } 30 | return [prev, current]; 31 | } 32 | remove(index) { 33 | const [prev, current] = this.#search(index); 34 | if (prev && current) { 35 | prev.next = current.next; 36 | this.length--; 37 | return this.length; 38 | } else if (current) { 39 | // index가 0일 때 40 | this.head = current.next; 41 | this.length--; 42 | return this.length; 43 | } 44 | // 삭제하고자 하는 대상이 없을 때 45 | // 아무것도 안 함 46 | } 47 | } 48 | class Node { 49 | next = null; 50 | constructor(value) { 51 | this.value = value; 52 | } 53 | } 54 | 55 | const ll = new LinkedList(); 56 | ll.length; 57 | ll.add(1); // 1 58 | ll.add(2); // 2 59 | ll.add(3); // 3 60 | ll.add(4); // 4 61 | ll.add(5); // 5 62 | ll.add(6); // 6 63 | ll.search(6); // undefined 64 | ll.remove(4); 65 | ll.search(4); // 6; 66 | ll.remove(4); 67 | ll.search(4); // undefined 68 | ll.remove(4); // undefined 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } -------------------------------------------------------------------------------- /priorityQueue.js: -------------------------------------------------------------------------------- 1 | class PriorityQueue { // 우선순위큐 2 | arr = [] 3 | 4 | #reheapUp(index) { 5 | if (index > 0) { 6 | const parentIndex = Math.floor((index - 1) / 2); 7 | if (this.arr[index].priority > this.arr[parentIndex].priority) { 8 | // 값 바꾸기 9 | const temp = this.arr[index]; 10 | this.arr[index] = this.arr[parentIndex]; 11 | this.arr[parentIndex] = temp; 12 | this.#reheapUp(parentIndex); 13 | } 14 | } 15 | } 16 | insert(priority, value) { 17 | const index = this.arr.length; 18 | this.arr[index] = { 19 | priority, value, 20 | }; 21 | this.#reheapUp(index); 22 | } 23 | #reheapDown(index) { 24 | const leftIndex = index * 2 + 1; 25 | if (leftIndex < this.arr.length) { 26 | const rightIndex = index * 2 + 2; 27 | const bigger = this.arr[leftIndex].priority > this.arr[rightIndex]?.priority ? leftIndex : rightIndex; 28 | if (this.arr[index]?.priority < this.arr[bigger]?.priority) { 29 | const temp = this.arr[index]; 30 | this.arr[index] = this.arr[bigger]; 31 | this.arr[bigger] = temp; 32 | this.#reheapDown(bigger); 33 | } 34 | } 35 | } 36 | remove() { // 루트 삭제 37 | if (this.arr.length === 0) { 38 | return false; 39 | } 40 | if (this.arr.length === 1) { 41 | return this.arr.pop(); 42 | } 43 | const root = this.arr[0]; 44 | this.arr[0] = this.arr.pop(); 45 | this.#reheapDown(0); 46 | return root; 47 | } 48 | sort() { // 힙 정렬 49 | const sortedArray = []; 50 | while (this.arr.length > 0) { 51 | sortedArray.push(this.remove()); 52 | } 53 | return sortedArray; 54 | } 55 | search(value) { 56 | for (let i = 0; i < this.arr.length; i++) { 57 | if (this.arr[i].value === value) { 58 | return i; 59 | } 60 | } 61 | return null; 62 | } 63 | update(value, newValue) { 64 | const index = this.search(value); 65 | if (index === null) { 66 | return false; 67 | } 68 | this.arr[index].value = newValue; 69 | for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // O(1/2n) 70 | this.#heapify(i); // O(1) 71 | } 72 | } 73 | removeValue(value) { // 특정 값 삭제 74 | const index = this.search(value); 75 | if (index === null) { 76 | return false; 77 | } 78 | this.arr.splice(index, 1); 79 | for (let i = Math.floor(this.arr.length / 2 - 1); i >= 0; i--) { // O(1/2n) 80 | this.#heapify(i); // O(1) 81 | } 82 | } 83 | #heapify(index) { 84 | const leftIndex = index * 2 + 1; 85 | const rightIndex = index * 2 + 2; 86 | const bigger = (this.arr[leftIndex]?.priority || 0) > (this.arr[rightIndex]?.priority || 0) 87 | ? leftIndex : rightIndex; 88 | console.log(index, this.arr[index], this.arr[bigger]); 89 | if (this.arr[index]?.priority < this.arr[bigger]?.priority) { 90 | const temp = this.arr[index]; 91 | this.arr[index] = this.arr[bigger]; 92 | this.arr[bigger] = temp; 93 | } 94 | } 95 | } 96 | 97 | const pq = new PriorityQueue(); 98 | pq.insert(6, 'one'); 99 | pq.insert(5, 'two'); 100 | pq.insert(4, 'three'); 101 | pq.insert(3, 'four'); 102 | pq.insert(2, 'five'); 103 | pq.insert(1, 'six'); 104 | pq.insert(10000, 'king'); 105 | console.log(pq.remove()); // 'king' 106 | pq; -------------------------------------------------------------------------------- /queue.js: -------------------------------------------------------------------------------- 1 | export class Queue { 2 | arr = []; 3 | 4 | enqueue(value) { 5 | return this.arr.push(value); 6 | } 7 | 8 | dequeue() { 9 | return this.arr.shift(); 10 | } 11 | 12 | peek() { 13 | return this.arr[0]; 14 | } 15 | 16 | get length() { 17 | return this.arr.length; 18 | } 19 | } 20 | 21 | // const queue = new Queue(); 22 | // queue.enqueue(1); 23 | // queue.enqueue(3); 24 | // queue.enqueue(5); 25 | // queue.enqueue(2); 26 | // queue.enqueue(4); // 5 27 | // console.log(queue.length); // 5 28 | // queue.dequeue(); // 1 29 | // console.log(queue.peek()); // 3; -------------------------------------------------------------------------------- /stack.js: -------------------------------------------------------------------------------- 1 | export class Stack { 2 | arr = []; 3 | 4 | push(value) { 5 | return this.arr.push(value); 6 | } 7 | 8 | pop() { 9 | return this.arr.pop(); 10 | } 11 | 12 | top() { 13 | return this.arr.at(-1); 14 | } 15 | 16 | get length() { 17 | return this.arr.length; 18 | } 19 | } 20 | 21 | // const stack = new Stack(); 22 | // stack.push(1); 23 | // stack.push(3); 24 | // stack.push(5); 25 | // stack.push(2); 26 | // stack.push(4); // 5 27 | // console.log(stack.length); // 5 28 | // stack.pop(); // 4 29 | // console.log(stack.top()); // 2; -------------------------------------------------------------------------------- /test.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /traversal.js: -------------------------------------------------------------------------------- 1 | import { BinarySearchTree } from './binarySearchTree.js'; 2 | import { Queue } from './queue.js'; 3 | import { Stack } from './stack.js'; 4 | 5 | function bfs(tree) { 6 | const queue = new Queue(); 7 | queue.enqueue(tree.root); 8 | while (queue.length > 0) { 9 | const node = queue.dequeue(); 10 | console.log(node.value); 11 | if (node.left) { 12 | queue.enqueue(node.left); 13 | } 14 | if (node.right) { 15 | queue.enqueue(node.right); 16 | } 17 | } 18 | } 19 | 20 | function dfs(tree) { 21 | const stack = new Stack(); 22 | stack.push(tree.root); 23 | while (stack.length > 0) { 24 | const node = stack.pop(); 25 | console.log(node.value); 26 | if (node.right) { 27 | stack.push(node.right); 28 | } 29 | if (node.left) { 30 | stack.push(node.left); 31 | } 32 | } 33 | } 34 | 35 | function preOrder(node) { 36 | if (!node) return; 37 | console.log(node.value); 38 | preOrder(node.left); 39 | preOrder(node.right); 40 | } 41 | 42 | function inOrder(node) { 43 | if (!node) return; 44 | inOrder(node.left); 45 | console.log(node.value); 46 | inOrder(node.right); 47 | } 48 | 49 | function postOrder(node) { 50 | if (!node) return; 51 | postOrder(node.left); 52 | postOrder(node.right); 53 | console.log(node.value); 54 | } 55 | 56 | const bst = new BinarySearchTree(); 57 | bst.insert(4) 58 | bst.insert(2) 59 | bst.insert(6) 60 | bst.insert(1) 61 | bst.insert(3) 62 | bst.insert(5) 63 | bst.insert(7) 64 | // bfs(bst); 65 | // dfs(bst); 66 | // preOrder(bst.root); 67 | // inOrder(bst.root); 68 | postOrder(bst.root); -------------------------------------------------------------------------------- /tree.js: -------------------------------------------------------------------------------- 1 | class Tree { 2 | constructor(value) { 3 | this.root = new Node(value); 4 | } 5 | } 6 | 7 | class Node { 8 | children = []; 9 | constructor(value) { 10 | this.value = value; 11 | } 12 | 13 | push(value) { 14 | this.children.push(new Node(value)); 15 | } 16 | } 17 | 18 | const tree = new Tree(50); 19 | tree.root.push(25); 20 | tree.root.push(75); 21 | tree.root.children[0].push(12) 22 | tree.root.children[0].push(37) 23 | tree.root.children[1].push(62) 24 | tree.root.children[1].push(87) --------------------------------------------------------------------------------