├── Algorithm
├── DP, 분할 정복, 그리디.md
├── Divide & Conquer.md
├── Graph.md
├── Readme.md
├── Sorting.md
└── 완전탐색, 재귀.md
├── Data Structure
├── Array.md
├── Graph.md
├── Hash.md
├── Readme.md
├── Stack, Queue.md
└── Tree & Heap.md
├── Database
├── Clustering, Replication.md
├── Database, key.md
├── Index.md
├── Normalization.md
├── Partitioning & Sharding.md
├── Readme.md
└── sql query.md
├── Java
├── AccessModifier.md
├── CollectionFramework.md
├── Error & Exception.md
├── GC.md
├── Generic.md
├── JDK8.MD
├── JVM.md
├── Modifier.md
├── OOP.md
├── Readme.md
├── Synchronization.md
└── Wrapper.md
├── Network
├── ApplicationLayer.md
├── Cookie, Session, OAuth, JWT.md
├── HTTP,HTTPS.md
├── Internet Layer (Network Layer).md
├── Network Access Layer (Physical & Data).md
├── PresentationLayer.md
├── REST API.md
├── Readme.md
├── SessionLayer.md
├── TCP, UDP.md
├── TransportLayer.md
├── 웹 접속 과정.md
└── 웹서버, WAS.md
├── Operating System
├── CPU Sheduling.md
├── Cache Memory & Memory Layered.md
├── Context Switching & PCB.md
├── Critical Section.md
├── Deadlock.md
├── File System.md
├── Interrupt.md
├── Page Replacement Algorithm.md
├── Paging & Segmentation.md
├── Process.md
├── Readme.md
├── Synchronous & Asynchronous & blocking & nonblocking.md
├── TLB, MMU.md
└── Virtual Memory.md
└── README.md
/Algorithm/DP, 분할 정복, 그리디.md:
--------------------------------------------------------------------------------
1 | # DP
2 | - DP란 **복잡한 문제를 간단한 여러 개의 문제로 나누어 푸는 방법**을 말합니다. DP에서는 2가지 조건을 충족해야 만 사용이 가능합니다.
3 | 1. **부분 반복 문제**(Overlapping Subproblem)
4 | - 어떤 문제가 여러 개의 부분 문제로 쪼개질 수 있는 경우를 말합니다.
5 | 2. **최적 부분 구조**(Optimal Substructure)
6 | - 작은 부분 문제에서 구한 최적의 답으로 큰 문제를 해결할 수 있는 경우를 말합니다.
7 |
8 | 이때, 분할 정복과의 가장 큰 차이는 **분할 정복법은 작은 문제의 답이 달라질 수 있지만, DP는 그렇지 않다는 것**입니다.
9 |
10 | - DP를 구현 할 때에는 **Memoization**과 **Tabulation**을 사용해서 구현이 가능합니다.
11 | 1. **Memoization**
12 | -
13 |
14 | - 재귀를 이용해서 문제를 해결 할 경우에 사용하는 테이블, **Top-Bottom** 으로 해결 할 경우 사용
15 | 2. **Tabulation**
16 |
17 | 
18 | - 반복문을 이용해서 문제를 해결 할 경우에 사용하는 테이블, **Bottom-Up**으로 해결 할 경우 사용
19 |
20 | #### Q) DP의 2가지 조건에 대해서 설명해주세요.
21 | - 어떤 문제가 여러 개의 부분 문제로 쪼개질 수 있는 경우인 **부분 반복 문제**를 충족해야 하고, 작은 부분 문제에서 구한 최적의 답으로 큰 문제를 해결할 수 있다는 **최적 부분 구조** 를 충족해야 합니다.
22 |
23 | #### Q) Top-Bottom 방식과 Bottom-Up 방식의 장단점에 대해서 설명해주세요.
24 | - **Top-Bottom**
25 | **[장점]** : 재귀를 이용한 방식이기 때문에 **가독성이 좋고, 서브 문제를 해결 할 경우 필요한 서브 문제들만 해결해도 된다는 장점**이 있습니다.
26 | **[단점]** : 결과가 어떻게 나오는지 알고 있어야 하며, **저수준으로 갈 수록 복잡해질 수 있으며, 리소스의 사용이 많아질수 있다**는 문제가 있습니다.
27 |
28 | - **Bottom-UP**
29 | **[장점]** : **처리 시간과 리소스 사용을 줄일 수 있고, 점화식을 찾은 경우에 점화식을 이용하여 문제를 해결 할 수 있다는 장점**이 있습니다.
30 | **[단점]** : 반복문으로 진행하다보니 **재귀 방식에 비해서 구현이 복잡** 할 수 있으며, Top-Bottom은 대 문제를 해결하기 위해 필요한 소 문제에 대해서만 구현을 하면 되지만 Bottom-Up 방식은 **처음부터 해결해야 하는 대문제까지의 모든 경우를 구해야 한다**는 단점이 있습니다.
31 |
32 | ---
33 | # Divide & Conquer (분할 정복)
34 | * 문제를 나눌 수 없을 때까지 나누어서 각각을 풀면서 다시 합병하여 문제의 답을 얻는 알고리즘입니다.
35 | - **하향식 접근법** 으로, 상위의 해답을 구하기 위해, 아래로 내려가면서 (top-down) 하위의 해답을 구하는 방식으로 수행됩니다.
36 | - 일반적으로 재귀함수로 구현합니다.
37 | > **divide-and-conquer의 핵심은 재귀호출입니다.**
38 | - Divide & Conquer은 `top-down` 접근 방식을 사용합니다.
39 | - 이때 문제를 잘게 쪼갤 때, 부분 문제는 서로 중복되지 않습니다. top-down이란, 처음부터 큰 문제를 방문 후 작은 문제를 호출, 재귀(recursive)방식을 사용합니다.
40 | (ex) 병합 정렬, 퀵 정렬 등
41 |
42 | #### 분할 정복 용어
43 | - Divide : 문제를 더 작은 문제로 분할하는 과정
44 | - Merge : 각 문제에 대해 구한 답을 원래 문제에 대한 답으로 병합하는 과정(merge)
45 | - Base case : 더 이상 답을 분할하지 않고 곧장 풀 수 있는 매우 작은 문제
46 |
47 | ### Q) 분할정복의 장단점을 설명해주세요
48 | - 장점 : 큰 문제를 재귀적으로 나누어 해결하기에 간단하지만 빠르며 병렬적으로 문제를 해결할 수 있다는 장점이 있습니다.
49 | - 단점 : 재귀적으로 문제를 해결하기 때문에 인풋이 너무 큰 경우 많은 프로그래밍 언어에서 Stack Overflow가 발생할 수 있으며, 이는 메모리의 비효율적 사용을 야기할 수 있습니다.
50 |
51 | ### Q) DP와 분할 정복의 공통점과 차이점을 설명해주세요
52 |
53 | **DP와 분할 정복의 공통점**
54 | - 문제를 잘게 쪼개서, 가장 작은 단위로 분할한다는 것입니다.
55 |
56 | **DP와 분할 정복의 차이점**
57 |
58 | 1) **동적 계획법**
59 | - DP의 부분 문제는 중복되기에 상위 문제 해결 시 재활용됩니다. 따라서 DP는 서로 상관관계가 있는 문제를 해결하는데에 적합합니다.
60 | - Memoization 기법을 사용합니다.(부분 문제의 해답을 저장해서 재활용하는 최적화 기법으로 사용)
61 |
62 | 2) **분할 정복**
63 | - 분할정복의 부분 문제는 서로 중복되지 않습니다. 따라서 분할정복은 서로 상관관계가 없는, 쪼개진 결과가 서로 독립적인 성격의 문제를 해결하는데 적합합니다.
64 | - Memoization 기법을 사용하지 않습니다.
65 |
66 | ---
67 |
68 | # Greedy
69 | - 그리디란 **미래를 생각하지 않고 현재 단계에서 가장 최선의 선택을 하는 기법**입니다 . 순간마다 하는 선택은 그 순간에 대해 지역적으로 최적이지만, 모았을 때 그것이 **최적의 해라는 보장은 없습니다.**
70 | - 그리디로 해결이 안되는 상황을 예시로 설명해보겠습니다. 지금 선택하면 1개의 쿠키를 받고, 1분 기다렸다 선택하면 2개의 쿠키를 받는 문제 가 있을 때 지금 **당장 최선의 선택은 쿠키 1개**를 받는 거지만, **결과적으로는** 1분 기다렸다가 **2개 받는 선택이 최선**입니다.
71 |
72 | ### Q) 그리디와 DP의 차이점에 대해 말씀해주세요.
73 | 문제를 작은 문제로 분할하여 해결하거나, 부분 문제의 최적해를 활용해 전체 문제의 최적해를 구한다는 문제 해결 방식은 동일합니다.
74 | 하지만 그리디는 **각 단계에서 최선의 선택을 하기 때문에 현재 선택이 나중에 영향을 끼친다**면 이는 최적의 해를 보장할 수 없습니다. 따라 이런 경우에는 **DP**, 영향을 끼치지** 않을 때 그리디**를 사용합니다.
75 |
76 | ### Q) 속도 측면에서는 뭐가 더 우세할까요?
77 | **그리디 알고리즘**입니다.
78 | **동적 프로그래밍 알고리즘**은 중복 계산을 피하고 전역적인 최적해를 보장하기는 하지만, **메모리 공간을 많이 사용**하고, 부분 문제들의 결과를 계산하고 저장하는 과정이 복잡하기 때문에 일반적으로 **그리디 알고리즘보다 더 높은 시간복잡도**를 가질 수 있습니다.
79 |
80 | ---
81 |
82 |
83 |
84 |
85 | ### 참고
86 | DP
87 | [이미지 출처](https://nulls.co.kr/codeit/392)
88 |
89 |
90 | 분할정복
91 | [이미지&내용 출처](https://syujisu.tistory.com/entry/%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95-Dynamic-Programming%EA%B3%BC-%EB%B6%84%ED%95%A0-%EC%A0%95%EB%B3%B5-Divide-and-Conquer-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98)
92 |
93 | [이미지&내용 출처](https://korguy.tistory.com/entry/%EB%B0%A9%EB%B2%95%EB%A1%A0-Divide-and-Conquer-%EB%B6%84%ED%95%A0%EC%A0%95%EB%B3%B5)
94 |
95 | 그리디
96 | [이미지 출처](https://github.com/JaeYeopHan/Interview_Question_for_Beginner/tree/master/Algorithm)
97 |
--------------------------------------------------------------------------------
/Algorithm/Divide & Conquer.md:
--------------------------------------------------------------------------------
1 | # Divide & Conquer (분할 정복)
2 | * 문제를 나눌 수 없을 때까지 나누어서 각각을 풀면서 다시 합병하여 문제의 답을 얻는 알고리즘입니다.
3 | - **하향식 접근법** 으로, 상위의 해답을 구하기 위해, 아래로 내려가면서 (top-down) 하위의 해답을 구하는 방식으로 수행됩니다.
4 | - 일반적으로 재귀함수로 구현합니다.
5 | > **divide-and-conquer의 핵심은 재귀호출입니다.**
6 | - Divide & Conquer은 `top-down` 접근 방식을 사용합니다.
7 | - 이때 문제를 잘게 쪼갤 때, 부분 문제는 서로 중복되지 않습니다. top-down이란, 처음부터 큰 문제를 방문 후 작은 문제를 호출, 재귀(recursive)방식을 사용합니다.
8 | (ex) 병합 정렬, 퀵 정렬 등
9 |
10 | #### 분할 정복 용어
11 | - Divide : 문제를 더 작은 문제로 분할하는 과정
12 | - Merge : 각 문제에 대해 구한 답을 원래 문제에 대한 답으로 병합하는 과정(merge)
13 | - Base case : 더 이상 답을 분할하지 않고 곧장 풀 수 있는 매우 작은 문제
14 |
15 | ### Q) 분할정복의 장단점을 설명해주세요
16 | - 장점 : 큰 문제를 재귀적으로 나누어 해결하기에 간단하지만 빠르며 병렬적으로 문제를 해결할 수 있다는 장점이 있습니다.
17 | - 단점 : 재귀적으로 문제를 해결하기 때문에 인풋이 너무 큰 경우 많은 프로그래밍 언어에서 Stack Overflow가 발생할 수 있으며, 이는 메모리의 비효율적 사용을 야기할 수 있습니다.
18 |
19 | ### Q) DP와 분할 정복의 공통점과 차이점을 설명해주세요
20 |
21 | **DP와 분할 정복의 공통점**
22 | - 문제를 잘게 쪼개서, 가장 작은 단위로 분할한다는 것입니다.
23 |
24 | **DP와 분할 정복의 차이점**
25 |
26 | 1) **동적 계획법**
27 | - DP의 부분 문제는 중복되기에 상위 문제 해결 시 재활용됩니다. 따라서 DP는 서로 상관관계가 있는 문제를 해결하는데에 적합합니다.
28 | - Memoization 기법을 사용합니다.(부분 문제의 해답을 저장해서 재활용하는 최적화 기법으로 사용)
29 |
30 | 2) **분할 정복**
31 | - 분할정복의 부분 문제는 서로 중복되지 않습니다. 따라서 분할정복은 서로 상관관계가 없는, 쪼개진 결과가 서로 독립적인 성격의 문제를 해결하는데 적합합니다.
32 | - Memoization 기법을 사용하지 않습니다.
33 |
34 | #### 사진 & 내용 출처
35 |
36 | https://syujisu.tistory.com/entry/%EB%8F%99%EC%A0%81-%EA%B3%84%ED%9A%8D%EB%B2%95-Dynamic-Programming%EA%B3%BC-%EB%B6%84%ED%95%A0-%EC%A0%95%EB%B3%B5-Divide-and-Conquer-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98
37 |
38 | https://korguy.tistory.com/entry/%EB%B0%A9%EB%B2%95%EB%A1%A0-Divide-and-Conquer-%EB%B6%84%ED%95%A0%EC%A0%95%EB%B3%B5
39 |
40 |
--------------------------------------------------------------------------------
/Algorithm/Readme.md:
--------------------------------------------------------------------------------
1 | ### 알고리즘
2 |
--------------------------------------------------------------------------------
/Algorithm/완전탐색, 재귀.md:
--------------------------------------------------------------------------------
1 | # 완전탐색
2 | 가능한 모든 경우를 탐색하는 기법입니다. 완전탐색 기법 중 하나인 백트래킹과 DFS를 예시로 설명해보겠습니다.
3 |
4 | ### 백트레킹(backtracking)
5 | - 답을 찾아가다 불필요한 경우 (즉 답이 나올 수 없는 경우)에 그 경로를 탐색하지 않고 되돌아가는 방식을 말합니다. 불필요한 부분을 쳐낸다는 점에서 가지치기라고도 표현할 수 있습니다.
6 | - 주로 DFS로 모든 경우를 탐색하는 과정에서, 조건문을 걸어 답이 될 수 없는 상황엔 탐색을 중지하는 하도록 구현할 수 있습니다.
7 |
8 | ### Q) 완전탐색을 구현하는 방식을 재귀로도 구현할 수 있는데, 재귀에 대해 설명해주세요.
9 | - 함수가 자기 자신을 호출하는 것을 의미합니다. 즉, 함수가 실행 도중에 자기 자신을 호출하여 문제를 해결하는 방식입니다.
10 |
11 | ### Q-1) 재귀함수를 구현할 때 필수조건에 대해 설명해주세요.
12 | 값을 찾을 때, 중단 조건을 명시해줘야 합니다. 중단 조건이 충족되면 재귀가 종료되고, 함수가 호출된 순서대로 결과를 반환하여 문제를 해결합니다
13 |
14 | ### Q) 완전탐색의 재귀와 DP는 큰 문제를 잘게 쪼갠다는 공통점이 있는데, 차이점은 뭘까요?
15 | - 메모이제이션 입니다.
16 | - 완전탐색은 중복된 부분 문제를 다시 계산합니다. 즉, 같은 부분 문제를 여러 번 해결하게 될 수 있습니다.
17 | - 반면에 DP는 중복된 부분 문제를 한 번만 계산하고 그 결과를 메모이제이션(Memoization)이나 테이블에 저장하여 재활용합니다. 이를 통해 계산의 중복을 피하고 실행 시간을 줄일 수 있습니다.
18 |
19 | ### Q) 완전탐색을 하게 되는 경우 여러 조건이 있는데 중복이 존재 여부/ 순서 존재 여부 의 4가지 경우의 시간복잡도에 대해 설명해주세요.
20 | > 💡 Hint! 순열, 조합, 중복순열, 중복조합
21 | 완전탐색 최악 시간 복잡도 O(N^M)
22 |
23 |
24 |
25 | **1. 순열 : 순서O, 중복X**
26 | - 서로 다른 n개에서 r개를 뽑아서 정렬하는 경우의 수
27 | - 중첩된 반복문을 사용하여 가능한 모든 순열을 생성하므로, 시간복잡도가 매우 크게 증가
28 | - 시간복잡도 `O(nPr) = O(n! / (n-r)!)`
29 |
30 |
31 |
32 | 순열 JAVA 코드
33 |
34 |
35 |
36 | ```java
37 | void permutation(int[] arr, int r) {
38 | int[] result = new int[r];
39 | boolean[] used = new boolean[arr.length];
40 | permutationUtil(arr, r, result, used, 0);
41 | }
42 |
43 | void permutationUtil(int[] arr, int r, int[] result, boolean[] used, int depth) {
44 | if (depth == r) {
45 | // 순열 결과 출력 또는 처리
46 | return;
47 | }
48 |
49 | for (int i = 0; i < arr.length; i++) {
50 | if (!used[i]) {
51 | used[i] = true;
52 | result[depth] = arr[i];
53 | permutationUtil(arr, r, result, used, depth + 1);
54 | used[i] = false;
55 | }
56 | }
57 | }
58 | ```
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 | **2. 중복순열 : 순서O, 중복O**
67 | - 서로 다른 n개에서 중복이 가능하게 r개를 뽑아서 정렬하는 경우의 수
68 | - 중첩된 반복문을 사용하여 가능한 모든 순열을 생성하므로, 시간복잡도가 매우 크게 증가
69 | - 시간복잡도 `O(n^r)`
70 |
71 |
72 |
73 | 중복 순열 JAVA 코드
74 |
75 |
76 |
77 | ```java
78 | void duplicatePermutation(int[] arr, int r) {
79 | int[] result = new int[r];
80 | duplicatePermutationUtil(arr, r, result, 0);
81 | }
82 |
83 | void duplicatePermutationUtil(int[] arr, int r, int[] result, int depth) {
84 | if (depth == r) {
85 | // 중복 순열 결과 출력 또는 처리
86 | return;
87 | }
88 |
89 | for (int i = 0; i < arr.length; i++) {
90 | result[depth] = arr[i];
91 | duplicatePermutationUtil(arr, r, result, depth + 1);
92 | }
93 | }
94 | ```
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 | **3. 조합 : 순서X, 중복X**
104 | - 서로 다른 n개에서 순서 없이 r개를 뽑는 경우의 수
105 | - 재귀적으로 모든 조합을 생성하며, 중첩된 반복문을 사용하지 않기 때문에, 시간복잡도가 일반적으로 순열보다 작음
106 | - 시간복잡도 ` O(nCr) = O(n! / ((n-r)! * r!))`
107 |
108 | 조합 JAVA 코드
109 |
110 |
111 |
112 | ```java
113 | void combination(int[] arr, int r) {
114 | int[] result = new int[r];
115 | combinationUtil(arr, r, result, 0, 0);
116 | }
117 |
118 | void combinationUtil(int[] arr, int r, int[] result, int depth, int start) {
119 | if (depth == r) {
120 | // 조합 결과 출력 또는 처리
121 | return;
122 | }
123 |
124 | for (int i = start; i < arr.length; i++) {
125 | result[depth] = arr[i];
126 | combinationUtil(arr, r, result, depth + 1, i + 1);
127 | }
128 | }
129 | ```
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 | **4. 중복조합 : 순서X, 중복O**
139 | - 서로 다른 n개에서 순서 없이, 중복이 가능하게 r개를 뽑는 경우의 수
140 | - 중첩된 반복문을 사용하여 가능한 모든 조합을 생성하므로, 시간복잡도가 중복 순열보다 크게 증가
141 | - 시간복잡도 `O((n+r-1)Cr) = O(((n+r-1)!)/((n-1)! * r!))`
142 |
143 |
144 |
145 | 중복 조합 JAVA 코드
146 |
147 |
148 |
149 | ```java
150 | void duplicateCombination(int[] arr, int r) {
151 | int[] result = new int[r];
152 | duplicateCombinationUtil(arr, r, result, 0, 0);
153 | }
154 |
155 | void duplicateCombinationUtil(int[] arr, int r, int[] result, int depth, int start) {
156 | if (depth == r) {
157 | // 중복 조합 결과 출력 또는 처리
158 | return;
159 | }
160 |
161 | for (int i = start; i < arr.length; i++) {
162 | result[depth] = arr[i];
163 | duplicateCombinationUtil(arr, r, result, depth + 1, i); // 중복이 허용되므로 i+1 대신 i를 전달
164 | }
165 | }
166 | ```
167 |
168 |
169 |
170 |
171 |
--------------------------------------------------------------------------------
/Data Structure/Array.md:
--------------------------------------------------------------------------------
1 | # 배열
2 | 배열이란, **동일한 자료형을 연속된 메모리 공간에 할당**하는 자료구조입니다.
3 | 연속된 공간에 저장되기 때문에, **0부터 시작하는 인덱스**를 통해 **값에 빠르게 접근**할 수 있다는 `O(1)` 장점이 있는 반면,
4 | 값을 **삽입/삭제** 하는 경우, 그 뒤의 **모든 요소들을 shift 하기 때문에 `O(N)` 비효율적**이라는 단점이 있습니다.
5 |
6 | ### Q) 배열과 리스트의 차이점에 대해 설명해주세요.
7 | 배열 : 초기 선언 시 **크기를 선언**하고, 크기 수정이 불가능합니다. (**고정적**)
8 | 리스트 : 초기 선언 시 크기를 **선언할 필요가 없고**, 크기가 **가변적** 입니다.
9 |
10 | ### Q-1) ArrayList와 LinkedList의 차이점
11 | **ArrayList** : **데이터를 연속적으로 저장**하기 때문에
12 | - 접근 `O(1)` : 인덱스를 통해
13 | - 삽입/삭제 `O(N)` : 뒤 shift
14 |
15 | **LinkedList** : **연속적인 공간에 저장하지 않고**, **각 노드가 데이터와 포인터**를 가지고 **포인터를 통해** 이전 노드와 다음 노드를 **연결**하기 때문에
16 | - 접근 `O(N)` : 순차적으로 탐색하며 접근
17 | - 삽입/삭제 `O(1)` : 앞뒤 링크만 변경
18 |
19 | ### Q-2) 배열과 리스트 둘 중 캐시의 지역성을 활용하기 좋은 건 뭘까요? (배열은 연속적으로 저장, 리스트는 불연속적으로 저장)
20 | - 배열입니다. 캐시의 지역성이란, 데이터 접근이 시간적 혹은 공간적으로 가깝게 일어나는 것을 의미합니다. **배열은 연속적으로 값을 저장하기 때문에, 특정 값에 접근하였을 때 주변 값에 빠르게 접근**할 수 있습니다. 이는 캐시의 지역성 중 공간적 지역성이 더 좋다고 표현할 수 있습니다.
21 |
22 | > 시간적 지역성 : 최근에 참조된 주소의 내용은 곧 다음에 다시 참조되는 특성
23 | 반복문 사용 시, 시간적 지역성이 좋다고 할 수 있습니다?
24 |
25 |
26 | ### Q) 배열같은 경우, index로 읽기에 속도가 빠르지만 검색 시 속도가 느립니다. 빠르게 검색할 수 있는 방법이 있을까요?
27 | - 첫번째 답 : 배열의 경우 순차적으로 접근하기 때문에 매번 O(N)의 시간 복잡도가 소요됩니다.
28 | 하지만 **HashMap을 사용하여 값을 저장한다면 O(N)의 시간 복잡도로 저장**하고, 이후에는 매번 **O(1)의 시간으로 값**을 찾을 수 있습니다.
29 |
30 | **Q-1) 배열을 첫번째부터 다 돌면서 HashMap에 저장하면 괜찮을까요?**
31 | - 비효율적
32 |
33 | 답 : **Binary Search** OR **선형 검색**
34 |
35 | ---
36 | > ### 종운님 추가조사👍 이진 탐색은 현업에서 거의 사용하지 않고, Hash 를 사용한다고 합니다.
37 | 이진 탐색을 하게 되면 결국 정렬 과정을 통해 선형 탐색보다 느리게 됩니다. ( 대부분의 데이터들은 정렬되지 않은 상태로 들어오므로 )
38 | 이에 **이진 탐색을 사용하게 되면 선형 탐색보다 빠르다는 보증이 없습니다.**
39 | 데이터 삽입/삭제가 빈번한 실무에서는 추가될 때 마다 정렬하는 과정을 거쳐야 하므로 **이진탐색은 비효율적**입니다.
40 |
41 |
42 |
43 | ---
44 |
45 | 1. Binary Search (이진 탐색 알고리즘) : 원하는 값을 찾고 싶을 때, 정렬된 리스트에서 검색 범위를 줄여 나가며 검색 값을 찾는 알고리즘입니다. - 정렬된 리스트에만 사용할 수 있다는 단점이 있지만, 검색이 반복될 때 마다 검색 범위가 절반으로 줄어들기 때문에 속도가 빠르다는 장점이 있습니다.
46 |
47 | - 사용 방법
48 | - 처음에 N개 크기의 배열에서 단계가 하나씩 지나감에 따라 탐색할 배열의 크기를 반씩 줄입니다.
49 |
50 | - 이진 탐색을 사용하는 경우 시간복잡도
51 | - 정렬되어 있지 않은 상태 : `O(NlogN)` (정렬) , `O(logN)` (값 탐색)
52 | - 정렬된 상태 : `O(logN)`
53 |
54 | 2. 선형 탐색 : 일렬로 된 자료를 왼쪽부터 오른쪽으로 차례대로 탐색하는 것
55 | - 매번 O(N)
56 |
57 | **정리**
58 | - HashMap : O(N) 저장, 이후 O(1)
59 | - Binary Search, 정렬X : O(NlogN) 정렬, 이후 O(logN)
60 | - Binary Search, 정렬O : O(logN)
61 | - 선형검색 : 매번 O(N)
62 |
63 | ### Q) 배열 내의 중복된 값이 존재하는 지 찾는 방법에 대해 설명해주세요.
64 | 요약: 배열은 `O(N^2)`의 시간복잡도가 소요되기 때문에, 중복요소를 저장하지 않는 **HashSet 자료구조를 사용**하여 `O(N)`의 시간복잡도로 값을 저장한 후 **HashSet과 배열의 크기를 비교**하면 됩니다.
65 |
66 | ---
67 |
68 | 배열은 값을 순차적으로 저장하기 때문에, 중복여부를 판단할 수 없습니다. 따라서 2중 반복문을 통해 판단하면 `O(N^2)`의 시간복잡도가 소요됩니다.
69 | ```java
70 | for (int i = 0; i < arr.length; i++) {
71 | for (int j = i + 1; j < arr.length; j++) {
72 | if (arr[i] == arr[j]) {
73 | return true; // 중복 값 발견
74 | }
75 | }
76 | }
77 | ```
78 |
79 | 이를 효율적으로 검색하기 위해, 중복 요소를 허용하지 않는 HashSet 자료구조를 사용하면 됩니다. `O(N)`의 시간복잡도로 배열의 크기인 N만큼 HashSet에 추가한 뒤, HashSet의 크기와 배열의 크기를 비교하여 알아낼 수 있습니다.
80 | - `HashSet.size() == Array.size()` : 중복요소 없다
81 | - `HashSet.size() != Array.size()` : 중복요소 있다
82 | ```java
83 | public static boolean hasDuplicates(int[] arr) {
84 | HashSet set = new HashSet();
85 | for (int i = 0; i < arr.length; i++) {
86 | if (!set.add(arr[i])) {
87 | return true; // 중복 값 발견
88 | }
89 | }
90 | return false; // 중복 값 없음
91 | }
92 | ```
93 |
94 | ### Q) list와 set을 비교해주세요.
95 | 💡 Hint! 중복과 순서 보장
96 | - List : 중복 허용 O, 순서 보장 O
97 | - Set : 중복 허용 X, 순서 보장 X
98 |
99 | ### Q-1) List와 Set을 사용하는 경우에 대해 설명해주세요.
100 | 💡 Hint! A라는 친구가 집단안에 있는 지 확인하고 싶은 경우, 어떤 자료구조를 사용할까요?
101 | - Set 입니다. contains 메소드를 통해 `O(1)`의 시간복잡도로 확인할 수 있습니다.
102 | - list 는 O(n)의 시간 복잡도가 걸리기 때문에, set을 사용하는 것이 효율적입니다.
103 |
104 | ✔️ List : 저장되는 데이터의 순서를 보장해야 할 때
105 | - 대기자 명단을 작성할 때
106 |
107 |
108 |
109 | ✔️ Set : 데이터가 존재하는 지 확인하고 싶을 때
110 | - 연락처 목록을 저장할 때
111 |
112 | ### Q) 배열의 softCopy와 deepCopy 에 대해 설명해주세요.
113 | 요약 : 자바의 객체와 같은 참조 변수는 직접 값을 저장하는 게 아닌 **힙 영역에 데이터를 저장하고 그의 주소값을 저장**하는 식으로 구성되어 있습니다. **softCopy**는 복사한 배열이 원래 배열의 **'주소값'을** 가져오고, **deepCopy는 '데이터'를** 가져옵니다.
114 |
115 | ---
116 |
117 |
118 | 설명을 위해 arr1 과 arr2 배열을 예시로 설명해보겠습니다.
119 | arr1 의 값을 arr2에 복사하고 싶을 때, **`arr2 = arr1`는 softCopy** 입니다. (주소값만 복사, 같은 힙의 데이터를 바라봄)
120 |
121 | - arr2에 arr1의 `O(1)`의 시간복잡도로 모든 값이 복사됩니다. 하지만 이는 **배열의 주소값이 복사된 것으로, 메모리에서 동일한 배열을 참조**합니다. 따라서 **arr1 또는 arr2 의 값을 변경하게 되면, 동시에 변경**됩니다.
122 |
123 | 반면 **`arr2 = arr[1].clone();` 이나 `System.arrayCopy(arr1, 0, arr2, 0, arr1.length)` 는 deepCopy** 입니다. (원본이 참조하고 있는 힙의 데이터까지 복제)
124 |
125 | - 이는 **배열 자체가 완벽하게 새 배열에 복사**됩니다. 전체 요소를 복사하기 때문에 `O(N)`의 시간복잡도가 소요됩니다.
126 |
127 |
128 | > System.arraycopy()
129 | - 배열의 일부분을 다른 배열로 복사할 때 사용
130 |
131 | > clone() 주의 사항
132 |
133 | 1차원 배열, 단일 클래스 타입의 경우, clone()은 완벽히 다른 데이터를 참조합니다.
134 | **하지만 클래스 타입을 여러개 담고 있는 배열**을 복사하는 경우,
135 | - 참조 객체인 배열 자체는 완벽히 복사가 됩니다.
136 | - 하지만 **배열 내용물 객체**는 **얕은 복사**가 됩니다.
137 | - 원본과 복사본의 배열 요소가 담고있는 주소값이 같아 바라보는 힙 데이터가 같습니다.
138 |
139 | 이는 클래스를 복사할 경우, **clone()을 오버라이딩하여 재정의** 해줘야 합니다.
140 |
141 | ### Q) 배열을 정렬하는 경우, 어떤 알고리즘을 사용하는 경우 가장 효율적일까요?
142 | - `O(NlogN)`의 시간복잡도를 가진 병합 정렬, 퀵 정렬을 사용합니다.
143 |
144 | **자바 Arrays.sort()**
145 | - primitive(기본형) 타입의 배열인 경우
146 | - 듀얼피봇 퀵정렬(Dual-Pivot QuickSort)를 사용
147 | - 듀얼피봇 퀵정렬은 일반적인 퀵정렬과는 다르게 피봇을 2개를 두고 3개의 구간을 만들어 퀵정렬을 진행한다고 합니다. 이 정렬방식은 랜덤 데이터에 대해서 평균적으로 퀵소트 보다 좋은 성능을 낸다고 알려져있습니다.
148 |
149 | - reference(참조) 타입의 배열인 경우
150 | - 참조 타입의 배열인 경우는 TimSort를 사용
151 |
152 | **자바 Collections.sort()**
153 | - TimSort 사용
154 | - TimSort : 삽입(Insertion) 정렬과 합병(Merge) 정렬을 결합하여 만든 정렬
155 |
156 | 
157 |
158 | > Arrays를 정렬했을때와 Collections를 정렬했을때 왜 사용하는 알고리즘이 다른걸까요 ?
159 | (출처 : https://sabarada.tistory.com/138)
160 | 그 이유는 바로 참조 지역성 원리(Local of Reference)에 있습니다. 참조 지역성의 원리란 동일한 값 또는 해당 값의 근처에 있는 스토리지 위치가 자주 액세스되는 특성을 말합니다. 이 참조 지역성의 원리는 CPU의 캐싱 전략에 영항을 미칩니다. 즉, CPU가 데이터를 엑세스하며 해당 데이터만이 아니라 인접한 메모리에 있는 데이터 또한 캐시 메모리에 함께 올려둡니다.
161 |
162 | 정렬의 실제 동작 시간은 C * 시간복잡도 + a라고 합니다. 시간복잡도는 다 아시는 내용일 것이고 a 상대적으로 무시할 수 있습니다. 하지만 곱해지는 C의 영향도는 고려를 해야합니다. 생각하지 않을 수 없습니다. 이 C라는 값이 바로 참조 지역성 원리가 영향을 미칩니다.
163 |
164 | Array는 메모리적으로 각 값들이 연속적인 주소를 가지고 있기 때문에 C의 값이 낮습니다. 그래서 참조 지역성이 좋은 퀵 정렬을 이용하면 충분한 성능을 제공할 수 있다고 합니다. 하지만 Collection은 List를 기준으로 봤을때 메모리간 인접한 ArrayList 뿐만 아니라 메모리적으로 산발적인 LinkedList도 함께 존재합니다. 따라서 참조 인접성이 좋지 않고 C의 값이 상대적으로 높다고 합니다. 이럴 때는 퀵 정렬 보다는 합병정렬과 삽입정렬을 병합한 Tim 정렬을 이용하는게 평균적으로 더 좋은 성능을 기대할 수 있다고합니다.
165 |
166 |
167 |
168 | ### Q) Map 에 대해 설명해주세요.
169 | - Map은 Key(키)와 Value(값)으로 나눠 데이터를 관리합니다.
170 | - HashMap 을 예시로 설명한다면, 해시테이블에 요소가 저장되어, 검색 시 `O(1)`의 시간 복잡도로 탐색할 수 있습니다.
171 | - TreeMap 은 트리 구조로 저장되어, 요소 간 순서 보장이 필요할 때 `O(logN)` 의 시간복잡도로 탐색할 수 있습니다.
172 |
173 | ### Q-1) Key 중복이 되나요?
174 | - 중복이 허용되지 않습니다.
175 |
176 | ### Q) Hash가 저장되는 방식에 대해 설명해주세요.
177 | - key값과 value값이 들어오면 **Key값이 Hash Function을 통해 고정된 길이의 hash로 변경**됩니다. 이 Hash가 저장위치가 되어, value값을 저장합니다.
178 |
179 | - Hash Function
180 | Input : Key, Output : Hash
181 | key -- Hash Funtion(key) -- Hashing ... -> 고정된 길이의 hash
182 |
183 | ### Q) 배열은 선형 자료구조일까요, 비선형 자료구조일까요?
184 | - **선형 자료구조** 입니다. 선형 자료구조는 **한 원소 뒤에 하나의 원소만이 존재하는 형태로 자료들이 선형으로 나열되어 있는 구조**입니다. 이는 **배열, 리스트, 큐, 스택 등**이 해당됩니다.
185 | - 반대로 **비선형 자료구조**는 **한 원소에 대해 다대다 관계**로 계층적 구조를 표현하는데 사용됩니다. 이는 **트리, 그래프** 등이 포함됩니다.
186 | 따라서 배열은 선형 자료구조 입니다.
187 |
188 | ### Q) Dynamic Array 에 대해 설명해주세요.
189 | > 💡 자바에서 ArrayList는 List + Array 를 합친 개념입니다. 이 때 배열을 메모리에 연속적으로 저장하면서 크기도 동적으로 변할까? 를 생각
190 | - 현재 배정된 memory를 증가시킬 때,
191 | 1. 확장된 메모리를 확보하고 (New Memory Allocation)
192 | 2. 기존의 Array 값들을 새로운 매모리에 복사해줍니다. (Copy Array to New Memory)
193 | 이를 자동으로 지원해주는 자료구조를 Dynamic Array 라고 합니다.
194 |
195 | 
196 |
197 | - Size: 현재 값이 배정되어 있는 원소의 크기
198 | - Capacity: 현재 배정된 메모리의 크기. 무조건 Capacity >= Size이어야 함.
199 | - Scaling factor(Growth Factor): 새로운 원소가 들어와서 들어와서 Capacity가 모자라면, Capacity를 늘려야 합니다. 이 때 메모리를 기존 메모리 대비 몇 배나 확장하게 될 지 판단하게 되는데, 이 값을 Scaling Factor라고 합니다.
200 | - 당연하지만, 이 값이 엄청 크면, time 측면에서는 이득이 있으나, 메모리 공간에서는 손해를 봅니다.
201 |
202 | 만약 새로운 값들이 어레이에 계속 들어와서 Capacity와 Size 값이 같아진다면, 기존의 메모리를 유지한 채 새로운 메모리를 추가하는 것이 아니라, 현재 Size * GrowthFactor만큼의 메모리를 확보한 다음, 이 메모리에 기존 값을 모두 복사해줍니다.
203 |
204 | - ArrayList는 데이터 추가 및 삭제 시 메모리를 재할당하기 때문에 속도가 Array보다 느립니다.
205 |
206 | ### 참고
207 | Copy : https://inpa.tistory.com/entry/JAVA-☕-Object-클래스-clone-메서드-얕은-복사-깊은-복사
208 | 자바 정렬 비교 : https://codingnojam.tistory.com/38
209 | https://frhyme.github.io/datastructure/java_dynamic_array/
210 |
211 |
212 |
213 |
--------------------------------------------------------------------------------
/Data Structure/Graph.md:
--------------------------------------------------------------------------------
1 | # 그래프
2 | 
3 |
4 | 그래프는 노드(N,node)와 그 노드를 연결하는 간선(E,dege)으로 이루어진 자료구조로, 연결되어 있는 객체 간의 관계를 표현할 수 있는 자료구조 입니다. 예를 들어 지도, 지하철 노선도, 도로(교차선, 일방통행길) 등 이 있습니다.
5 |
6 | ### Q) 그래프와 트리의 차이점에 대해 설명해주세요.
7 | - 그래프
8 | - 노드와 노드를 연결하는 간선을 모아놓은 자료구조입니다.
9 | - 루트노드 개념 없음
10 | - 부모-자식 노드 개념이 없음
11 | - 네트워크 구조
12 | - 노드 간 다양한 경로 가능
13 | - 트리
14 | - 트리 또한 그래프이며, 그 중 사이클이 허용되지 않는 그래프를 말합니다.
15 | - 한 개의 루트노드만이 존재
16 | - 부모-자식 관계 있음, 자식노드는 한 개의 부모노드만 가짐.
17 | - 계층적 구조
18 |
19 | ### Q-1) 그래프의 구현 방식에 대해 설명해주세요.
20 |
21 |
22 |
23 |
24 | - 인접 행렬
25 | - 정점의 수 N*N크기의 행렬을 생성해, 행렬의 각 원소를 한 정점이라고 생각하고 인접한 경우에는 1, 인접하지 않은 경우에는 0으로 행렬에 표시합니다.
26 | - 정점 간의 인접 여부를 빠르게 알 수 있다는 장점과, N^2의 메모리 양의 단점이 있습니다.
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | - 인접 리스트
35 | - 각각의 **정점에 인접한 정점들을 연결 리스트**로 표시한 것
36 | - 정점과 간선의 삽입이 빠르고 인접 관계를 표시하는 리스트에 사용되는 메모리의 양이 적다는 장점
37 | - 정점 간의 인접 여부를 인접 리스트를 타고 **순차 탐색을 해야한다는 단점**
38 |
39 |
40 |
41 | ### Q-2) 노드가 적고 간선이 많은 경우에는 어떤 구현 방식을 사용하여야 할까요?
42 | - 행렬입니다.
43 |
44 | ### Q) 그래프에 싸이클이 없는 경우는 트리라고 해주셨는데, 그래프에 싸이클이 존재하지 않으면 트리라고 할 수 있을까요? 아니라면 왜 그럴까요?
45 | - 싸이클이 없어도 트리는 계층적 모델이며, 그래프는 연결 형태를 표시하는 것 입니다. 연결 형태만 표시된다면 그래프 라고 할 수 있습니다.
46 |
47 | 
48 |
--------------------------------------------------------------------------------
/Data Structure/Hash.md:
--------------------------------------------------------------------------------
1 | # 해시
2 |
3 | ### 1. 해시란?
4 | - 데이터의 효율적인 관리를 목적으로 임의의 크기를 가진 **데이터(Key)** 를 고정된 크기의 **데이터(Value)** 로 변화시켜 저장하는 것
5 | - Key와 Value를 이용해서 저장하므로, 데이터의 탐색 속도가 **O(1)** 에 수렴한다.
6 |
7 | ### 2. 해시 함수란?
8 | - 임의의 길이의 데이터를 고정된 길이의 데이터로 매핑해주는 함수이다.
9 | 1. **key** : 매핑 전 값
10 | 2. **hash value** : 매핑후 값
11 | 3. **hashing** : 매핑하는 과정
12 |
13 | ### 3. 해시 테이블이란?
14 | 
15 | - key를 hash value로 매핑하고 hash value를 인덱스 삼아서, 저장하고자 하는 value를 저장하는 자료구조이다.
16 | - **Bucket** 은 Hash Table에서 Data가 저장되는 공간이다.
17 |
18 | #### Q) 해시 충돌을 어떻게 해결하는지에 대해서 설명해주세요.
19 | - 해시 충돌은 Hash Value가 겹쳐서 같은 버킷에 저장하려고 할 때 발생합니다.
20 | - 해시 충돌의 해결 방법은 크게 2가지로 구분합니다.
21 |
22 |
23 | **Separate Chaining(분리 연결법)**
24 | 
25 |
26 | - 해시 충돌 시 추가적인 메모리를 사용해 **LinkedList** or **Tree** 를 이용해서 해결하는 방법
27 | - cf) 자바 8 이상에서는 데이터의 사이즈가 커지면 Tree를 이용하고, RB 트리를 이용해 Balanced 트리로 만듦
28 |
29 | **Open Addressing(개방 주소법)**
30 | 
31 |
32 | - chaining과 달리 한 버킷 당 들어갈 수 있는 value가 1개이다. 따라서, 해싱 이후 삽입 시에 이미 도출 된 hash value 버킷에 값이 있다면 다음 주소를 사용하는 방식으로 해결한다.
33 | - **Probing** : 해시 충돌 시 해시 테이블 내의 새로운 주소를 찾는 방법이다.
34 | 1. **Linear Probing(선형 탐사)**
35 |
36 |
37 | - 최초 해시값에 해당하는 버킷에 다른 데이터가 있다면 한칸씩 이동하여 해결한다.
38 | **[문제]** : 특정 해시 값 주변 버킷이 모두 채워져 있는 primary clustering에 취약하다.
39 |
40 | 2. **Quadratic Probing(제곱 탐사)**
41 |
42 |
43 | - 고정 폭으로 이동하는 선형 탐사와 달리 폭이 제곱 수 만큼 늘어나 이동한다.
44 | **[문제]** : 여러 개의 서로 다른 키들이 동일한 초기 해시값을 갖는 secondary clustering에 취약하다.
45 |
46 | - **Double Hashing(이중 해싱)**
47 | - 탐사할 해시 값의 규칙을 제거하는 방식이고 이를 이용해 클러스터링을 방지하기 위한 기법이고, 처음 버킷을 찾을 때의 해시 함수와, Probing을 위한 해시 함수를 별개로 사용한다.
48 | **[문제]** : 3가지 중 캐시 효율이 가장 좋지 않고, 많은 연산량을 요구한다.
49 | - 개방 주소법을 사용한다는 것은 한 버킷 당 한 데이터 밖에 들어가지 못하기 떄문에, load factor가 1과 같거나 작아야 합니다.
50 | #### Q) 왜 Separate Chaining 방식에서 사이즈가 커지면 리스트가 아닌 트리 형식으로 자료를 저장하나요?
51 | - 트리는 **계층적 구조로 구성되어 있는 대용량 데이터를 저장하기 용이한 자료구조**이기 때문에 트리를 사용하는 것이고, Separate Chaining의 트리 방식은 보통 Balanced Tree로 구성되기 떄문에, **이진 탐색을 하는데 기존의 리스트의 탐색 시간인 O(N) 보다 낮은 O(logN) 만큼만 수행**하면 되기 때문에, 트리를 사용합니다.
52 |
53 | #### Q) 해시 테이블의 개념과 동작 원리에 대해서 설명해주세요.
54 | - key를 hash value로 매핑하고 hash value를 인덱스 삼아서, 저장하고자 하는 value를 저장하는 자료구조이다.
55 | - 해시 함수를 통해서 도출된 Hash Value를 이용하여 Hash Value를 인덱스로 가지는 버킷에 데이터를 저장함으로써 탐색할 떄 O(1) 로 수행할 수 있다는 장점이 있습니다.
56 | - **Bucket** 은 Hash Table에서 Data가 저장되는 공간이다.
57 |
58 | #### Q) 해시 테이블의 장단점에 대해서 설명해주세요.
59 | - [장점] : 해시 테이블은 해시 충돌이 발생하지 않았다는 전제하에, 탐색을 O(1) 만에 수행 할 수 있습니다.
60 | - [단점] :
61 | - 해시 충돌이 발생 할 경우 추가적인 연산이 필요하며, Separate Chaning 방식을 사용했을 경우 추가적인 탐색시간이 증가합니다.
62 | - 해시 테이블에 대한 공간도 산정을 해주어야 하는데, 해시 테이블의 공간이 부족할 경우 resize를 해줘야 한다는 단점이 있습니다. 보통 load Factor가 0.75 이상이 되면 2배로 확장합니다.
63 | - 해시 테이블에 대한 정렬을 수행하려면 추가적인 자료구조를 사용해야합니다.
64 |
65 | #### Q) 자바에서의 HashTable과 HashMap의 차이
66 | - HashMap은 key와 value에 null을 허용하지만, HashTable은 null을 허용하지 않습니다.
67 | - **HashMap** 은 데이터의 **동시성 처리를 보장**하지 않지만, **HashTable** 은 **데이터의 동시성 처리를 지원**해서 HashMap에 비해 상대적으로 연산 속도가 느립니다.
68 | - 최근에는 HashTable의 동시성을 개선한 **ConcurrentHashMap**을 사용합니다.
69 |
70 | #### Q) 해시 테이블을 사용했을 때의 탐색, 삽입, 삭제에 대한 시간복잡도
71 | - 삽입, 삭제, 탐색 모두 해시 충돌이 밣생하지 않았을 경우에는 O(1)의 시간복잡도가 발생합니다.
72 | - 해시 충돌 발생 시 해시 충돌을 해결하는 방법에 따라 시간복잡도가 달라질 수 있으며, Separate Chaining 방식을 이용하여 리스트 자료구조를 이용하여 해결했을 경우에는 O(n)까지 중가할 수 있고, 트리 자료구조를 이용하여 해결했을 경우에는 O(logn) 까지 증가할 수 있습니다.
73 |
74 | #### Q) 해시를 사용하는 이유에 대해서 설명해주세요.
75 | - 자원을 관리하는 관점에서 보면 많은 양의 데이터를 적은 양의 데이터를 관리하기 위해서 사용하고, key-value 를 통해서 찾고자 하는 데이터를 빠르게 찾고자 할 때 용이합니다.
76 |
77 | #### Q) 해시 함수를 사용하는 이유와 없을 때의 문제점.
78 | - 해시 함수를 통해서 많은 양의 데이터를 적은 양의 데이터로 관리 할 수 있는데, 해시 함수를 사용하지 않는다면 들어오는 key 별로 데이터를 적재해야하기 때문에 메모리 낭비가 심해진다는 문제가 있습니다.
79 |
80 | #### Q) load-factor에 대해서 설명해주세요.
81 | - 해시 테이블의 버킷에 평균 몇개에 데이터가 저장되는지에 대한 지표입니다.
82 | - N을 키의 개수, M을 해시 테이블의 크기라고 할 때, **N/M** 입니다.
83 | - 따라서, N/M이 1을 초과하게 되면 해시 충돌이 발생합니다.
84 |
85 | #### Q) load-factor가 너무 작거나 크다면 어떤 문제가 있을까요?
86 | - load-factor가 너무 작다면 키의 개수에 비해 **해시 테이블의 크기가 너무 크게 책정되어 메모리가 낭비되고 있다는 것**을 의미합니다.
87 | - load-factor가 너무 크다면 **해시 충돌이 발생을 하게 되는 상황이고, 삽입, 삭제, 탐색 연산에 있어서 추가적인 연산이 발생**한다는 문제가 있습니다.
88 | - 따라서 위와 같은 문제를 해결하기 위해 적절하게 resize를 해줄 필요가 있습니다.
89 |
--------------------------------------------------------------------------------
/Data Structure/Readme.md:
--------------------------------------------------------------------------------
1 | ### 자료구조
2 |
--------------------------------------------------------------------------------
/Data Structure/Stack, Queue.md:
--------------------------------------------------------------------------------
1 | # Stack, Queue
2 | 스택(Stack)은 top이라 불리는 한쪽 끝에서만 자료를 넣거나 뺄 수 있는 Data Structure입니다. 자료를 넣는 것을 push, 꺼내는 것을 pop이라 하며 가장 마지막에 넣은 자료가 먼저 나오는 Last-In-First-Out(LIFO) 구조입니다.
3 | 큐는(Queue)는 rear라 불리는 한 쪽 끝에서만 자료를 넣고 front라 불리는 반대쪽 한쪽 끝에서만 자료를 뺄 수 있는 Data Structure입니다. 자료를 넣는 것을 자료를 넣는 것을 enqueue, 꺼내는 것을 dequeue이라 하며 가장 먼저 넣은 자료가 먼저 나오는 First-In-First-Out(FIFO) 구조입니다.
4 |
5 | ### Q) 스택과 큐의 내부 구조를 배열로 구현하면 어떻게 구현할 수 있나요?
6 | - stack : JAVA의 ArrayList로 구현을 할 시 push 는 add() 메소드를 통해, pop은 리스트의 맨 앞(인덱스 0)의 요소를 반환하고 제거해줍니다.
7 | - queue : JAVA의 ArrayList로 구현을 할 시 push 는 add() 메소드를 통해, pop은 리스트의 맨 뒤(인덱스 -1)의 요소를 반환하고 제거해줍니다.
8 | 
9 |
10 | ### Q) 삽입, 삭제가 빈번할텐데, 배열은 정적인 크기를 가지고 있는데 위의 말씀하신 대로라면 배열의 크기가 동적으로 변한다는 문제가 있지 않나요?
11 | JAVA의 ArrayList는 배열과 리스트의 특성을 합친 자료구조입니다. 그렇기에 배열은 정적인 크기를 갖고 있으나, JAVA의 ArrayList는 동적으로 크기를 변하는 것이 가능하기에 괜찮습니다.
12 |
13 | ### Q) 큐의 사용 사례에 대해 설명해주세요.
14 | - 버퍼(Buffer) : 먼저 요청이 들어온 요청부터 먼저 처리해줍니다.
15 | (+) 버퍼 사용 이유
16 | 버퍼를 사용하지않으면 입력과 즉시 데이터가 전송되기때문에 전송타겟에 부하가 걸릴 수 있습니다.
17 | 입력된것을 한번에 묶어서 전달하기에 전송시간이 줄어들며, 성능이 향상합니다.
18 | 더 나아가, 사용자가 잘못 입력시 수정도 가능하다는 장점을 갖고 있습니다.
19 | 그러나 입력과 즉시 데이터 전송을 하지않기 때문에 반응시간이 느립니다.
20 |
21 | ### Q) 스택의 사용 사례에 대해 설명해주세요.
22 | - call stack : 함수의 순서를 저장해두는 데 사용됩니다.
23 | - 웹 브라우저 뒤로가기 : 가장 나중에 열린 페이지부터 뒤로 가기를 실행합니다.
24 | - 문서작업에서 Ctrl+Z : 가장 나중에 수정한 내역부터 되돌립니다.
25 |
26 | ### Q) 스택으로 큐를 구현하는 방법에 대해 설명해주세요.
27 | 💡 스택 한개는 InBox, 한 개는 OutBox 용도로 만듭니다.
28 | 1. inBox에 데이터를 push(삽입)합니다. ex) 4→ 3→ 2→ 1
29 | 
30 | 2. inBox에 있는 데이터를 pop(추출) 하여 outBox에 push(삽입)합니다. ex) 1→ 2→ 3→ 4
31 | 
32 | 
33 | 3. outBox에 있는 데이터를 pop(추출) 합니다. - 4→ 3→ 2→ 1
34 | 
35 |
36 | ### Q) 큐로 스택을 구현하는 방법에 대해 설명해주세요.
37 | 💡 큐 한 개는 메인 큐, 다른 큐는 임시 큐 용도로 둡니다.
38 | 1. 메인 큐에 값을 넣습니다.(put) ex) 1→ 2→ 3 → 4
39 | 
40 | 2. 메인 큐에 1개의 원소가 남을 때까지 get 한 값을 임시 큐에 put 합니다.
41 | 
42 | 3. 마지막 남은 원소는 result 변수에 저장합니다.
43 | 
44 | 4. 임시 큐에 있는 원소들을 메인 큐로 모두 이동시킵니다. (get → put)
45 | 
46 | 5. result 값을 리턴합니다.
47 |
48 | ### Q) Stackoverflow 현상에 대해 설명해주세요.
49 | - Stack overflow는 스택 포인터가 메모리 내 스택의 경계를 넘어갈 때 발생하는 에러입니다. 해당 변수의 크기가 Stack보다 크거나, 함수를 무한으로 호출하고 있을 때, 혹은 Stack을 넘어가 다른 곳에 위치하고 있는 경우에 주로 발생합니다.
50 | - (+) Stack은 높은 주소 (High Address)부터 낮은 주소 (Low address)로 메모리에 할당됩니다.
51 | 
52 |
53 | ### Q-1) 해결하는 방법은 무엇이 있나요?
54 | - JAVA VM 옵션에서 스택의 크기를 증가시켜주면 됩니다.
55 |
56 | ### Q) Messaging queue에 대해 아는 데까지 말씀해주세요.
57 | - 메시지 큐는 메시지를 임시로 저장하는 간단한 버퍼라고 생각하면 됩니다. 메시지를 전송 및 수신하기 위해 중간에 메시지 큐를 두는 것입니다.
58 | - 메시지 전송 시 생산자(Producer)로 취급되는 컴포넌트가 메시지를 메시지 큐에 추가합니다. 해당 메시지는 소비자(Consumer)로 취급되는 또 다른 컴포넌트가 메시지를 검색하고 이를 사용해 어떤 작업을 수행할 때까지 메시지 큐에 저장됩니다.
59 | 
60 | - 사용하는 이유 : 메시지 큐는 소비자(Consumer)가 실제로 메시지를 어느 시점에 가져가서 처리하는 지는 보장하지 않습니다. 언젠가는 큐에 넣어둔 메시지가 소비되어 처리될 것이라고 믿습니다.
61 | 이러한 비동기적 특성 때문에 메시지 큐는 실패하면 치명적인 핵심 작업보다는 **어플리케이션의 부가적인 기능**에 사용하는 것이 적합합니다.
62 | - 메시지 큐의 이점
63 | - 비동기(Asynchronous)
64 | 메시지 큐는 생산된 메시지의 저장, 전송에 대해 동기화 처리를 진행하지 않고, 큐에 넣어 두기 때문에 나중에 처리할 수 있습니다. 여기서, 기존 동기화 방식은 많은 메시지(데이터)가 전송될 경우 병목이 생길 수 있고, 뒤에 들어오는 요청에 대한 응답이 지연됩니다.
65 | - 낮은 결합도(Decoupling)
66 | 생산자 서비스와 소비자 서비스가 독립적으로 행동하게 됨으로써 서비스 간 결합도가 낮아집니다.
67 | - 확장성(Scalable)
68 | 생산자 서비스 혹은 소비자 서비스를 원하는 대로 확장할 수 있기 때문에 확장성이 좋습니다.
69 | - 탄력성(Resilience)
70 | 소비자 서비스가 다운되더라도 어플리케이션이 중단되는 것은 아닙니다. 메시지는 메시지 큐에 남아 있습니다. 소비자 서비스가 다시 시작될 때마다 추가 설정이나 작업을 수행하지 않고도 메시지 처리를 시작할 수 있습니다.
71 | - 보장성(Guarantees)
72 | 메시지 큐는 큐에 보관되는 모든 메시지가 결국 소비자 서비스에게 전달된다는 일반적인 보장을 제공합니다.
73 |
74 | ### Q) 우선순위 큐는 어떤 자료구조로 구현돼있나요?
75 | heap을 통해서 구현합니다.
76 | ### Q-1) 왜 heap을 사용하나요?
77 | heap은 최대, 최소값을 반환하는데 특화된 (시간복잡도 O(1)) 자료구조입니다. 우선순위가 높은/낮은 데이터 추출에 가장 빠르게 반환할 수 있는 자료구조이기 때문입니다.
78 |
79 | ### Q-2) heap을 toString()으로 출력한다면 순서대로 나올까요?
80 | 아닙니다. heap은 tree로 구성된 자료구조이기에, 순서대로가 아닌 트리 노드에 담긴 순서대로 나올 것 입니다.
81 |
82 | ### Q-3) 우선순위 큐의 사용사례는 무엇이 있나요?
83 | 우선순위가 가장 높은 것을 추출할 때 사용됩니다.
84 | 1. 다익스트라 알고리즘(Dijkstra’s algorithm) : 최소 값을 찾을 때 우선순위 큐가 사용됩니다.
85 | 2. 힙정렬: 많은 힙 정렬에서는 우선순위 큐를 사용합니다.
86 | 3. 허프만 코딩: 문자열을 트리를 이용해 2진수로 압축하는 알고리즘이고 min-Priority를 사용합니다.
87 |
88 | ### Q) 양방향 큐는 무엇인가요?
89 | - 덱(Deque)는 양방향에서 요소를 추가하고 제거할 수 있는 양방향 큐입니다.
90 | 큐는 맨 뒤 요소 (rear) 에 값을 추가하고, 맨 앞 요소 (front) 의 값을 삭제하는 방식이지만 덱(Deque)는 맨 앞에 추가할수고, 맨 뒤를 삭제할 수도 있습니다.
91 | - 스택처럼 사용할 수도 있고 큐 처럼 사용할 수도 있는 자료구조입니다.
92 | - 단방향 큐를 일반적인 리스트(list) 로 구현할 때 요소를 추가하고 제거할 때의 복잡도는 O(n) 인 반면, 양방향에서 값을 추가하고 제거하는 처리의 복잡도는 O(1)로 구현할 수 있습니다.
93 | 
94 |
95 | #### 사진 & 내용 출처
96 | https://tecoble.techcourse.co.kr/post/2021-09-19-message-queue/
97 | https://pro-programmer.tistory.com/4
98 | https://cocoon1787.tistory.com/691
99 | https://80000coding.oopy.io/bab54a8f-01de-4dcc-9630-2e8eaae9ed67
100 | https://underdog11.tistory.com/entry/%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-Priority-Queues-%EC%9A%B0%EC%84%A0%EC%88%9C%EC%9C%84-%ED%81%90
101 | https://ryu-e.tistory.com/96
102 |
--------------------------------------------------------------------------------
/Data Structure/Tree & Heap.md:
--------------------------------------------------------------------------------
1 | # 트리
2 |
3 | ### Q) 트리 중 이진트리에 대해 설명해주세요.
4 |
5 | - 트리는 노드로 이루어진 자료구조로 스택이나 큐와 같은 선형 구조가 아닌 비선형 자료구조입니다.
6 | - 다음과 같은 특징이 있습니다.
7 |
8 | - 1. 트리는 하나의 루트 노드를 갖는다.
9 |
10 | - 2. 루트 노드는 0개 이상의 자식 노드를 갖는다.
11 |
12 | - 3. 자식 노드 또한 0개 이상의 자식 노드를 갖는다.
13 |
14 | - 4. 노드(Node)들과 노드들을 연결하는 간선(Edge)들로 구성되어 있다.
15 |
16 | - 트리에는 사이클(cycle)이 존재할 수 없다. 여기서 사이클이란 시작 노드에서 출발해 다른 노드를 거쳐 다시 시작 노드로 돌아올 수 있다면 사이클이 존재한다고 한다.
17 |
18 |
19 | - 트리는 사이클(cycle)이 없는 하나의 연결 그래프(Connected Graph)라고 할 수 있다.
20 | 트리의 노드는 self-loop가 존재 해서는 안된다.
21 |
22 |
23 |
24 |
25 | **루트 노드(root node)** : 부모가 없는 노드로 트리는 단 하나의 루트 노드를 가진다. (ex : A- 루트노드)
26 |
27 | **단말 노드(leaf node)** : 자식이 없는 노드로 terminal 노드라고도 부른다. (ex : C, D, E - 단말 노드)
28 |
29 | **내부 노드(internal node)** : 단말 노드가 아닌 노드(ex : A, B - 내부 노드)
30 |
31 | **간선(edge)** : 노드를 연결하는 선
32 |
33 | **형제(sibling)** : 같은 부모 노드를 갖는 노드들 (ex : D-E, B-C : 형제)
34 |
35 | **노드의 깊이(depth)** : 루트 노드에서 어떤 노드에 도달하기 위해 거쳐야 하는 간선의 수(ex : D의 depth : 2)
36 |
37 | **노드의 레벨(level)** : 트리의 특정 깊이를 가지는 노드의 집합 ( ex : level 1- {B, C} )
38 |
39 | **노드의 차수(degree)** : 자식 노드의 개수 ( ex : B의 degree - 2, C의 degree - 0)
40 |
41 | **트리의 차수(degree of tree)** : 트리의 최대 차수 ( ex : 위 트리의 차수는 2이다)
42 |
43 | ### Q-1) 이진트리 검색과 삭제 시간 복잡도 평균에 대해 설명해주세요.
44 |
45 | - 이진 트리의 검색과 삭제 시간 복잡도는 트리의 높이에 의해 결정됩니다. 따라서 이진 트리의 높이가 h라면, 검색과 삭제는 O(h) 시간이 걸립니다.
46 |
47 | 이진 탐색 트리의 경우, 평균 높이는 O(log n)이므로 검색과 삭제의 평균 시간 복잡도는 `O(log n)`입니다. 이진 탐색 트리의 높이가 O(log n)이 되는 것은 키 값들이 무작위로 배치될 때 발생하며, 이 경우 대부분의 검색과 삭제 작업은 O(log n) 시간 안에 수행됩니다.
48 |
49 | 하지만 이진 탐색 트리에서 키 값들이 일정한 패턴으로 배치되는 경우, 트리의 높이가 n-1이 될 수 있습니다. 이러한 경우, 검색 및 삭제 연산의 시간 복잡도는 O(n)이 됩니다.
50 |
51 | 따라서, 이진 탐색 트리의 검색 및 삭제 연산의 평균 시간 복잡도는 O(log n)이며, `최악의 경우 O(n)`이 될 수 있습니다.
52 |
53 | ### Q-2) 편형된 트리를 보완할 수 있는게 있을까요?
54 |
55 | - Balanced Tree(균형 트리)가 있습니다. 균형 트리는 트리의 높이가 가능한 작은 상태를 유지하는 이진 탐색 트리의 일종입니다. 이진 탐색 트리에서 키 값들이 무작위로 배치되지 않은 경우, 트리의 높이는 O(n)이 될 수 있습니다. 이 경우, 검색 및 삭제 작업의 시간 복잡도가 O(n)이 되므로 효율적인 이진 탐색 트리가 아닙니다.
56 |
57 | 반면에 균형 트리는 트리의 높이를 가능한 작게 유지하기 위해 노드의 삽입, 삭제 등의 작업을 수행할 때 트리의 구조를 조정합니다. 대표적인 균형 트리로는 AVL 트리, 레드-블랙 트리, B-트리 등이 있습니다.
58 |
59 | ### Q) AVL 트리와 레드블랙트리에 대해 알고계신가요?
60 |
61 | - 이진탐색트리의 문제점을 극복할 수 있는 자료구조이다. 이진탐색트리에서 한쪽으로 노드가 쏠리게되면 최악의 경우 O(N)의 시간이 필요하기때문에 성능이 저하된다.
62 |
63 | - AVL트리는 다음과 같은 특징을 가진다.
64 |
65 | - 이진 탐색 트리의 속성을 가진다.
66 | - 왼쪽, 오른쪽 서브 트리의 높이 차이가 최대 1이다.
67 | - 높이 차이가 1보다 커지면 회전(Rotation)을 통해 균형을 맞춰 높이 차이를 줄인다.
68 | - 삽입, 검색, 삭제의 시간 복잡도가 O(log N)이다. (N : 노드의 개수)
69 |
70 | - Balance Factor(BF)
71 | - 왼쪽과 오른쪽의 자식의 높이 차이를 뜻합니다.
72 | - 회전
73 | - 불균형한 트리로 바로잡기 위해서는 회전이 필요합니다.
74 |
75 | ### Q-1) AVL과 레드블랙 차이에 대해 알려주세요.
76 |
77 | 1. AVL트리는 더욱 엄격한 균형을 이루고 있기 때문에 `Red-Black 트리보다 더 빠른 조회를 제공`
78 |
79 | 2. Red-Black 트리는 상대적으로 느슨한 균형으로 인해 회전이 거의 이루어지지 않기 때문에 AVL트리보다 빠르게 삽입 및 제거 작업을 수행
80 |
81 | 3. AVL트리는 각 노드에 대해 BF를 저장하므로 노드 당 int 저장이 필요
82 |
83 | 4. Red-Black 트리는 노드당 1비트의 정보만 필요합니다. (플래그 반전만 시키면 됨)
84 |
85 | 5. Red-Black 트리는 맵, C++의 멀티캐스트, Java treeMap 등 대부분의 언어 라이브러리에서 사용, AVL트리는 더 빠른 검색이 필요한 데이터베이스에서 사용
86 |
87 | ### Q) Balanced 트리의 시간 복잡도 최악이 어떻게 될까요?
88 |
89 | - 균형 트리의 검색, 삽입, 삭제 연산의 최악 시간 복잡도는 `O(log n)`입니다. 이는 이진 탐색 트리의 경우와 동일하며, 트리가 균형을 유지하므로 트리의 크기 n에 대해 항상 일정한 시간 복잡도를 보장합니다.
90 |
91 | ### Q) 이진트리와 이진 탐색 트리를 각각 비교해서 설명해주세요.
92 |
93 | - 이진 트리는 각 노드가 최대 2개의 자식 노드를 가지는 트리로, 왼쪽 자식 노드는 부모 노드보다 작은 값, 오른쪽 자식 노드는 부모 노드보다 큰 값이 저장됩니다.
94 |
95 | - 이진 탐색 트리는 이진 트리의 일종으로, 각 노드의 왼쪽 자식 노드는 부모 노드보다 작은 값, 오른쪽 자식 노드는 부모 노드보다 큰 값이 저장되는 트리입니다. 이진 탐색 트리는 검색이나 정렬에 용이합니다.
96 |
97 | ### Q) 3가지 순회방식에 대해서 알고 계신가요?
98 |
99 | -
100 |
101 | 전위 순회 : 0->1->3->7->8->4->9->10->2->5->11->6
102 |
103 | 중위 순회 : 7->3->8->1->9->4->10->0->11->5->2->6
104 |
105 | 후위 순회 : 7->8->3->9->10->4->1->11->5->6->2->0
106 |
107 | ### Q) 정렬이 된 상태에서 출력한 값을 보고 싶다면 어떤 순회를 사용해야할까??
108 |
109 | - 중위 순회는 왼쪽 서브트리, 현재 노드, 오른쪽 서브트리 순서로 노드를 탐색하는 방법입니다. 이진 탐색 트리의 특성 상 중위 순회를 사용하면 노드가 정렬된 순서대로 출력됩니다. 즉, 중위 순회를 수행하면 정렬된 값을 순서대로 출력할 수 있습니다.
110 |
111 | 중위 순회의 시간 복잡도는 트리의 크기에 비례합니다. 따라서 이진 탐색 트리가 균형을 유지하는 경우, 중위 순회의 시간 복잡도는 O(n log n)입니다. 하지만, 트리의 높이가 매우 높은 경우, 중위 순회의 시간 복잡도는 O(n)이 될 수 있습니다.
112 |
113 | ### Q) 후위순회를 사용하는 사례에 대해 설명해주세요.
114 |
115 | - 후위 순회는 이진 트리의 각 노드에 대한 작업을 수행하기에 적합합니다. 예를 들어, 후위 순회를 사용하여 이진 트리에서 수식을 계산하거나, 트리에서 각 노드의 깊이를 계산하는 등의 작업을 수행할 수 있습니다.
116 |
117 | 또한, 후위 순회는 이진 트리에서 메모리 해제 등의 정리 작업을 수행할 때에도 유용합니다. 이는 노드의 자식 노드들을 모두 방문한 후, 부모 노드를 방문하며 메모리를 해제하기 때문입니다.
118 |
119 | ### Q) 해시테이블말고 이진 탐색 트리를 사용하는 이유와 각 차이에 대해 설명해주세요.
120 |
121 | - 기능적인 측면에서 보면 탐색, 삭제, 삽입과 같은 기본기능들에 대해서, `해시 테이블` : O(1)
122 | `이진탐색트리` : O(logN) 정도 성능으로 동작한다.
123 |
124 | 해시 테이블의 해시 함수의 비용과, 충돌 해결비용까지 고려하더라도 `데이터가 엄청 많아지는` 경우에는 해시 테이블이 효과적이라고 볼 수 있다. 그리고 만약 입력 사이즈를 알고 있다면, 입력 사이즈에 맞게 최적화된 해시 함수를 이용하여 해시 테이블의 해시 값을 균일하게 분포시켜서 성능을 최적화시킬 수 있을 것이다.
125 |
126 |
127 |
128 | 하지만 이진탐색트리에는 `데이터들의 순서가 정렬`된 상태로 유지된다는 강력한 장점이 있다. 이 특성으로 인해 데이터를 정렬된 형태로 순회할 수 있다는 장점도 있겠지만, 아주 좋은 성능으로 범위기반 쿼리가 가능하다는 장점도 있다. 그러므로 `순서와 밀접한 연관이 있는 데이터` 를 다루는 상황에서는 이진탐색트리가 효과적일 것이다. 또한 문자열과 같은 데이터를 다루는 상황에서는 키의 동등 비교를 수행하는 해시 테이블보다, 키의 크기 비교를 수행하는 이진트리가 유리할 것이다.
129 |
130 | - 메모리 측면에서보면 이진탐색트리는 딱 필요한 원소 만큼의 공간만을 할당하는 반면, 해시 테이블은 해시 적중률을 높이기 위해 `원소의 개수 이상의 메모리`를 유지해야한다. 그러므로 사용량 측면에서는 이진탐색트리가 유리하다.
131 |
132 | - 캐시 적중률 측면에서 보면 이진탐색트리는 노드 기반 자료구조로 메모리 파편화가 진행되어 `캐시 적중률`이 떨어지게 된다. 반면, 해시 테이블은 배열 기반 자료구조로 연속된 메모리를 유지하기 때문에 `캐시 적중률이 상당히 높다`.
133 |
134 | ### Q) b-tree / b+tree 차이에 대해 설명해주세요.
135 |
136 | - 
137 |
138 | B-Tree 는 위 그림과 같이 생겼습니다. Binary-Tree 라고 오해를 하지만 Balanced-Tree 를 의미합니다. 자식이 2개 이상 가능합니다.
139 |
140 | B-tree 는 균형 트리로 루트로부터 리프까지의 거리가 일정한 트리 구조입니다. 이렇게 균형을 유지할 경우 어떤 데이터를 검색할 때 빠른 속도로 데이터를 찾을 수 있습니다. 하지만 만약 트리의 노드가 수정되어야 한다면 재정렬을 해줘야 하기 때문에 수정시 약점이 있습니다.
141 |
142 | MySQL의 InnoDB에서 사용되는 B+Tree 는 리프 노드를 제외하고 값을 담아두지 않기 때문에 하나의 블록에 더많은 Key 들을 담아 둘 수 있다 는 장점이 있습니다. 이는 곧, 트리의 높이가 낮아짐을 나타냅니다.
143 |
144 | 풀 스캔시 B+Tree는 `리프 노드에 데이터`가 모두 있기 때문에 한번의 선형 탐색만 하면 되기 때문에 B-Tree 에 비해 빠르다 는 장점이 있습니다. 참고로 같은 레벨의 노드에서는 `Double Linked List` 를 사용하고 자식 노드는 `Single Linked List` 를 사용합니다.
145 |
146 | ### Q-1) 노드가 이진트리는 2개였는데 b-tree도 2개만 가지고 있나요?
147 |
148 | - B-트리(B-tree)는 이진 트리와 달리 자식 노드의 개수가 정해져 있지 않습니다. 각 노드는 여러 개의 자식 노드를 가질 수 있습니다.
149 |
150 | ### Q) 완전 이진 트리랑 불안전 이진 트리는 어떻게 구분?
151 |
152 | - 완전 이진 트리(Complete Binary Tree)는 모든 레벨에서 노드가 꽉 차 있고, 마지막 레벨에서는 오른쪽부터 순서대로 노드가 채워진 이진 트리를 말합니다. 이와 반대로, 불완전 이진 트리(Incomplete Binary Tree)는 모든 레벨에서 노드가 꽉 차 있지 않거나, 마지막 레벨에서 오른쪽에서부터 노드가 채워져 있지 않은 이진 트리를 말합니다.
153 |
154 | ### Q) 힙과 이진 탐색 트리의 차이점?
155 |
156 | - 구현 방식
157 |
158 | `이진 탐색 트리`: 모든 노드의 왼쪽 서브트리에는 해당 노드보다 작은 값의 노드들이, 오른쪽 서브트리에는 해당 노드보다 큰 값의 노드들이 위치합니다. 각 노드의 값은 자신을 기준으로 왼쪽 서브트리에는 작은 값의 노드들만, 오른쪽 서브트리에는 큰 값의 노드들만 저장됩니다. 삽입/삭제 연산 시 최악의 경우 O(h)의 시간 복잡도를 가집니다. 이 때 h는 트리의 높이를 의미합니다. 만약 트리가 한쪽으로 치우쳐져 있을 경우, 삽입/삭제 연산 시간이 O(n)으로 급증할 수 있습니다.
159 |
160 | `힙`: `완전 이진 트리 형태`를 띄며, 부모 노드와 자식 노드 간의 대소 관계가 정해져 있습니다.
161 | 노드 값의 저장 방식입니다. 부모 노드와 자식 노드 간의 대소 관계가 정해져 있어, 최대 힙(Max Heap)의 경우 부모 노드의 값이 자식 노드의 값보다 크고, 최소 힙(Min Heap)의 경우 부모 노드의 값이 자식 노드의 값보다 작습니다. 삽입/삭제 연산 시 `최악의 경우 O(log n)의 시간 복잡도`를 가집니다. 트리의 높이가 균형적으로 유지되기 때문에 이진 탐색 트리와 달리 삽입/삭제 연산 시간이 일정합니다.
162 |
163 | 따라서 이진 탐색 트리는 `탐색 연산에 더 유리`하며, `삽입/삭제 연산이 빈번하지 않은 경우에 적합`합니다. 반면에 힙은 `최대/최소값을 빠르게 찾을 수 있으며`, `삽입/삭제 연산이 빈번한 경우에 적합`합니다.
164 |
165 | ### Q) 힙에도 작은 값은 왼쪽, 큰 값은 오른쪽으로 가는 성질이 적용될까요?
166 |
167 | - 힙은 이진 탐색 트리와 달리 부모 노드와 자식 노드 간의 대소 관계가 정해져 있으며, 부모 노드의 값이 자식 노드의 값보다 큰 경우를 최대 힙(Max Heap)이라고 합니다. 최소 힙(Min Heap)의 경우는 부모 노드의 값이 자식 노드의 값보다 작은 경우입니다.
168 |
169 | ### Q) 이진 탐색트리랑 힙에서 중복된 값을 삽입하는게 가능할까요? (힙은 중복가능)
170 |
171 | - 이진 탐색 트리는 중복을 허용하지 않고, 힙은 중복을 허용한다.
172 |
173 | ### Q) 힙 삽입 삭제 시 연산이 어떻게 일어날까요?
174 |
175 | - 삭제할 값을 선택합니다. 최대 힙(Max Heap)의 경우 루트 노드에 있는 가장 큰 값을 선택하고, 최소 힙(Min Heap)의 경우 루트 노드에 있는 가장 작은 값을 선택합니다.
176 |
177 | 삭제할 값을 힙의 맨 마지막 노드와 교환합니다.
178 |
179 | 힙의 맨 마지막 노드를 삭제합니다.
180 |
181 | 변경된 노드를 힙의 구조에 맞게 재정렬합니다. 최대 힙(Max Heap)의 경우, 루트 노드로부터 아래로 내려가며 자식 노드 중 가장 큰 값을 가진 노드와 교환해 나가며 정렬합니다. 최소 힙(Min Heap)의 경우도 마찬가지로, 루트 노드로부터 아래로 내려가며 자식 노드 중 가장 작은 값을 가진 노드와 교환해 나가며 정렬합니다.
182 |
--------------------------------------------------------------------------------
/Database/Clustering, Replication.md:
--------------------------------------------------------------------------------
1 | # 클러스터링
2 | - 동일한 데이터베이스를 여러 대의 서버가 관리하도록 클러스터를 구축하는 것.
3 | - 클러스터링을 이용함으로써 하나의 서버에 몰리던 부하를 여러 곳으로 분산 시키는 로드 밸런싱이 가능해집니다.
4 |
5 | #### 클러스터링의 종류
6 | 1. **Active-Active 방식**
7 | - Active-Active 방식은 동일한 데이터 베이스를 여러 대의 서버가 관리하도록 하는 상태에서, 관리하는 서버들을 모두 켜놓는 상태를 말합니다.
8 | **[장점]** : 하나의 데이터베이스 서버가 죽더라도 바로 다른 데이터베이스에서 필요한 작업을 수행하면 되기 때문에 클라이언트 입장에서는 서버의 문제가 없는 것처럼 받아들일 수 있고, 안정적인 서비스를 운영 할 수 있습니다.
9 | **[단점]** : 여러 대의 서버가 데이터베이스를 공유하므로 병목현상이 발생해서 더 많은 비용이 발생할 수 있고, 여러 개의 서버를 지속적으로 운영하는 과정에서 서버 비용이 많이 소모될 수 있습니다.
10 | 2. **Active-StandBy 방식**
11 | - Active-Active 방식과 달리 모든 서버를 열어두는 것이 아니고, 주 서버를 Active 상태로 유지를 하다가 Active 상태에 문제가 생기면 StandBy 즉, 실행중이지 않고 대기중이었던 데이터베이스 서버를 Active 상태로 전환해서 사용하는 방식입니다. 이러한 방식을 **FailOver** 방식이라고 합니다.
12 | **[장점]** : 기존의 Active-Active 방식에 비해서 상대적으로 비용이 덜 들게 되고 병목현상도 덜 발생하게 됩니다.
13 | **[단점]** : Acitve 서버가 문제가 발생했을 경우 StandBy 서버를 Active 서버로 전환하는데에 시간이 소요되어 그 기간동안 클라이언트들은 서비스를 이용할 수 없다는 문제가 있고, Active-Active 방식에 비해서 로드 밸런싱 효율도 떨어진다는 문제가 있습니다.
14 |
15 | ### Q) 레디스 클러스터링 방식
16 | - Redis Cluster 방식은 데이터를 자동으로 여러 개의 Redis 노드에 나누어 저장할 수 있는 방법을 제공합니다. 이때, 일부 노드가 죽거나 통신이 되지 않을 때에도 작업을 계속 할 수 있는 가용성을 제공합니다.
17 | - 단, 과반수의 master 노드가 죽는 경우에는 클러스터도 중단됩니다.
18 | - Redis 6.0 부터 ThreadedIO가 추가되어 사용자 명령에 대해서는 멀티 쓰레드가 지원되지만, 명령어를 실행하는 코어 부분은 싱글 쓰레드로 동작합니다.
19 |
20 | # 리플리케이션
21 | - 리플리케이션은 복제된 데이터베이스를 운용하는 방식입니다.
22 | - 이때, 원본 데이터베이스를 Master, 복제된 데이터베이스를 Slave라고 부릅니다. Slave 데이터베이스는 Master 데이터베이스를 복제하여 동일한 데이터를 가지게 됩니다.
23 |
24 | **[장점]**
25 | 1. 리플리케이션은 Master 데이터베이스와 Slave 데이터베이스에 각기 다른 명령을 수행하도록 할 수 있습니다. 이로 인해, Insert, Update, Delete 등의 무거운 작업은 Master에 일임하고, Select 같이 가벼운 작업은 Slave에 일임해 부하를 분산시킬 수 있습니다.
26 | 2. 리플리케이션을 이용하면 데이터 안정성을 획득할 수 있고, Master 데이터베이스의 데이터가 손상되었을 때 Slave 데이터베이스에 복제된 데이터를 통하여 복구할 수 있습니다.
27 |
28 | **[단점]**
29 | 1. Slave에 Master의 데이터를 복제할 때 비동기로 동기화가 됩니다. 이에 따라 데이터의 일관성이 깨질 수 있는 상황이 생길 수도 있습니다. 이때, 복제를 하기 위해 Binary Log 를 사용합니다.
30 |
31 | ### Q) 무거운 연산과 가벼운 연산이 무엇인지에 대해서 설명해주세요.
32 | - 무거운 연산은 주로 CREATE, DELETE, UPDATE 등을 의미하고, 가벼운 연산은 SELECT를 의미합니다.
33 |
34 | ### Q) MYSQL 데이터베이스 리플리케이션 실행 방식에 대해서 설명해주세요.
35 | 1. **Async Replication**
36 | - MySQL이 기본적으로 채택하는 Replication 방식이고, Binary Log을 사용하여 복제를 합니다. Binary Log에는 MySQL의 모든 변경 사항이 기록이 되고, Slave DB가 이 Binary Log를 이용하여 Replication을 수행하는 방식입니다.
37 | - 하지만, replicaiton이 async 방식으로 동작해서 Master 에서는 Slave의 복제 여부등을 확인하지 않아 데이터 일관성 문제를 발생할 수가 있고, Slave의 부하 정도, 시스템 사용륭, 네트워크 속도 등 여러가지 이유로 Replication이 지연될 수 있습니다.
38 |
39 | 2. **Semi-Sync Replication**
40 | - MySQL 5.5 버전에서 도입된 방식입니다. Master DB에서 Slave로 전달된 Relay log의 기록이 완료되었다는 메시지를 받고나서 처리중인 트랜잭션의 결과를 클라이언트에게 반환합니다.
41 | - Async 방식에 비하면 성능이 저하되지만 완전한 sync 방식 보다는 성능 저하가 덜하고, 변경이 전달된 이후에 클라이언트에게 결과를 반환하기 때문에, 데이터 동기화를 더욱 보장해 줄 수 있습니다.
42 |
43 | 3. **binlog**
44 | - Binary log는 DDL 과 DML 같이 데이터베이스 내에서 발생하는 변경 내역들이 저장되는 로그 파일 입니다.
45 | - 이러한 로그 파일은 **row, mixed, statement** 3가지 포맷을 가지고 있습니다.
46 | 1. **statement** : 전통적으로 사용하던 방식으로 실행된 쿼리 구문 그대로 Binlog에 남겨지는 방식
47 | 2. **row** : 생성/변경된 데이터의 Before/After row image가 binlog에 저장하여, 사이즈가 statement보다 크게 생성
48 | 3. **mixed** : row와 statement 중간 형태로 날짜와 같이 determine이 필요한 경우 row형태로 저장되는 형식
49 |
50 | ### Q) 클러스터링과 리플리케이션의 차이점에 대해서 설명해주세요.
51 | - 클러스터링은 동일한 데이터베이스를 각 다른 서버에서 관리하는 방식이고, 리플리케이션은 동일한 데이터베이스를 하나의 서버에서 데이터베이스를 복제해서 사용하는 방식으로 사용합니다.
52 | ### Q-1) 동기, 비동기 관점에서도 설명해주세요.
53 | - 이때, 클러스터링은 같은 데이터베이스를 단순히 각기 다른 서버에서 관리를 하다보니, 동기로 동작하고 리플리케이션은 동일한 서버에서 데이터베이스를 복제해서 사용하므로, Master 데이터베이스를 Slave 데이터베이스에 데이터를 복제하는 과정이 필요해서 비동기로 동작합니다.
54 |
55 | ### Q-2) 클러스터링과 리플리케이션은 각각 어느 상황에서 사용하는 것이 좋을까?.
56 | - 클러스터링은 리플리케이션에 비해서 가용성 측면에서 많은 장점을 가져다주고 추가적으로 부하 분산을 위한 로드밸런싱도 리플리케이션에 비해서 좋기 때문에 안정적인 서비스를 하기 위한 목적이라면 클러스터링을 사용합니다.
57 | - 리플리케이션은 서버는 안정적이지만 무거운 쿼리에 대한 응답 속도를 높이고 이에 따라 부하를 분산 시켜 성능 최적화를 하고 싶을 때 사용하는 것이 좋습니다.
58 |
59 | ### Q) 분산 락을 어떻게 구현 할 것 같은지 답변을 해주세요.
60 | - 제 3의 서버로 레디스를 두고 분산 데이터베이스에 락에 대해서 락을 레디스에서 잠궈두고 구독자-발행자 패턴을 사용하여 락이 풀리게 되면 그때 제일 처음 진입한 구독자에 대해서 락 권한을 주어 접근 할 수 있도록 합니다.
61 | - 혹은 낙관적 락을 택하고, 트랜잭션을 수행하면서 데이터의 불일치성이 발견되면 그 떄, 애플리케이션 단계에서 연쇄 롤백을 처리하는 방법도 있습니다. 하지만 이는 구현하기가 복잡하고, 클라이언트에게 안 좋은 서비스 경험도 줄 수 있습니다.
62 |
63 | ### Q) GTID가 무엇인지 설명해주세요.
64 | - GTID는 Global Transaction IDentifier의 약자로 MySQL 데이터베이스에서 커밋되는 각 트랜잭션과 함께 생성되고 트랜잭션에 연결되는 고유한 식별자를 의미합니다.
65 | - 이 식별자는 Master서버 뿐만 아니라 복제 대상에 속하는 Replica(Slave)서버에서도 고유합니다.
66 | - 따라서, Master의 트랜잭션 복제 시 Biglog 파일에 pos 정보 대신에 GTID를 사용하여, master-slave의 일관성을 쉽게 확인 할 수 있습니다.
67 |
68 | ### 참고 자료
69 | [클러스터링, 리플리케이션](https://code-lab1.tistory.com/205)
70 | [레디스 클러스터링](https://velog.io/@tngusqkr1/Redis-cluster-%EC%84%A4%EC%A0%95-1)
71 | [MySQL 리플리케이션 방식](https://hoing.io/archives/3111)
72 | [GTID](https://hoing.io/archives/18445)
73 |
--------------------------------------------------------------------------------
/Database/Database, key.md:
--------------------------------------------------------------------------------
1 | # 데이터 베이스 종류와 특징
2 |
3 | DB는 크게 RDB, NoSQL로 분류되고 RDB에는 mysql, oracle 등이있고
4 | noSQL은 몽고디비, 카산드라 등이 있습니다
5 | 이외에도 더많이 존재합니다.
6 |
7 | 특징은 아래와 같습니다.
8 |
9 | - DB는 실시간서비스 되므로 실시간으로 접근할수있다는 특성이있다.
10 |
11 | - DB상태는 계속 변경되고 항상 최신의 데이터를 유지하는 특성이있다.
12 |
13 | - 다수의 사용자가 동시에 같은 내용의 데이터를 이용할수있어야한다.
14 |
15 | - 사용자가 요구하는 데이터 내용으로 데이터를 찾는 특성이있다.
16 |
17 |
18 | # 키 종류와 특징
19 |
20 | - 슈퍼키: 유일성을 만족하는키 (학번+이름, 주민번호+학번)
21 |
22 | - 복합키 : 2개이상의 속성을 사용한키
23 |
24 | - 후보키: 유일성 ,최소성을 만족하는 키
25 |
26 | - 기본키 : NOT NULL, 유일해야한다.
27 |
28 | - 대체 키 : 후보키중 기본키가 아닌키
29 |
30 | - 외래키 : 테이블간 기본키를 참조하는 속성 , 테이블간 관계를 나타내기 위해 사용된다
31 |
32 |
33 | ### 데이터 구조가 자주변하는 데이터를 저장하기위해 RDB, NOSQL중 어떤것이 더 좋을까
34 |
35 | - RDBMS는 스키마를 미리정의하고 데이터타입도 정의하기때문에 구조화된 데이터를 저장하기에 좋고 NOSQL은 데이터 구조에 국한되지않고 데이터를 쉽게 분산저장할수있기때문에 NOSQL이 더 적절하다
36 |
37 |
38 | ### 슈퍼키, 후보키의 관계를 말해주세요
39 |
40 | 슈퍼키는 유일성을 만족하고, 후보키는 유일성, 최소성을 만족한다.
41 | 슈퍼키에서 최소성을 만족하면 후보키이다.
42 |
43 | ### Q) 외래키에 null이 들어갈수있나?
44 | 네 들어갈수있습니다. 그러나 일반적으로 허용하지않습니다.
45 | 최대한 지양해야 참조무결성을 지키는데 좋습니다.
46 |
47 |
48 |
49 | ### Q) nosql에 데이터가 어떻게 저장되는지 설명해주세요
50 |
51 | - Key-value 모델 : Object, JSON 자료형 형식으로 데이터를 쉽게쉽게 저장, 출력이 가능(가장 심플)
52 |
53 | - json Document 모델 : 테이블 대신 Collection이라는 문서 기반으로 데이터 분류, 저장
54 |
55 | - Graph 모델 : 데이터를 노드의 형태로 저장하고 노드간의 흐름 or 관계를 저장할 수 있음
56 |
57 |
58 | ### Q) 로그같은걸 남길때 NOSQL에서 어떤구조를 사용하는게 좋을까?
59 | https://kciter.so/posts/about-mongodb
60 | https://stackoverflow.com/questions/10525725/which-nosql-database-should-i-use-for-logging
61 | https://www.quora.com/Which-NoSQL-database-is-best-for-machine-log-data
62 |
63 | https://www.infoworld.com/article/3263773/how-to-choose-the-right-nosql-database.html
64 |
65 | column model? document model?
66 |
67 | > #### Q) 유일성과 최소성의 의미?
68 |
69 | 유일성: 유니크한 키값으로 하나의 키값으로 투플을 유일하게 식별할수있는 성질
70 |
71 | 최소성: 키를 구성하는 속성중 필요한 속성들로만 최소로 구성하는 성질
72 |
73 | > #### Q) 복합키는 최소성을 만족하나?
74 |
75 | 만족 할수도있고, 안할수도있다.
76 | 관련자료는 찾기힘들었다.
77 |
78 |
79 | ### Q) nosql과 RDB의 차이점
80 |
81 | - nosql은 트랜잭션을 지원하지않고 ACID성질도 가지고있지않다.
82 | - nosql은 테이블구조에 제약을 받지않아서 쉽게 분산저장할수있다.
83 | - RDB는 스키마로 인해 데이터 중복이 없기때문에 update가 많을때 유리할수있다.
84 | - nosql은 대량의 데이터를 빠르게 입출력할때 적합할수있다.
85 |
86 | > #### Q) CAP이론에 대해 설명해주세요
87 |
88 | 분산 DB의 세가지속성인 일관성(Consistency), 가용성(Availability), 분리 내구성(Partition tolerance) 을 나타낸다.
89 |
90 | - Consistency(일관성)
91 | - 모든 노드가 같은시간에 같은 데이터를 보여줘야한다는 의미
92 | - 쓰기동작이 완료된후 발생하는 읽기동작은 마지막으로 쓰여진 데이터를 리턴해야한다는걸 의미한다.
93 |
94 | - Availabilty(가용성)
95 | - 특정 노드가 장애나도 서비스가 가능해야한다
96 | - read,write등은 항상 성공적으로 리턴되어야한다
97 |
98 | - Partitions Tolerance(분리 내구성)
99 | - 노드간에 통신문제가 생겨 메시지를 주고받지 못하더라도 동작해야한다.
100 | - Availabilty는 특정 노드가 장애가 발생한상황이라면 해당특성은 노드의 상태는 정상이지만 네트워크 등의 문제로 연결이 끊어진 상황에대한 이야기다.
101 |
102 |
103 | > #### Q) DBMS가 무엇인가?
104 |
105 | - DB를 관리하는 시스템
106 | - 데이터를 계층또는 탐색 형식으로 저장한다
107 | - 파일시스템을 사용해 저장한다.
108 | - 테이블간 관계가 없다
109 | - 데이터에대한 보안을 제공하지않고, 정규화를 수행할수없어 데이터의 높은 중복성을 가질수있다.
110 |
--------------------------------------------------------------------------------
/Database/Normalization.md:
--------------------------------------------------------------------------------
1 | # Normalization (정규화)
2 |
3 | **정규화(Normalization)**
4 | - 정규화의 기본 목표는 **테이블 간에 중복된 데이터를 허용하지 않는다는 것**이며, 중복된 데이터를 허용하지 않음으로써 **무결성(Integrity)를 유지하고, DB의 저장 용량을 줄일 수 있다.**
5 | - 정규화를 하지 않았을 때에는 **이상(Anomaly) 현상**이 발생한다.
6 |
7 | **이상(Anomaly) 현상**
8 | - 이상 현상은 3가지로 구분한다.
9 | 1. **삽입 이상(Insertion Anomaly)** : 튜플 삽입 시 특정 속성에 해당하는 값이 없어 NULL을 입력해야 하는 현상
10 | 2. **삭제 이상(Deletion Anomaly)** : 튜플 삭제 시 같이 저장된 다른 정보까지 연쇄적으로 삭제되는 경우
11 | 3. **갱신 이상(Update Anomaly)** : 속성 값 갱신 시 중복된 데이터의 일부만 갱신되어 정보의 모순이 발생하는 현상
12 |
13 | **함수적 종속성(Functional Dependency)**
14 | - 정규화를 이해하기 전에 함수적 종속성에 대해서 이해 할 필요가 있다.
15 | - 함수 종속성은 어떤 릴레이션 R이 있을 때 X와 Y를 각각 속성의 부분집합이라고 가정했을 때, **X의 값을 알면 Y의 값을 알 수 있고**, **X의 값에 따라 Y의 값이 변경되는 Y는 X에 함수적 종속**이라고 한다.
16 | - **X를 결정자, Y를 종속자**라고 한다.
17 | - 함수적 종속관계에는 **완전 함수적 종속, 부분 함수적 종속, 이행적 함수 종속**이 있습니다.
18 | 1. **완전 함수적 종속**
19 | 
20 | - 종속자가 **기본키에만 종속되며, 기본키가 여러 속성으로 구성되어 있을 경우 기본키를 구성하는 모든 속성이 포함된 기본키의 부분집합에 종속**된 경우
21 | - 즉, 여러 속성으로 구성되어 있을 경우 **어떠한 속성이 기본키의 최소성을 만족시키는 경우**를 말한다.
22 |
23 | 2. **부분 함수적 종속(Partial Functional Dependency)**
24 | 
25 | - 릴레이션에서 종속자가 기본키가 아닌 다른 속성에 종속되거나, 기본키가 여러 속성으로 구성되어 있을 경우 기본키를 구성하는 속성 중 일부만 종속되는 경우
26 | - 즉, 여러 속성으로 구성되어 있을 경우 **어떠한 속성에 대해서 기본키의 최소성을 만족시키지 못하는 경우**를 말한다.
27 |
28 | 3. **이행 함수적 종속(Transitive Functional Dependency)**
29 | 
30 | - 릴레이션에서 X, Y, Z라는 3개의 속성이 있을 때 **X -> Y, Y -> Z 라는 종속 관계가 있을 경우, X -> Z가 성립될 때**를 말한다.
31 |
32 | ### 제 1 정규화
33 | 
34 | - `제 1 정규화`는 **테이블의 컬럼이 원자값(Atomic Value) 즉, 하나의 값을 갖도록 테이블을 분해하는 것**입니다.
35 | - 위 예시는 `제 1 정규형`을 만족하지 못하는 상황입니다. 해당 테이블을 정규화를 수행하게 되면 다음과 같이 변하게 됩니다.
36 | 
37 |
38 | ### 제 2 정규화
39 | 
40 | - **제 1 정규형을 만족하는 테이블에 대해서 완전 함수 종속을 만족하도록 테이블을 분해하는 것**입니다. 즉, **부분 함수 종속을 제거 하는 것**입니다.
41 | - 위 예시는 `제2 정규형`을 만족하지 못하는 상황입니다. 한 강좌가 한 강의실에서만 이루어질 경우, 현재 기본키가 학생번호, 강좌이름으로 구성되어 있을 때 강좌이름 만으로도 강의실을 구분 할 수 있기 때문입니다. 해당 테이블을 정규화를 수행하게 되면 다음과 같이 변하게 됩니다.
42 | 
43 |
44 | ### 제 3 정규화
45 | 
46 | - **제 2 정규형을 만족하는 테이블에 대해서 이행적 종속을 없애도록 테이블을 분해하는 것**입니다. 즉, **이행 함수 종속을 제거 하는 것**입니다.
47 | - 위 예시는 `제 3 정규형`을 만족하지 못하는 상황입니다. 기본키는 학생 번호이고, 한 명의 학생은 한 가지 강의밖에 듣지 못한다고 가정했을 때, 수강료가 강좌이름에 종속되어 있을 경우, 수강료는 학생번호에도 종속되는 이행종속이 발생되게 됩니다. 해당 테이블을 정규화를 수행하게 되면 다음과 같이 변하게 됩니다.
48 | 
49 |
50 | ### BCNF 정규화
51 | 
52 | - **제 3정규형을 만족하는 테이블에 대해서 모든 결정자가 후보키가 되도록 테이블을 분해하는 것입니다.** 즉, 테이블 내 모든 속성이 유일성과 최소성을 만족하도록 만드는 정규화입니다.
53 | - 위 예시는 기본키가 학생번호 특강이름으로 이루어졌을 때, 학생번호 특강이름이 교수를 결정합니다. 하지만 교수가 한 가지 강의만 진행한다고 가정했을 때, 교수또한 특강이름의 결정자가 되지만 해당 테이블에서는 중복된 값이 발생해서 유일성을 위배하므로 후보키가 될 수 없습니다. 해당 테이블을 정규화를 수행하게 되면 다음과 같이 변하게 됩니다.
54 | 
55 |
56 | ### Q) 프로젝트를 진행하면서 정규화 혹은 역정규화의 필요성을 느껴서 해보신 경험이 있다면 얘기해주세요.
57 | - **제 3 정규형**을 위반하여 테이블의 조회 성능을 높인 경험이 있습니다. 통합 테이블 기법을 사용하여 슈퍼타입 서브타입에 대한 공통 부분에 대해서는 유지하고 추가적으로 어떤 세부 타입에 따라 값이 별개로 필요한 상황이었는데, 이때 세부 항목에 대한 필드가 많지 않을 것이라고 판단해서 테이블 내부에 구분하기 위한 Dtype 필드를 명시하고 해당 Dtype 필드에 해당 값들을 종속시켜 해당 값들이 기본 키에도 종속적이지만 Dtype에도 종속적인 이행 종속을 지키지 않았던 경험이 있습니다.
58 |
59 | ### Q) 외래키를 꼭 사용해야 하는지, 아니면 사용하지 않아도 되는지에 대한 의견을 말씀해주세요.
60 | - 외래키를 사용하지 않는 다는 것은 테이블과 관련이 있는 데이터들을 관계로 인한 테이블을 구성하지 않고, 조인에 의한 성능 저하로 인해 한 테이블에 관계를 지정할 수 있는 모든 데이터들을 한 테이블에 넣는 것으로 보입니다.
61 | - 이럴 경우에 해당 테이블이 어떠한 역할을 하는지 파악 하기가 어려우며, 이상현상등이 발생할 가능성이 높고, 또 테이블에 어떠한 필드가 추가되었을 때 수정하기가 어렵다는 단점이 존재합니다. 물론 테이블을 통합 했을 때 필드가 적다면 조인을 하지 않아 조회 성능을 향상 시킬 수 있다는 장점이 있기 때문에, 필드 수 혹은 조인의 횟수에 대해서 고민해서 트레이드 오프를 잘 판단해야 된다고 생각합니다.
62 |
63 | ### Q) 정규화를 계속 진행을 하였을 때의 단점이 무엇인가요?
64 | - 정규화를 계속해서 진행을 한다는 것은 테이블을 계속해서 분할을 하는 것을 의미합니다. 테이블을 계속해서 분할 한 상탸에서 원하는 데이터들을 조회하기 위해서는 조인 기법을 이용하여 테이블을 조회를 해야 합니다.
65 | - 이때, 인덱스가 없는 상황에서 테이블을 조인하게 되었을 때, 어떠한 조인 기법을 택하냐에 따라 다르지만 조인으로 인해 성능저하가 발생합니다.
66 | - 따라서, 정규화를 진행하는 것이 무조건적으로 좋다 라고 말하기는 어렵습니다.
67 |
68 | ### 참고 자료
69 | [[정규화]https://mangkyu.tistory.com/110](https://mangkyu.tistory.com/110)
70 | [[정규화2]https://code-lab1.tistory.com/48](https://code-lab1.tistory.com/48)
71 | [[이상현상]https://code-lab1.tistory.com/47](https://code-lab1.tistory.com/47)
72 | [[함수적 종속]https://dodo000.tistory.com/20](https://dodo000.tistory.com/20)
73 |
--------------------------------------------------------------------------------
/Database/Partitioning & Sharding.md:
--------------------------------------------------------------------------------
1 | # 파티셔닝, 샤딩
2 | 파티셔닝 : DB 테이블을 열에 대해서 수직으로 혹은 행에 대해 수평으로 나누는 두 가지 방법으로 작은 부분으로 여러 개 나누는 것
3 |
4 | 샤딩 : 동일한 스키마를 가지고 있는 여러대의 데이터베이스 서버들에 데이터를 작은 단위로 나누어 분산 저장하는 기법
5 |
6 | ### Q) 파티셔닝을 나누는 기준에 대해 설명해주세요.
7 | - `Vertical Partitioning`(수직) : Column 기준
8 | **장점**
9 | - 자주 사용하는 칼럼을 분리하여 성능을 향상할 수 있다.
10 | - 같은 타입의 데이터가 저장되어 데이터 압축률을 높일 수 있다.
11 | - 조회 시 필요 없는 칼럼을 조회하지 않아도 되므로 성능상의 이점이 있다.
12 |
13 | **단점**
14 | - 데이터를 찾는 과정이 기존보다 복잡하므로 Latency 증가
15 |
16 | - `Horizontal Partioning`(수평) : Row 기준
17 | **장점**
18 | - 데이터의 개수를 기준으로 나누어 파티셔닝한다.
19 | - 데이터의 개수와 인덱스의 개수가 줄어들어 성능이 향상된다.
20 |
21 | **단점**
22 | - 데이터를 찾는 과정이 기존보다 복잡하므로 Latency 증가
23 |
24 | ### Q-1) 수직 파티셔닝이 정규화와 비슷한 것 같은데, 무슨 차이가 있을까요?
25 | - 별개로! 정규화는 중복된 데이터를 분리하기 위해 사용, 수직 파티셔닝은 이 테이블에 대해 정규화가 다 끝나고 성능상 이점을 보기 위해 그 때 분리함.
26 |
27 | ### Q-2) 수평 파티셔닝과 샤딩이 비슷한데, 샤딩의 장단점에 대해 설명해주세요.
28 | - 파티셔닝은 모든 데이터를 동일한 컴퓨터에 저장하지만, 샤딩은 데이터를 서로 다른 컴퓨터에 분산한다는 점에서
29 | - 장점 : 부하가 분산됩니다.
30 | - 단점
31 | - 서버를 나눈 것 == 분산된 서버마다 연결해야하므로 수평 파티셔닝보다 접근시간이 더 오래 걸립니다.
32 | - 하나의 서버가 고장났을 때, 문제에 대한 대처가 복잡하다. 데이터 무결성이 지켜지지 않는다.
33 |
34 | ### Q) 샤딩을 어떤 기준으로 해야 효율적일까요?
35 | - 샤딩이란 작은 단위로 나누어 분산 저장하는 기법, 이 때 작은 단위 : 샤드
36 | - Hash Sharding
37 | - PK값의 모듈러 연산 결과를 통해 샤드를 결정하는 방식
38 | - 데이터 개수가 변경될 때 해시 함수도 변경해야하고, 따라서 데이터의 재 정렬이 필요
39 | - 총 데이터베이스 수가 정해져있을 때 유용
40 |
41 | - Range Sharding
42 | - PK 값을 범위로 지정하여 샤드를 지정하는 방식
43 | - Hash Sharding 대비 데이터베이스 증설 작업에 큰 리소스가 소요되지 않는다.
44 | - 특정한 데이터베이스에만 부하가 몰릴 수 있다는 단점
45 |
46 | ### Q) 어떤 경우에 수직 파티셔닝이 쓰이면 좋을까요?
47 | - 조회 시 필요없는 칼럼이 있는 경우, 칼럼을 제외해도 되므로 칼럼별로 분류할 때 사용 가능
48 | - 필요없는 칼럼이 없는 경우, 구할 때 마다 메모리에 값을 올리는 게 부담이 있으므로 자주 사용하는 컬럼만 파티셔닝하여 메모리에 올릴 때 유용유용
49 |
50 | ### Q) 샤딩은 언제 도입을 고려해볼까요?
51 | - 데이터베이스에 들어온 양이 어마무시하게 많을 때
52 |
53 | ### Q) 파티셔닝 종류에 대해 설명해주세요.
54 | 
55 |
56 | **List Partitioning 리스트 파티셔닝**
57 | - 관리자가 직접 지정하는 방식으로 잘 설정한 경우에는 빠른 성능이 보장되지만, 잘못 설정된 경우에는 성능 저하됨. (ex 지역별)
58 | - 많은 SQL에서 해당 칼럼의 조건이 많이 들어오는 경우 유용
59 |
60 | **Range Partitioning 범위 파티셔닝**
61 | - 데이터 내의 특정 범위 내역을 정하여 파티셔닝 해주는 방법
62 | - 장점 : 사용하기 쉬움
63 | - 단점 : 데이터가 균일하게 분포되지 못해서 성능 저하가 생길 수 있다 (ex) 우편 번호, 날짜 등의 데이터에 적합)
64 |
65 | **Hash Partitioning 해시 파티셔닝**
66 | - 파티션 키(Key)의 해시 값에 의한 파티셔닝
67 | - range 파티션에서 범위 분포에 대한 단점을 보완
68 | - hash 함수가 데이터를 균등하게 분포시켜 성능 하락을 방지
69 | - 데이터의 관리가 어렵다는 단점
70 |
71 | **Composite Partitioning 복합 파티셔닝**
72 | - 위 파티셔닝 종류 중 두개 이상을 사용하는 방식
73 | - 큰 파티션에 대한 I/O 요청을 여러 파티션으로 분산할 수 있다.
74 | - 예를 들면 먼저 범위 분할하고, 다음에 해시 분할 같은 것을 생각할 수 있다.
75 |
76 | ### Q-1) 파티셔닝을 사용한다는 것은 데이터를 분리해서 조회 속도를 향상시키기 위함인데, 해시 파티셔닝은 결국 어떤 파티션에 어떤 데이터가 있는 지 모르니 모든 테이블을 찾는 경우가 생길 것 같습니다. 그럼 해시분할은 왜 사용할까요?
77 | - 해시 분할의 경우 mod를 사용하기때문에 mod를 이용해서 값을 찾을 수 있고 키를 문자나 날짜로 설정할 수도 있는데 이럴 경우에는 숫자화를 해준다음 mod를 적절하게 사용해서 찾을 수 있습니다.
78 |
79 | ### Q) 파티셔닝의 3가지 이점에 대해 설명해주세요.
80 | - 테이블 분산을 통해, 쓰기 작업 시 작업이 분산돼 성능이 향상됩니다.
81 | - 물리적으로 여러 테이블로 분산하여 저장되지만, 사용자는 마치 하나의 테이블에 접근하는 것과 같이 사용
82 | - 큰 테이블을 나눠 사용하므로, 관리하기 쉽습니다.
83 |
84 |
85 |
--------------------------------------------------------------------------------
/Database/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/Database/sql query.md:
--------------------------------------------------------------------------------
1 | ### 쿼리 수행 순서
2 | FROM -> WHERE -> SELECT -> GROUP BY -> HAVING -> ORDER BY -> LIMIT 순으로이루어 져 있다. GROUP BY 의 위치는 무조건 FROM, WHERE 뒤에 위치해야 한다.
3 |
4 |
5 | ### HAVING과 WHERE의 차이를 설명해주세요.
6 |
7 | - 그룹을 나타내는 결과 집합의 행에만 적용된다는 점에서 차이가 있다.
8 | - WHERE 절은 개별 행에 적용됩니다. 쿼리에는 WHERE 절과 HAVING 절이 모두 포함될 수 있다.
9 |
10 | ### group by의 역할에 대해 설명해주세요
11 | 테이블에서 특정 구조로 그룹을 지어주는 역할을 하는 구문
12 |
13 | ### DELETE, TRUNCATE, DROP의 차이를 설명해주세요
14 |
15 | DELETE는 테이블의 컬럼을 삭제할수있고 테이블 용량은 줄어들지않는다.삭제후 되돌릴수없다.
16 | TRUNCATE는 테이블을 용량이 줄어들고 인덱스도 삭제된다. 삭제후 되돌릴수없다.
17 | DROP은 테이블을 삭제한다. 삭제후 되돌릴수없다.
18 |
19 | ### INSERT/ UPDATE/ DELETE/ LIKE/ null
20 |
21 | ```sql
22 | INSERT INTO table_name (column1, column2, column3,...) VALUES (value1, value2, value3,...)
23 |
24 | UPDATE 테이블명 SET 컬럼1=컬럼1의 값, 컬럼2=컬럼2의 값 WHERE 대상이 될 컬럼명=컬럼의 값
25 |
26 | DELETE FROM 테이블명 [WHERE 삭제하려는 칼럼 명=값]
27 |
28 | 아디다스로 시작하는 데이터 검색
29 |
30 | select * from tbl_board where title like '아디다스%';
31 |
32 | 아디다스로 끝나는 데이터 검색
33 |
34 | select * from tbl_board where title like '%아디다스';
35 |
36 | 아디다스가 들어가는 데이터 검색
37 |
38 | select * from tbl_board where title like '%아디다스%';
39 | ```
40 |
41 | #### 평균, 합계, 최고, 최저
42 | ```sql
43 | 합 : select sum(컬럼이름) from 테이블 where 조건
44 |
45 | 평균 : select avg(컬럼이름) from 테이블 where 조건
46 |
47 | 최고 : select max(컬럼이름) from 테이블 where 조건
48 |
49 | 최저 : select min(컬럼이름) from 테이블 where 조건
50 |
51 | ```
52 |
53 | #### 테이블 정보
54 | ```sql
55 | SHOW TABLE STATUS;
56 | ```
57 | #### 중복 제거
58 | distinct
59 |
60 | ### **IN, NOT IN 설명**
61 | IN : where 절에서 찾으려는 모든값을 SELECT해준다
62 | NOT IN: 입력한 값을 제외한 값을 SELECT해줄수있게 해준다.
63 |
64 | mysql 기준
65 | ### **숫자에서 문자로**
66 | ```sql
67 | select cast(2 as char(1));
68 | ````
69 | ### **문자에서 숫자로**
70 | ```sql
71 | SELECT CAST('123' AS UNSIGNED);
72 | // 문자열을 부호없는 정수형으로
73 | ```
74 | ### **문자에서 날짜로**
75 | ```sql
76 | STR_TO_DATE('2000-01-31', '%Y-%m-%d')
77 | ```
78 | ### **날짜 관련 함수**
79 | 너무많아서..
80 | https://jang8584.tistory.com/7
81 |
82 | ### **분석 함수**
83 | ROW_NUMBER(): 결과에 순번, 순위를 매기는 함수
84 | ```sql
85 | SUM(sal) OVER(PARTITION BY job ORDER BY empno)
86 | ```
87 |
88 | - **누적 함수**
89 | ```sql
90 | SUM(sal) OVER(PARTITION BY job ORDER BY empno)
91 | ```
92 | 합을구할때는 SUM만쓰면되는데 조회순서대로 누적할때는 OVER까지 사용한다.
93 |
--------------------------------------------------------------------------------
/Java/AccessModifier.md:
--------------------------------------------------------------------------------
1 | # 접근제어자
2 |
3 | ### 1. 접근제어자에 대해서 설명해주세요.
4 | * 접근제어자는 **클래스 또는 클래스의 내부의 멤버들에 사용되어 해당 클래스나 멤버들을 외부에서 접근하지 못하도록 접근을 제한하는 역할을 수행하는 것**입니다.
5 | * 자바에는 **public**, **default**, **protected**, **private** 총 4가지로 구성이 되어 있습니다.
6 |
7 | 
8 |
9 | ### 2. DI 사용 시 어떤 접근제어자를 사용하여 개발을 하는가
10 | - 외부 객체에서 내부 객체에 속성에 직접 접근을 하면 안되기 때문에 private를 사용해주어야 하며, 추가적으로 해당 객체 내에 구성클래스가 있는 경우 의존 주입을 무조건 받도록 하는 것이 좋기 때문에 final 키워드를 사용해서 객체 생성 시 컴파일 단계에서 체크하도록 하여 의존 주입을 잊지 않도록 합니다.
11 |
12 | #### Q) 스프링 프레임워크가 없는 세상이라면 DI를 어떻게 구현 할 것인가.
13 | - 클라이언트가 요청 할 때마다 생기는 것이 아닌 애플리케이션이 실행 할 때만 필요한 것이고, 그 클래스의 수가 많지 않다면 직접 new 키워드를 사용해서 직접 주입을 해 줄것이고 그 외에 상황에서는 의존주입 받아야 하는 클래스에 대해서 직접 싱글톤 패턴을 통해 구현을 하고 동시성 처리를 하여 구현을 할 것 같습니다.
14 | - 즉, **IOC(Inversion Of Control, 제어의 역전)** 를 직접 구현해서 사용을 할 것 같습니다.
15 |
16 | **[내용 및 사진 출처]**
17 | - https://www.codestates.com/blog/content/%EA%B0%9D%EC%B2%B4-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D-%ED%8A%B9%EC%A7%95
18 |
19 |
--------------------------------------------------------------------------------
/Java/CollectionFramework.md:
--------------------------------------------------------------------------------
1 | # 컬렉션 프레임 워크
2 | ### 1. 자바의 컬렉션 프레임워크 란
3 | 
4 | * 컬렉션은 **다수의 요소를 하나의 그룹으로 묶어 효율적으로 저장하고, 관리할 수 있는 기능을 제공하는 일종의 컨테이너** 이다.
5 | * 가변적인 크기를 갖고, 데이터의 삽입, 탐색, 정렬에 대한 편리한 API를 다수 제공한다.
6 | * JDK 1.2 버전부터 java.util 패키지에서 지원하고 이전에도 Vector, Stack, Hash Table 등이 존재했지만 통일성이 없고 표준화 된 인터페이스가 존재하지 않았다.
7 | * 컬렉션 프레임워크에는 크게 리스트(List), 큐(Queue), 집합(Set), 맵(Map)으로 분류 할 수 있다.
8 |
9 | #### Q) Set과 Map은 중복을 허용하지 않는다. 그럼 Set과 Map은 어떤 방식으로 중복을 검사하는가
10 | ```java
11 | public class HashSet extends AbstractSet
12 | implements Set, Cloneable, java.io.Serializable {
13 | // 일부 코드 생략
14 | private transient HashMap map;
15 |
16 | public HashSet() {
17 | map = new HashMap<>();
18 | }
19 | }
20 | ```
21 | - Set과 Map 둘 다 동일하게 HashTable을 사용합니다.
22 | **Map은 형식으로 Value에 값이 들어가 있는 경우가 많습니다.**
23 | **Set은 무조건 로 저장**합니다. 해시 함수에 대한 HashValue를 키로 사용함으로써, 동일한 키가 존재하면 equals() 메서드를 통해 중복된 값인지 확인합니다.
24 | #### Q) 만약 사용자가 정의한 타입이면 어떻게 같은지를 구분하는가
25 | - 사용자가 정의한 Reference type은 Object에 구현되어 있는 동등성 비교(Equals)와 hashcode() 오버라이딩 함으로써 객체가 동일한지 판단할 수 있도록 해줍니다.
26 | #### Q) hashcode()의 default 값은 무엇인가요?
27 | - hashCode의 구현부는 JDK에 달려있다고 합니다. 대체적으로 객체의 메모리 주소라고 많이 알려져있는데, 그렇지 않다고 합니다.
28 |
29 | #### Q) HashMap, LinkedHashMap, TreeMap에 대해서 설명해주세요.
30 | - **HashMap**은 가장 기본적인 Map 자료구조로 `` 로 구성되어 있습니다. 하지만 iterator를 사용하여 **출력 시 순서가 보장되지 않습니다.**
31 | - **LinkedHashMap**은 HashMap에서 순서가 보장되지 않는 단점을 해결하여 **순서가 보장**되도록 하는 Map 자료구조입니다.
32 | - **TreeMap**은 Map에 저장 된 키에 대해서 **이진 트리를 기반으로 정렬**되어 있는 Map 자료구조를 말합니다.
33 |
34 | #### Q) 세 가지 Map 자료구조에 대해서 어떤 것을 더 자주 사용하는가
35 | - HashMap을 사용합니다. Map 자료구조는 ``를 통해 찾고자 하는 값을 O(1) 로 찾아낼 수 있다는 장점이 있습니다. Linked 혹은 Tree는 부가적인 기능이 추가된 것이여서, 만약 필요하다면 다른 컬렉션을 사용 할 것 같습니다.
36 | #### Q) HashMap, LinkedHashMap, TreeMap에 탐색에 대한 속도 차이가 존재하는가
37 | - HashMap, LinkedHashMap 같은 경우에는 O(1) 만큼 동일하게 소요되지만, LinkedHashMap 같은 경우에는 Linked-list를 유지하는 비용이 추가로 발생됩니다.
38 | - TreeMap은 RedBlackTree로 구성되어 있고, 트리로 구성되어서 삽입, 탐색하는데 O(logN) 만큼의 시간이 소요됩니다.
39 |
40 | #### Q) HashMap, HashTable, ConcurrentHashMap의 차이점
41 | **[HashMap]**
42 | - HashMap은 **동기화 처리를 하지 않는 자료구조이기에 Thread-safe 하지 않습니다.
43 | - **싱글 쓰레드 환경에서 사용**을 해야합니다.
44 | - 동기화 처리를 하지 않아 **HashTable과 ConcurrentHashMap에 비해 데이터를 찾는 속도가 빠릅니다.**
45 |
46 | **[HashTable]**
47 | - HashTable이 HashMap 보다 먼저 나왔는데, **HashTable은 동기화 처리**가 되어있습니다.
48 | - HashMap은 key와 value에 null을 허용하는 반면, **HashTable은 null을 허용하지 않습니다**.
49 | - **인스턴스 메서드에 synchronized** 가 걸려있습니다.
50 | ```java
51 | public synchronized V put(K key, V value) {
52 | if (value == null) {
53 | throw new NullPointerException();
54 | }
55 |
56 | Entry,?> tab[] = table;
57 | int hash = key.hashCode();
58 | int index = (hash & 0x7FFFFFFF) % tab.length;
59 | @SuppressWarnings("unchecked")
60 | Entry entry = (Entry)tab[index];
61 | for(; entry != null ; entry = entry.next) {
62 | if ((entry.hash == hash) && entry.key.equals(key)) {
63 | V old = entry.value;
64 | entry.value = value;
65 | return old;
66 | }
67 | }
68 |
69 | addEntry(hash, key, value, index);
70 | return null;
71 | }
72 | ```
73 |
74 | **[ConcurrentHashMap]**
75 | - ConcurrentHashMap은 **HashTable의 동기화 성능을 최적화 한 자료구조**입니다.
76 | - HashTable은 메서드 자체에 동기화 처리를 하였지만, **ConcurrentHashMap은 동기화 블럭을 사용하여 한 Entry에 대해서만 동기화**가 이루어집니다.
77 |
78 | #### Q) ArrayList, LinkedList를 각각 어떤 상황에서 사용 할 것인가
79 | - ArrayList는 인덱스를 가지고 있어 인덱스로 조회를 하는 경우에 빠르게 사용 할 수 있다는 장점이 있습니다. 하지만 중간에 값을 추가하거나 삽입하는 과정에서 쉬프트로 인해 많은 비용이 발생하고 데이터가 추가되는 과정에서 GC와 백업에 대한 연산에 있어서도 추가적인 비용이 발생 할 수 있어 정적인 조회가 많은 경우에 사용합니다.
80 | - LinkedList는 ArrayList와 달리 중간 삽입, 삭제 연산이 빠르지만 탐색 속도가 ArrayList에 비해서 떨어지기때문에 중간 삽입, 삭제 연산이 많다면 LinkedList를 사용합니다.
81 |
82 | #### Q) ArrayList의 capacity가 꽉찼을 경우에 발생하는 일을 설명해주세요.
83 | - ArrayList는 capacity가 초과되면 데이터를 백업하고 메모리 공간을 비웁니다. 이 과정에서 GC가 발생하고, 추가적인 메모리 공간을 늘려 새로운 메모리 공간에 다시 데이터를 적재합니다.
84 |
85 | #### Q) HashMap의 충돌에 대해서 설명해주세요.
86 | - 자바에서는 해시 충돌에 대해서 Separate Chaning 방식을 택하고 있고, 하나의 해시버킷에 8개의 키-값 쌍이 모이면 RB Tree로 변경됩니다.
87 |
88 | #### Q) 해시 충돌에 확률을 줄이기 위한 방법
89 | - 자바에서는 해시 버킷의 개수의 기본값은 16이고 임계점(loadFactor 0.75)에 도달 할 때마다 버킷 개수의 크기를 두 배씩 증가시킵니다. 버킷의 최대 개수는 2^30 입니다.
90 | - 하지만 이때, 해시 버킷의 개수가 2^a 형태가 되므로 보조 해시 함수의 % M 을 사용할 경우 하위 a개의 비트만 사용하게 되어서 해시 충돌이 쉽게 발생할 수 있다는 문제가 있습니다.
91 |
92 | - 자바에서는 해시 충돌을 줄이기 위해 보조 해시 함수를 사용하고 있고, java 7 에서는 다음과 같은 보조 해시 함수를 사용하였습니다.
93 | ```java
94 | final int hash(Object k) {
95 | // Java 7부터는 JRE를 실행할 때, 데이터 개수가 일정 이상이면
96 | // String 객체에 대해서 JVM에서 제공하는 별도의 옵션으로
97 | // 해시 함수를 사용하도록 할 수 있다.
98 | // 만약 이 옵션을 사용하지 않으면 hashSeed의 값은 0이다.
99 | int h = hashSeed;
100 | if (0 != h && k instanceof String) {
101 | return sun.misc.Hashing.stringHash32((String) k);
102 | }
103 | h ^= k.hashCode();
104 | // 해시 버킷의 개수가 2a이기 때문에 해시 값의 a비트 값만을
105 | // 해시 버킷의 인덱스로 사용한다. 따라서 상위 비트의 값이
106 | // 해시 버킷의 인덱스 값을 결정할 때 반영될 수 있도록
107 | // shift 연산과 XOR 연산을 사용하여, 원래의 해시 값이 a비트 내에서
108 | // 최대한 값이 겹치지 않고 구별되게 한다.
109 | h ^= (h >>> 20) ^ (h >>> 12);
110 | return h ^ (h >>> 7) ^ (h >>> 4);
111 | }
112 | ```
113 | - java 8 부터는 굉장히 단순해졌는데 해시 값과 해시 값에 대한 시프트 연산으로 >>> 16 만큼 이동한 값과 XOR 연산을 통한 보조 해시 함수를 사용하고 있습니다.
114 | ```java
115 | static final int hash(Object key) {
116 | int h;
117 | return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
118 | }
119 | ```
120 |
121 | ### 참고 이미지
122 | - [사진1](https://hudi.blog/java-collection-framework-1/)
123 | - [Hash 참고자료](https://d2.naver.com/helloworld/831311)
--------------------------------------------------------------------------------
/Java/Error & Exception.md:
--------------------------------------------------------------------------------
1 | # Error & Exception
2 | 자바의 예외는 크게 3가지로 나눌 수 있습니다.
3 |
4 | 
5 |
6 | - 1. **에러(Error)**:
7 | - 에러(Error)는 시스템에 무엇인가 비정상적인 상황이 발생한 경우에 사용됩니다. 주로 자바 가상 머신에서 발생시키는 것이며 예외와 반대로 이를 애플리케이션 코드에서 잡을 수 없습니다.
8 | - (ex) 메모리 부족(OutofMemoryError), 스택오버플로우(StackOverflowError)
9 |
10 | - 2. **예외**
11 | - 예외(Exception)란 입력 값에 대한 처리가 불가능하거나, 프로그램 실행 중에 참조된 값이 잘못된 경우 등 정상적인 프로그램의 흐름을 어긋나는 것을 말합니다. 자바에서 예외는 개발자가 직접 처리할 수 있기 때문에 예외 상황을 미리 예측하여 핸들링할 수 있습니다.
12 |
13 | > 컴파일러가 에러처리를 확인하지 않는 RuntimeException 클래스들은 unchecked 예외라고 부르고
14 | 예외처리를 확인하는 Exception 클래스들은 checked 예외라고 부릅니다.
15 |
16 | - 2-1. **체크 예외(Checked Exception)** :
17 | - Checked Exception은 RuntimeException을 상속하지 않은 클래스입니다.
18 | - 명시적인 예외 처리를 해야 합니다.
19 | - 컴파일 시점에 확인할 수 있습니다. (=> 따라서 반드시 에러 처리를 해야하는 특징(try/catch or throw)을 가집니다. )
20 | - 트랜잭션 안에서 동작할 때 Checked Exception이 발생하면 Rollback 되지 않는다는 특징이 있습니다.
21 | - **기본적으로 Checked Exception은 복구가 가능하다는 메커니즘** 을 가집니다.
22 | - 복구가 가능하니 트랜잭션 도중 에러가 발생하더라도 롤백이 발생하지 않습니다.
23 | - 예를 들어, 특정 이미지 파일을 찾아서 전송해 주는 함수에서 이미지를 찾지 못 했을 경우 기본 이미지를 전송한다는 복구 전략을 가질 수 있습니다.
24 | - 즉, **복구가 가능하니 Rollback은 진행하지 않는다**는 의미이다.
25 | - (ex) 존재하지 않는 파일의 이름을 입력(FileNotFoundException)
26 | 실수로 클래스의 이름을 잘못 적음(ClassNotFoundException)
27 |
28 | - 2-2. **언체크 예외(Unchecked Exception)** :
29 | - Unchecked Exception은 RuntimeException을 상속한 클래스입니다.
30 | - 명시적인 예외 처리를 하지 않습니다. 즉, 에러 처리를 강제하지 않습니다.
31 | - 런타임 시점에 확인할 수 있습니다. ( RuntimeException의 하위 클래스이기에 실행 중에(runtime) 발생할 수 있는 예외를 의미합니다. )
32 | - 트랜잭션 안에서 동작할 때 Unchecked Exception이 발생하면 롤백된다는 특징이 있습니다.
33 | - (ex) 열의 범위를 벗어난(ArrayIndexOutOfBoundsException)
34 | 값이 null이 참조변수를 참조(NullPointerException)
35 |
36 | 
37 |
38 |
39 | ### Q) Checked Exception 과 Unchecked Exception 의 transaction 예외 처리 방식을 설명해주세요.
40 | - Checked Exception : 기본적으로 commit 이 됩니다. (무조건 처리돼야 하는 exception)
41 | - Unchecked Exception : rollback 이 됩니다. (무조건 처리돼야 하지 않아도 되는 exception)
42 |
43 | ### Q-1) @Transactional 는 어떻게 구현되나요?
44 | - proxy 원리를 사용해서 구현됩니다.
45 | - 프록시 패턴을 사용하는 이유 : 프록시 객체는 원래 객체를 감싸고 있는 객체로, 원래 객체와 타입은 동일합니다. 프록시 객체가 원래 객체를 감싸서 client의 요청을 처리하게 하는 패턴입니다.
46 | - 프록시 패턴을 통해 접근 권한을 부여할 수 있습니다.
47 | - 프록시 패턴을 통해 부가 기능을 추가할 수 있습니다.
48 | ### Q-2) @Transactional 이 붙지 않은 메소드의 내부에서 @Transactional 이 붙은 메소드를 사용할 시, 이 내부 메소드도 @Transactional이 적용될까요?
49 | - 적용되지 않습니다.
50 | - 예시는 아래와 같습니다.
51 |
52 | ```java
53 | public class BookImpl implements Books {
54 | public void addBooks(List bookNames) {
55 | bookNames.forEach(bookName -> this.addBook(bookName));
56 | }
57 |
58 | @Transactional
59 | public void addBook(String bookName) {
60 | Book book = new Book(bookName);
61 | bookRepository.save(book);
62 | book.setFlag(true);
63 | }
64 | }
65 | ```
66 | - 위와 같은 상황에서 addBooks메서드의 내부에서 호출하는 addBook 메서드의 @Transactional 어노테이션이 적용되지 않습니다.
67 |
68 | - Spring은 AOP를 이용해 `@Transactional` 어노테이션을 선언한 메서드가 실행되기 전 transaction begin을 삽입하고, 메서드 실행 후에 Transaction commit 코드를 삽입하여, 객체 변경감지를 수행하도록 유도합니다.
69 |
70 | - Spring의 코드 삽입 방식은 크게 2가지가 있습니다.
71 |
72 | - 1) 바이트 코드 생성(CGLIB)
73 | - 2) 프록시 객체 사용
74 | - 2가지 방법 중에 Spring은 기본적으로 프록시 객체 사용 방식을 선택합니다. (SpringBoot는 기본적으로 바이트 코드 생성 방식 사용)
75 |
76 | - 원리는 아래 코드와 같습니다. 프록시 객체로 우리가 만든 메서드를 한번 감싸서, 메서드 위 아래로 코드를 삽입합니다.
77 |
78 | ```java
79 | public class BooksProxy {
80 | private final Books books;
81 | private final TransactonManager manager = TransactionManager.getInstance();
82 |
83 | public BooksProxy(Books books) {
84 | this.books = books;
85 | }
86 |
87 | public void addBook(String bookName) {
88 | try {
89 | manager.begin();
90 | books.addBook(bookName);
91 | manager.commit();
92 | } catch (Exception e) {
93 | manager.rollback();
94 | }
95 | }
96 | }
97 | ```
98 | - 위와 같은 코드로 인해 우리가 BookImpl클래스를 사용할 때, 스프링이 제공하는 BookProxy 객체를 사용하게 되며, 프록시 객체가 제공하는 addBook 메서드를 사용해야만 트랜잭션 처리가 수행되게 됩니다.
99 |
100 | - **@Transactional이 수행되지 않은 이유**
101 | - BooksProxy 가 addBooks 메서드를 수행하면, 아래와 같은 순서로 작동됩니다.
102 | - `BookProxy::addBooks -> BooksImpl::addBook`
103 |
104 | - 즉, **프록시 객체가 아닌 실제 BookImpl 객체의 함수를 호출하게 되므로 해당 메서드는 트랜잭션으로 감싸지지 않은 상태**로 @Transactional 어노테이션 기능이 수행되지 않는 것입니다.
105 |
106 | - **해결 방법**
107 | - 1. @Transactional 어노테이션 메서드는 클래스 내부적으로 사용하지 말고, 밖에서 사용합니다. (권장)
108 | - 2. 굳이 내부적으로 사용하려면, 자기 자신의 Proxy 객체를 사용하여 처리합니다. (아래 코드 참조)
109 |
110 | ```java
111 | @Service
112 | public class BooksImpl implements Books {
113 | @Autowired
114 | private Books self;
115 |
116 | public void addBooks(List bookNames) {
117 | bookNames.forEach(bookName -> self.addBook(bookName)); // this 가 아닌 변수 self 로
118 | }
119 |
120 | @Transactional
121 | public void addBook(String bookName) {
122 | Book book = new Book(bookName);
123 | bookRepository.save(book);
124 | book.setFlag(true);
125 | }
126 | }
127 | ```
128 | - 위 코드는 Books 인터페이스를 이용하여 BooksProxy 인스턴스를 주입할 수 있도록 유도합니다.
129 | - 그 후, 프록시 객체의 addBook 메서드 사용을 통해 @Transactional 어노테이션 기능을 사용할 수 있게 합니다.
130 |
131 | #### 사진 & 내용 출처
132 |
133 | https://steady-coding.tistory.com/583
134 |
135 | https://velog.io/@chullll/Transactional-%EA%B3%BC-PROXY
136 |
137 | https://velog.io/@ddongh1122/Spring-Transactional-%ED%81%B4%EB%9E%98%EC%8A%A4-%EB%82%B4%EB%B6%80-%ED%98%B8%EC%B6%9C-%EB%AF%B8%EC%9E%91%EB%8F%99-%EC%9D%B4%EC%8A%88
138 |
--------------------------------------------------------------------------------
/Java/GC.md:
--------------------------------------------------------------------------------
1 | # GC
2 | 가비지 컬렉터은 가바 가상 머신내의 실행 엔진 영역에 존재합니다.
3 | **Heap 영역에서 동적으로 할당했던 메모리 중 필요 없게 된 메모리 객체**(garbage)를 모아 **주기적으로 제거**하는 프로세스입니다.
4 | - 여기서 동적으로 할당했던 메모리 영역 : 프로그램 런타임에 사용되는 Heap 영역 메모리
5 | - 필요 없게 된 영역 : 어떤 변수도 가리키지 않게 된 영역
6 |
7 | ### Q) GC의 작동원리에 대해 설명해주세요.
8 | - ### Q-1) 언제 GC가 작동될까요? ( = Garbage가 될 때 )
9 | - 참조되는 객체가 **더 이상 참조되지 않을 때** GC 처리를 합니다.
10 |
11 | - ### Q-2) GC의 내부 작동 원리
12 | 
13 | - GC는 Young 영역과 Old 영역으로 나눠져 있습니다.
14 |
15 | #### Young 영역
16 | - **새롭게 생성된 객체가 할당되는 영역**입니다. Young영역에 대한 GC를 **Minor GC**라고 부릅니다.
17 | - Eden, Survivor0, Survivor1 으로 나뉨
18 | - **Eden**
19 | - new를 통해 새로 생성된 객체가 위치
20 | - 정기적인 쓰레기 수집 후 살아남은 객체들은 Survivor 영역으로 보냄
21 | - **Survivor 0/1**
22 | - 최소 1번의 GC 이상 살아남은 객체가 존재하는 영역
23 | - Survivor 0 또는 Survivor 1 둘 중 하나에는 꼭 비어 있어야 함
24 | - 만약 두 Survivor 영역에 모두 데이터가 존재하거나, 모두 사용량이 0이라면 현재 시스템이 정상적인 상황이 아님
25 |
26 | - ### Q) 왜 Survivor 영역은 2개 인가요?
27 | 
28 | - 외부 단편화 문제를 해결하기 위해서 입니다. 메모리가 할당되고 헤제되기를 반복하다 보면 왼쪽 사진과 같이 총 메모리 공간은 남지만,
29 | 파편화되어있어 메모리를 할당할 수 없는 문제가 발생합니다. (외부 단편화)
30 |
31 | > 💡 **age !**
32 | - minorGC 때 garbage되어 사라지지 않고, **Survivor영역에서 살아남은 횟수를 의미하는 값**입니다. **age 값이 임계값에 다다르면 Promotion(Old 영역으로 이동) 여부를 결정**합니다.
33 | - Object Header에 기록됨
34 | - JVM 중 가장 일반적인 HotSpot JVM age의 기본 임계값 : 31
35 | - 객체 헤더에 age를 기록하는 부분이 6 bit로 되어 있기 때문
36 |
37 |
38 | #### Old 영역
39 | - Young영역에서 Reachable 상태를 유지하여 **살아남은 객체가 복사되는 영역**입니다.
40 | - Young 영역보다 크게 할당되며, 영역의 크기가 큰 만큼 가비지는 적게 발생합니다.
41 | - old 영역에 대한 가비지 컬렉터(Garbage Collection)을 **Major GC** 또는 Full GC라고 부릅니다.
42 | - **Young에서 처리할 수 없을 정도로 큰 경우, 바로 Old Generation**
43 |
44 | #### Meta Space 영역
45 | 
46 | - **자바 8 이전** : **Permanation 영역** - Heap 영역에 위치
47 | - **자바 8 이후** : **MetaSpace 영역** - Native Memory 영역에 위치
48 |
49 | - 저장하는 데이터 : 자바의 메타 데이터
50 | - Class Meta Data
51 | - Method Meta Data
52 | - Static Object Variable
53 |
54 | 💡 **PermGen 제거된 이유 ? ( = 단점 )**
55 | - PermGen 영역이 **고정 크기**로 할당되어 있기 때문에, 할당 가능한 메모리 크기가 제한적입니다.
56 | - 클래스 메타데이터가 많아지면, PermGen 영역의 **메모리 부족으로 인해 OutOfMemory(OOM) Error 가 발생**할 수 있습니다.
57 | - PermGen 영역의 GC는 **Full GC** 를 수행하기 때문에, GC 가 길어집니다.
58 |
59 | 💡 이를 보완한 MetaSpace
60 | - Metaspace 영역은 JVM에 의해 관리되는 Heap이 아닌 OS 레벨에서 관리되는 Native Memory 영역
61 | - 운영체제가 메모리를 동적할당하는 방식으로 변경
62 | - 그러므로 Metaspace가 Native 메모리를 이용함으로서 개발자는 영역 확보의 상한을 크게 의식할 필요가 없어지게 됨!
63 | - 메모리의 동적할당으로 이루어지기 때문에 메모리 단편화를 방지하기 위하여 블록 할당방식으로 변경되었으며 메타데이터의 정보는 힙과 네이티브 메모리 두 영역에 모두 할당
64 |
65 |
66 | ### Q) Young/Old 영역을 나누는 이유?
67 | - Heap 영역은 처음 설계될 때 다음의 2가지 전재로 설계되었습니다.
68 | - 대부분의 객체는 금방 접근 불가능한 상태가 된다.
69 | - 오래된 객체에서 새로운 객체로의 참조는 아주 적개 존재한다.
70 | - 즉, **객체는 대부분 일회성이며, 메모리에 오래 남아있는 경우가 드물기 때문에** 생존 기간에 따라 **객체를 효율적으로 관리**하기 위해 나눕니다.
71 |
72 | ### Q) Minor GC와 MajorGC 의 차이점에 대해 말씀해주세요.
73 | - 소요 시간 입니다. Young 영역은 크기가 작기때문에 Minor GC 적은 시간, Old 영역은 크기가 크기 때문에 MajorGC는 오래 걸립니다.
74 |
75 | ### Q-1) Stop the World 에 대해 설명해주세요.
76 | - Stop the world는 GC를 수행하기 위해 어플리케이션 자체를 멈추는 현상을 말합니다. GC는 자신을 제외한 모든 스레드를 모두 멈추기 때문에 차질이 생길수도 있습니다.
77 |
78 | ### Q-2) 왜 다른 스레드들은 모두 종료해야 할까요?
79 | - Heap의 상태가 변경될 수 있기 때문에 중단하고, 값을 변경해야 합니다.
80 |
81 | ### Q) Old 영역의 객체는 Young 영역의 객체를 참조하는 경우가 있습니다. 이럴 경우, Eden 영역에서 GC가 실행되면, Old 영역이 참조하고 있는 객체는 지우면 안됩니다. List형식으로 순차적으로 확인해야하는데, 개선하기 위한 방법을 JVM이 보유한 방법에 대해 설명해주세요.
82 | > Hint💡 Table
83 | - Old영역에 512bytes 크기의 Card Table 이 있습니다.
84 | - Card Table
85 | - **old 영역에 있는 객체가 Young 영역을 참조할 때 마다 그에 대한 정보가 표시**됩니다.
86 | - **Minor GC**가 실행될 때, 모든 Old영역에 존재하는 객체를 검사하는 것은 비효율적임, Young 영역에서 GC가 진행될 때 **카드 테이블만 조회**하여 GC의 대상인 지 식별합니다.
87 |
88 | ### Q) 가장 인상깊었던 Garbage Collection 알고리즘에 대해 설명해주세요.
89 | **CMS GC (Concurrent Mark Sweep)**
90 | 
91 | - 애플리케이션의 지연 시간을 최소화 하기 위해 고안되었으며, 애플리케이션이 구동중일 때 프로세서의 자원을 공유하여 이용 가능한 알고리즘
92 | - Mark Sweep 알고리즘을 **Concurrent하게 수행**
93 | - ❌ 단점 : 다른 GC 방식보다 메모리와 CPU를 더 많이 필요로 하며, Compaction 단계를 수행하지 않음.
94 | - 시스템이 장기적으로 운영되다가 조각난 메모리들이 많아 Compaction 단계가 수행되면 오히려 **Stop The World 시간이 길어지는 문제가 발생**
95 |
96 | **G1(Garbage First) GC**
97 |
98 |
99 | 
100 | - 장기적으로 많은 문제를 일으킬 수 있는 CMS GC를 대체하기 위해 개발
101 | - **Region(지역)이라는 개념**을 새로 도입하여 **Heap을 균등하게 여러 개의 지역**으로 나누고, **각 지역을 역할과 함께 논리적으로 구분**하여(Eden 지역인지, Survivor 지역인지, Old 지역인지) 객체를 할당
102 | - Heap을 동일한 크기의 Region으로 나누고, 가비지가 많은 Region에 대해 우선적으로 GC를 수행
103 |
104 |
105 | ### Q) static을 잘못쓰면 Memory Leak 이 발생할 수 있는데, 자바 GC와 연관지어 설명해주세요.
106 | - Memory Leak은 프로그램에서 동적으로 할당한 메모리 공간을 반환하지 않는 경우 발생할 수 있는 문제 입니다. 개발자가 객체를 생성하고 사용한 후, 메모리를 반환하지 않는 경우에 발생합니다.
107 |
108 | - (질문자 예시) 가변적인 자료구조 앞에 static을 붙이는 경우
109 | - static 으로 hashMap이 있다고 쳤을 때 할당 해제가 되지 않아 memory leak 발생
110 | - 참조가 안되어있으면 GC 가 발동이 되어야하는데, static을 사용함으로 인해 Memory에 계속 남아있게 됨.
111 |
112 | - static을 사용하게 되면 compile과 동시에 method영역에 객체가 할당되게 됩니다. 사용되지 않는데 메모리에 계속 남아있다면 메모리 낭비이기 때문에 GC가 안쓰는 걸 확인하고 비워줌으로 메모리를 효율적으로 사용할 수 있습니다.
113 |
114 | ### Q) 자바8부터 static이 저장되는 영역이 바꼈는데, static은 어디에 저장될까요?
115 |
116 | - MetaSpace영역 입니다.
117 | - Method Area : 클래스 정보와 메서드 코드를 저장
118 | - Metaspace : 클래스 메타데이터를 저장
119 |
120 | > [추가 참고]
121 | > class meta-data가 metaspace로 이동하고 기존에 perment 영역에 저장되던 static object는 heap영역에 저장되도록 변경되었다고 설명하는데 이는 reference는 여전히 metaspace에서 관리됨을 의미하기에 참조를 잃은 static object는 GC의 대상이 될 수 있으나 reference가 살아있다면 GC의 대상이 되지 않음을 의미한다.
122 | >
123 | >
124 | > 따라서, metaspace는 여전히 static object에 대한 reference를 보관하며 애매하게 heap에 걸쳐지지 않고 non-heap(native memory)로 이관되며 static 변수(primitive type, interned string)는 heap 영역으로 옮겨짐에 따라 GC의 대상이 될 수 있게끔 조치한 것이다.
125 |
126 | - ### Q-1) static은 결국 heap으로 옮겨졌으면, 결국 GC가 될 수 있는 거 아닌가요?
127 | - **null 선언 시** 사용하지 않는 객체로 GC가 가능해집니다.
128 |
129 | ### Q) JVM도 되게 다양한데, 그 중 Hotspot JVM 이 기존의 Mark-And-Sweep 을 개선하였는데 알고 계시면 설명해주세요.
130 | > Hint💡 Bump the Pointer, TLABs
131 | - **Bump the pointer** 란
132 | - **Eden영역에 마지막으로 할당된 객체의 주소를 캐싱**해두는 것 입니다.
133 | - 새로운 객체를 위해 유효한 메모리를 탐색할 필요없이 마지막 주소의 다음 주소를 사용하게 함으로써 **속도를 높일** 수 있습니다.
134 | - 이를 통해 새로운 객체를 할당할 때 객체의 크기가 Eden영역에 적합한지만 판별하면 되므로 빠르게 메모리를 할당할 수 있습니다.
135 |
136 | 멀티쓰레드 환경인 경우, Eden영역에 할당할 때 동기화가 필요합니다. **멀티쓰레드 환경에서 성능 문제를 해결하기 위해 TLABs 가 도입**되었습니다.
137 |
138 | - **TLABs(Thread Local Allcation Buffers)** 란
139 | - **각각의 스레드마다 Eden영역에 객체를 할당하기 위한 주소를 부여함**으로써 동기화 작업 없이 빠르게 메모리를 할당하는 기술입니다.
140 | - 각각의 쓰레드는 자신이 갖는 주소에만 객체를 할당함으로써 동기화없이 bump the pointer를 통해 빠르게 객체를 할당할 수 있습니다.
141 |
142 | ### Q) Traffic 이 몰릴 것으로 예상되는 이벤트가 예정되어 있습니다. 여기서 Young 과 Old 영역의 비율을 튜닝할 수 있는데, 어떤 비율로 튜닝해야 할까요?
143 | > Plus💡 기존 default값 **Young 1 : Old 3**
144 |
145 | ##### 1.먼저 **트래픽의 특성을 파악**해야 합니다.
146 | - Young 영역은 적은 크기의 객체를 빠르게 처리하는 데 사용되며, Old 영역은 큰 크기의 객체를 처리하는 데 사용됩니다.
147 |
148 | ##### 2-1. **짧은 시간동안 대량의 작은 객체가 생성되는 경우**
149 | - **Young 영역의 크기를 늘리고** Old 영역의 크기를 줄여서 Young GC가 더 자주 발생하도록 설정하는 것이 좋습니다. 작은 객체를 더 빠르게 처리하고 메모리를 효율적으로 사용할 수 있습니다.
150 | - Young 영역의 크기를 늘리면 Major GC 빈도가 줄어들기 때문에 가비지 수집기의 성능이 향상될 수 있습니다.
151 | - == 마이너 GC가 더 자주 발생할 수 있음
152 |
153 | ##### 2-2. **대량의 큰 객체가 생성되는 경우**
154 | - **Old 영역의 크기를 늘려** GC가 덜 발생하도록 설정하는 것이 좋습니다. 이렇게 함으로써 큰 객체를 더 효율적으로 처리하고 메모리를 효율적으로 사용할 수 있습니다.
155 | - Old 영역의 크기를 늘리면 Major GC의 빈도를 줄일 수 있지만, Major GC의 일시 중지 시간이 길어질 수 있음
156 |
157 | ##### 3.**결론**
158 | - 따라서 예상되는 트래픽의 특성을 고려하여 Young 영역과 Old 영역의 비율을 조정하면, GC 성능을 최적화할 수 있습니다.
159 | - 응용 프로그램이 수명이 짧은 개체를 많이 생성하는 경우 Young 영역의 크기를 늘리는 것이 좋습니다.
160 | - 응용 프로그램에 수명이 긴 개체가 많은 경우 Old 영역의 크기를 늘리는 것이 좋습니다.
161 |
162 |
163 | ---
164 |
165 | _**스터디 진행 시 대답과 꼬리질문**_
166 | (꼬리질문이 좋아서 넣어봤습니다 ㅎㅎ )
167 |
168 | - 먼저 Young 영역의 비중을 늘릴 것 입니다. 트레픽이 몰린다는 것은 많은 유저가 들어온다는 뜻이므로, 금방 생성되었다 사라지는 객체가 많을 것 같기 때문에 3:1 로 하겠습니다.
169 |
170 | - ### Q-1) 그럼 Young 영역을 높인다는건데, 영역이 크기가 커지면 Stop-the-World 시간도 길어지고 수거해야할 객체가 많아지지 않을까요?
171 | - Young 영역과 Old영역을 늘렸을 때의 Trade-off 설명
172 |
173 |
174 |
175 |
176 | ### 참고
177 | [내용 및 사진-1](https://inpa.tistory.com/entry/JAVA-☕-JVM-내부-구조-메모리-영역-심화편#가비지_컬렉터_garbage_collector_,gc)
178 | [내용 및 사진-2](https://flightsim.tistory.com/240)
179 | [MetaSpace 내용-1](https://goodgid.github.io/Java-8-JVM-Metaspace/)
180 | [MetaSpace 내용-2](https://velog.io/@agugu95/자바-런타임-환경과-메모리-Java-Heap-Permgen-and-MetaSpace)
181 | [GC 알고리즘](https://mangkyu.tistory.com/119)
182 | [G1 GC 알고리즘](https://steady-coding.tistory.com/590)
183 | [GC-static -1](https://8iggy.tistory.com/230)
184 | [GC-static -2](https://8iggy.tistory.com/229)
185 |
--------------------------------------------------------------------------------
/Java/Generic.md:
--------------------------------------------------------------------------------
1 | # Generic
2 |
3 | ### 1. Generic 이란
4 | * 다양한 타입의 객체들을 다루는 메서드나 컬렉션 클래스에 컴파일 시의 타입 체크를 해주고 형변환의 번거로움을 줄여주는 기능을 하는 것입니다.
5 |
6 | #### Q) Generic에는 어떤 타입이 가능한가?
7 | - 제너릭은 레퍼런스 타입만 사용이 가능합니다. 따라서 기본형 타입을 제너릭에 사용하려면 Wrapper 클래스를 사용해야합니다.
8 |
9 | #### Q) Generic의 장점에는 무엇이 있는가?
10 | - 타입의 안정성을 제공해주고, 타입 체크와 형변환을 생략할 수 있으므로 코드가 간결해진다.
11 | - 부모 타입을 미리 정할 수 있고, 다형성으로 유연한 설계가 가능하기 떄문에 재사용성도 높아진다.
12 |
13 | #### Q) 제너릭 타입이 컴파일 시에 제거되는 과정을 말해주세요.
14 | 1. 제너릭 타입의 경계를 제거합니다. `` 이때 T는 Fruit로 치환됩니다. 만약 `` 였다면 Object로 치환됩니다.
15 | 2. 타입 제거 후 타입이 일치하지 않는 곳은 형변환을 추가해줍니다.
16 | ```java
17 | List list = new ArrayList();
18 |
19 | Fruit get(int i) {
20 | //return list.get(i); Object, Fruit 일치 X
21 | return (Fruit) list.get(i);
22 | }
23 | ```
24 | - 제너릭 타입을 컴파일 당시에 제거하는 이유는 JDK 1.5에 제너릭이 도입되었는데, 그 이전 코드와의 호환성을 위해 이러한 과정을 거치는 것이다.
25 |
26 | #### Q) 제한된 제너릭(Bounded Generic)의 장점에 대해서 설명해주세요.
27 | - 기존의 제너릭은 타입을 하나 밖에 선언하지 못하여 유연성이 좋지 않다는 문제가 있었습니다. 하지만 제한된 제너릭을 사용하면 유연성있게 특정 타입의 자손 혹은 구현체들에 대해 타입 지정을 할 수 있게 됩니다.
28 |
29 | #### Q) `List