├── .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 | 
8 |
9 | ## 연결리스트
10 |
11 | 
12 |
13 | ## 스택과 큐
14 |
15 | 
16 |
17 | ## 트리와 이진트리 종류
18 |
19 | 
20 |
21 | ## __⭐️이진탐색트리⭐️ : 재귀함수, 주석, 트리, 코드를 보면서 흐름을 파악해야한다.__
22 |
23 | 
24 |
25 | ---
26 | 
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 | 
144 |
145 |
146 |
147 | ## 우선순위 큐 & 그래프 & 해시테이블
148 |
149 | 
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 | 
--------------------------------------------------------------------------------
/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)
--------------------------------------------------------------------------------