The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── Algorithm
    ├── BFS & DFS.md
    ├── GCD&LCM.md
    ├── LRU Cache.md
    ├── 거품 정렬(Bubble Sort).md
    ├── 병합 정렬(Merge Sort).md
    ├── 삽입 정렬(Insertion Sort).md
    ├── 선택 정렬(Selection Sort).md
    ├── 순열 구하기.md
    ├── 순열과 조합.md
    ├── 이분 탐색(Binary Search).md
    ├── 퀵 정렬(Quick Sort).md
    ├── 투포인터 알고리즘.md
    └── 힙 정렬(Heap Sort).md
├── Android
    ├── 4대 컴포넌트.md
    ├── Activity Lifecycle.md
    ├── Android_Interview.md
    ├── Android에서 Enum 사용.md
    └── RecyclerView's setHasFixedSize.md
├── Data Structure
    ├── Trie(트라이).md
    ├── [Data Structure] Array vs LinkedList.md
    ├── [Data Structure] B Tree & B+ Tree.md
    ├── [Data Structure] Hash(해시).md
    ├── [Data Structure] Heap.md
    ├── [Data Structure] Stack과 Queue.md
    ├── [Data Structure] Tree.md
    ├── [Data Structure] 이진 탐색 트리.md
    ├── [Data Sturcture] ArrayList vs LinkedList.md
    └── 우선순위 큐.md
├── Database
    ├── Key(키).md
    ├── SQL - Injection.md
    ├── SQL - Join.md
    ├── SQL vs NoSQL.md
    ├── 데이터베이스 기본 용어.md
    ├── 이상(Anomaly).md
    ├── 인덱스(INDEX).md
    └── 트랜잭션.md
├── Java
    ├── HashSet vs HashMap.md
    ├── Integer vs int.md
    ├── [Java] ==와 equals() 차이.md
    ├── [Java] Call by Value vs Call by Reference.md
    ├── [Java] Garbage Collection.md
    ├── [Java] JVM.md
    ├── [Java] Java에서 Thread.md
    ├── [Java] Java의 String.md
    ├── [Java] Reflection.md
    ├── [Java] String,StringBuilder,StringBuffer 차이.md
    ├── [Java] Wrapper Class.md
    ├── [Java] equals() 메소드 동작 원리.md
    ├── [Java] final 키워드.md
    ├── [Java] int와 short.md
    ├── [Java] non-static 멤버와 static 멤버의 차이.md
    ├── [Java] 객체지향 프로그래밍 개념.md
    ├── [Java] 기본형과 참조형의 차이점.md
    ├── [Java] 변수의 종류와 메모리 구조.md
    ├── [Java] 오버라이딩과 오버로딩.md
    ├── [Java] 인터페이스.md
    ├── [Java] 접근 제어 지시자.md
    ├── [Java] 직렬화.md
    ├── [Java] 추상 클래스.md
    ├── [Java] 추상 클래스와 인터페이스의 차이.md
    ├── [Java] 클래스와 인스턴스.md
    └── 값 타입과 참조 타입의 차이.md
├── Kotlin
    ├── kotlin_functions.md
    ├── 범위 지정 함수.md
    ├── 코틀린-간단한 개념.md
    └── 코틀린-간단한 개념2.md
├── LICENSE
├── Network
    ├── 3 way handshake.md
    ├── Blocking I:O & Non-Blocking I:O.md
    ├── Cookie_Session.md
    ├── GetVsPost.md
    ├── HTTP, HTTPS.md
    ├── HTTP동작과정과 HTTP Method, 상태코드.md
    ├── OSI 7 계층.md
    ├── REST & RESTful.md
    ├── TCP.md
    ├── UDP.md
    ├── 공개키 & 대칭키.md
    ├── 로드 밸런싱.md
    └── 주소창에 naver.com을 치면 일어나는 일.md
├── Operating System
    ├── CPU 스케줄링.md
    ├── Cache.md
    ├── Context Switching.md
    ├── IPC(Inter Process Communication).md
    ├── PageReplacement.md
    ├── Paging_Segmentation.md
    ├── 교착상태(DeadLock).md
    ├── 단편화.md
    ├── 동기와 비동기.md
    ├── 동기화 문제.md
    ├── 스케줄러의 종류.md
    ├── 시스템 콜(System Call).md
    ├── 인터럽트(Interrupt).md
    └── 프로세스와 스레드.md
├── README.md
└── 운영체제와 정보기술의 원리
    ├── 운영체제란.md
    ├── 인터럽트의 원리.md
    └── 컴퓨터 시스템의 동작 원리.md


/Algorithm/BFS & DFS.md:
--------------------------------------------------------------------------------
  1 | ## BFS & DFS
  2 | 
  3 | 그래프 알고리즘으로, 문제를 풀 때 상당히 많이 사용되는 개념이다.
  4 | 
  5 | 문제의 상황에 맞게 BFS와 DFS를 활용하면 된다.
  6 | 
  7 | 여기서 사용되는 코드는 백준에 있는 [DFS와 BFS](https://www.acmicpc.net/problem/1260) 문제를 기반으로 한다.
  8 | 
  9 | > V : 정점, E : 간선
 10 | 
 11 | #### BFS
 12 | 
 13 | - 너비 우선 탐색이라 하며 BFS(Breadth-First Search)라 부른다.
 14 | - 루트 노드 혹은 임의의 노드에서 시작해 인접한 노드를 먼저 탐색하는 방법.
 15 | - 시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회 방법이다.
 16 | - 즉, 깊게 탐색하기 전에 넓게 탐색하는 것이다.
 17 | - 큐를 사용한다. (해당 노드의 주변부터 탐색해야 하기 때문이다.)
 18 | - 최소 비용(즉, 모든 곳을 탐색하는 것보다 최소 비용이 우선일 때)에 적합하다.
 19 | 
 20 | ![img](https://camo.githubusercontent.com/b8073f26dfdf1644e8a92312fff100341987a8f5/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f352f35642f427265616474682d46697273742d5365617263682d416c676f726974686d2e676966)
 21 | 
 22 | - 시간 복잡도
 23 |   - 인접 행렬 : O(V^2)
 24 |   - 인접 리스트 : O(V+E)
 25 | 
 26 | 
 27 | 
 28 | **[Code]**
 29 | 
 30 | ```java
 31 | import java.io.*;
 32 | import java.util.*;
 33 | 
 34 | public class Main {
 35 |     private static final String SPACE = " ";
 36 |     private static ArrayList<Integer>[] a;
 37 |     private static boolean[] visit;
 38 | 
 39 |     public static void main(String[] args) throws IOException {
 40 |         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 41 | 
 42 |         String[] input = br.readLine().split(SPACE);
 43 |         int n = convert(input[0]); // 정점의 개수
 44 |         int m = convert(input[1]); // 간선의 개수
 45 |         int start = convert(input[2]); // 시작할 정점 번호
 46 | 
 47 |         // 배열 초기화.
 48 |         a = new ArrayList[n + 1];
 49 | 
 50 |         for (int i = 1; i <= n; i++) {
 51 |             a[i] = new ArrayList<>();
 52 |         }
 53 | 
 54 |         for (int j = 0; j < m; j++) {
 55 |             String[] inputs = br.readLine().split(SPACE);
 56 |             int u = convert(inputs[0]);
 57 |             int v = convert(inputs[1]);
 58 | 
 59 |             // 양방향 그래프일 경우 양쪽 다 추가해준다.
 60 |             a[u].add(v);
 61 |             a[v].add(u);
 62 |         }
 63 | 
 64 |         // 방문할 정점이 여러 개인 경우 정점 번호가 가장 작은 것부터 탐색하기 위해서 정렬한다.
 65 |         for (int i = 1; i <= n; i++) {
 66 |             Collections.sort(a[i]);
 67 |         }
 68 | 
 69 |         visit = new boolean[n + 1];
 70 |         bfs(start);
 71 |         System.out.println();
 72 |     }
 73 | 
 74 |     private static int convert(String command) {
 75 |         return Integer.parseInt(command);
 76 |     }
 77 | 
 78 |     private static void bfs(int start) {
 79 |         LinkedList<Integer> queue = new LinkedList<>();
 80 | 
 81 |         visit[start] = true;
 82 |         queue.add(start);
 83 | 
 84 |         while (!queue.isEmpty()) {
 85 |             int x = queue.remove(); // 큐에서 정점을 뺀다.
 86 | 
 87 |             System.out.print(x + SPACE);
 88 | 
 89 |             for (int y : a[x]) {
 90 |                 // 방문한 적이 있는지 체크한다.
 91 |                 if (!visit[y]) {
 92 |                     // 해당 정점을 방문한 적이 없다면 방문했다고 true 로 체크한다.
 93 |                     // 그리고 해당 정점을 큐에 넣는다.
 94 |                     visit[y] = true;
 95 |                     queue.add(y);
 96 |                 }
 97 |             }
 98 |         }
 99 |     }
100 | }
101 | // 입력
102 | 5 5 3
103 | 5 4
104 | 5 2
105 | 1 2
106 | 3 4
107 | 3 1
108 | // 출력 결과
109 | 3 1 4 2 5
110 | ```
111 | 
112 | 
113 | 
114 | #### DFS
115 | 
116 | - 깊이 우선 탐색이며 DFS(Depth-First Search)라고 부른다.
117 | - 루트 노드에서 시작해서 다음 분기로 넘어가기 전에 해당 분기를 완벽하게 탐색한다.
118 | - 넓게 탐색하기 전에 깊게 탐색하는 것이다.
119 | - 예를 들어, 미로를 탐색할 때 한 방향으로 갈 수 있을 때까지 계속 가다가 더 이상 갈 수 없게 되면 다시 가장 가까운 갈림길로 돌아와서 이곳으로부터 다른 방향으로 다시 탐색을 진행하는 방법과 유사하다.
120 | - 스택이나 재귀함수를 통해 구현한다.
121 | - 모든 경로를 방문해야 할 경우 사용에 적합하다.
122 | 
123 | ![img](https://camo.githubusercontent.com/aaad9e39961daf34d967c616edeb50abf3bf1235/68747470733a2f2f75706c6f61642e77696b696d656469612e6f72672f77696b6970656469612f636f6d6d6f6e732f372f37662f44657074682d46697273742d5365617263682e676966)
124 | 
125 | - 시간 복잡도
126 |   - 인접 행렬 : O(V^2)
127 |   - 인접 리스트 : O(V+E)
128 | 
129 | 
130 | 
131 | **[Code]**
132 | 
133 | ```java
134 | import java.io.*;
135 | import java.util.*;
136 | 
137 | /**
138 |  * created by victory_woo on 02/04/2019
139 |  * DFS와 BFS 복습
140 |  */
141 | public class BOJ1260_RE {
142 |     private static final String SPACE = " ";
143 |     private static ArrayList<Integer>[] a;
144 |     private static boolean[] visit;
145 | 
146 |     public static void main(String[] args) throws IOException {
147 |         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
148 | 
149 |         String[] input = br.readLine().split(SPACE);
150 |         int n = convert(input[0]); // 정점의 개수
151 |         int m = convert(input[1]); // 간선의 개수
152 |         int start = convert(input[2]); // 시작할 정점 번호
153 | 
154 |         // 배열 초기화.
155 |         a = new ArrayList[n + 1];
156 |         visit = new boolean[n + 1];
157 | 
158 |         for (int i = 1; i <= n; i++) {
159 |             a[i] = new ArrayList<>();
160 |         }
161 | 
162 |         for (int j = 0; j < m; j++) {
163 |             String[] inputs = br.readLine().split(SPACE);
164 |             int u = convert(inputs[0]);
165 |             int v = convert(inputs[1]);
166 | 
167 |             // 양방향 그래프일 경우 양쪽 다 추가해준다.
168 |             a[u].add(v);
169 |             a[v].add(u);
170 |         }
171 | 
172 |         // 방문할 정점이 여러 개인 경우 정점 번호가 가장 작은 것부터 탐색하기 위해서 정렬한다.
173 |         for (int i = 1; i <= n; i++) {
174 |             Collections.sort(a[i]);
175 |         }
176 |         dfs(start);
177 |     }
178 | 
179 |     private static int convert(String command) {
180 |         return Integer.parseInt(command);
181 |     }
182 | 
183 |     private static void dfs(int x) {
184 |         // 방문한 적이 있다면 종료한다.
185 |         if (visit[x]) {
186 |             return;
187 |         }
188 | 
189 |         visit[x] = true;
190 |         // 방문한 순서 출력
191 |         System.out.print(x+" ");
192 | 
193 |         for (int y : a[x]) {
194 |             if (!visit[y]) {
195 |                 dfs(y);
196 |             }
197 |         }
198 | 
199 |     }
200 | }
201 | // 입력
202 | 5 4 5
203 | 5 4
204 | 4 3
205 | 4 2
206 | 1 5
207 | // 출력 결과
208 | 5 1 4 2 3
209 | 
210 | // 입력
211 | 5 5 3
212 | 5 4
213 | 5 2
214 | 1 2
215 | 3 4
216 | 3 1
217 | // 출력 결과
218 | 3 1 2 5 4
219 | ```


--------------------------------------------------------------------------------
/Algorithm/GCD&LCM.md:
--------------------------------------------------------------------------------
 1 | ### 최대공약수 GCD(Greatest Common Divisor)
 2 | 
 3 | - 최대공약수는 두 자연수의 공통된 약수 중 가장 큰 수를 의미한다.
 4 | - ex) 72와 30의 최대 공약수는 6이다.
 5 | 
 6 | 
 7 | 
 8 | ### 최소 공배수 LCM(Least Common Multiple)
 9 | 
10 | - 최소공배수는 두 자연수의 공통된 배수 중 가장 작은 수를 의미한다.
11 | - 최소 공배수 = 두 자연수의 곱 / 최대 공약수
12 | - ex) 72와 30의 최소 공배수는 360이다.
13 | 
14 | 
15 | 
16 | ### 유클리드 호제법(Euclidean Algorithm)
17 | 
18 | 2개의 자연수를 입력 받아 최대 공약수를 구하기 위해 2부터 두 자연수 중 작은 자연수까지 모두 나누어보면서 가장 큰 공약수를 구할 수 있다. 하지만, 이 방법으로 문제를 풀면 시간 복잡도는 O(N)이 된다. 나쁜 방법은 아니지만, 보다 효율을 높일 수 있는 방법이 존재하며 **유클리드 호제법이란 알고리즘을 사용하면 시간 복잡도를 O(logN)으로 줄일 수 있다.**
19 | 
20 | 
21 | 
22 | > 호제법이란? 두 수가 서로 상대방 수를 나누어서 결국 원하는 수를 얻는 방법
23 | 
24 | 
25 | 
26 | **[정의]**
27 | 
28 | 2개의 자연수 a,b에 대해서 a를 b로 나눈 나머지를 r이라 하면 단(a>b), a와 b의 최대공약수는 b와 r의 최대 공약수와 같다. 이 성질에 따라, b를 r로 나눈 나머지 r0를 구하고, 다시 r을 r0로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때, 나누는 수가 a와 b의 최대 공약수이다. 
29 | 
30 | 이는 명시적으로 기술된 가장 오래된 알고리즘으로서도 알려져 있으며, 기원전 300년 경에 쓰인 유클리드의 <원로> 제7권, 명제 1부터 3까지에 해당한다.
31 | 
32 | 
33 | 
34 | ex) 85와 51의 최대 공약수를 유클리드 호제법을 사용하여 구해보자.
35 | 
36 | - X % Y = R이라고 했을 때, X,Y의 최대 공약수는 Y와 R의 최대 공약수와 같다는 특징을 기억하자. 나머지 R이 0이 될 때까지 Y와 R의 나머지 연산을 반복한다.
37 | - 85 % 51 = 34
38 | - 51 % 34 = 17
39 | - 34 % 17 = 0
40 | - 이때, Y 값의 자리에 있는 17이 최대 공약수가 된다.
41 | 
42 | 
43 | 
44 | 
45 | 
46 | ### Reference
47 | 
48 | - [최대공약스, 최소공배수 구하기 유클리드 호제법 알고리즘 :: 코드자몽](https://myjamong.tistory.com/138)
49 | 
50 | 


--------------------------------------------------------------------------------
/Algorithm/LRU Cache.md:
--------------------------------------------------------------------------------
 1 | ## LRU Cache(Least Recently Used)
 2 | 
 3 | 
 4 | 
 5 | #### Cache 개념
 6 | 
 7 | 캐시는 데이터나 값을 미리 복사해 놓는 임시 장소를 가리킨다. 캐시는 접근 시간에 비해 원래 데이터를 접근하는 시간이 오래 걸리는 경우나 값을 다시 계산하는 시간을 절약하는 경우 사용한다. 캐시에 데이터를 미리 복사해 놓으면 계산이나 접근 시간 없이 빠른 속도로 데이터에 접근할 수 있다. (캐시가 사용하는 리소스의 양도 제한이 있다.)
 8 | 
 9 | #### LRU Cache 개념
10 | 
11 | LRU는 Least Recently Used의 약자로 OS의 페이지 교체 알고리즘의 하나로 최근에 가장 오랫동안 사용하지 않은 페이지를 교체하는 알고리즘이다. 캐시에 공간이 부족하면 가장 최근에 사용하지 않은 항목을 제거한다.
12 | 
13 | 
14 | 
15 | #### LRU Cache 구현
16 | 
17 | ![img](https://k.kakaocdn.net/dn/bW7p8I/btqv5hjmB5E/X3lwMNQP8Np2Jtl2kQg1EK/img.png)
18 | 
19 | 
20 | 
21 | LRU Cache 구현은 Doubly Linked List를 통해 구현한다. head에 가까운 데이터일수록 최근에 사용한 데이터이고, tail에 가까울수록 가장 오랫동안 사용하지 않은 데이터로 간주하여 새로운 데이터를 삽입할 때, 가장 먼저 삭제되도록 한다.
22 | 
23 | 삽입된 데이터를 사용하면 head로 옮겨 우선순위를 높이게 되고, 삭제될 우선순위에서 멀어지게 된다.


--------------------------------------------------------------------------------
/Algorithm/거품 정렬(Bubble Sort).md:
--------------------------------------------------------------------------------
 1 | ## 거품 정렬(Bubble Sort)
 2 | 
 3 | - 서로 인접한 두 원소를 검사하여 정렬하는 알고리즘이다.
 4 | - 인접한 2개의 원소를 비교해 크기가 순서대로 되어 있지 않으면 서로 교환한다.
 5 | - 선택 정렬과 기본 개념이 유사하다.
 6 | 
 7 | 
 8 | 
 9 | ### 로직
10 | 
11 | 1. 1회전에 첫 번째 원소와 두 번째 원소를, 두 번째 원소와 세 번째 원소를, 세 번째 원소와 네 번째 원소를, ... 이런 식으로 마지막 - 1 번째 원소와 마지막 원소를 비교하여 조건에 맞지 않으면 서로 교환한다.
12 | 2. 1회전을 수행하고 나면 가장 큰 원소가 맨 뒤로 이동하므로 2회전에서는 맨 끝에 있는 원소는 정렬에서 제외되고, 2회전을 수행하고 나면 끝에서 두번째 원소까지는 정렬에서 제외된다. 이렇게 정렬을 1회전 수행할 때마다 정렬에서 제외되는 데이터가 하나씩 늘어난다.
13 | 
14 | 
15 | 
16 | ```java
17 | private static void sort(int[] arr) {
18 |         for (int i = 0; i < arr.length; i++) { // 1
19 |             for (int j = 0; j < arr.length - i - 1; j++) { // 2
20 |                 if (arr[j] > arr[j + 1]) { // 3
21 |                     int temp = arr[j];
22 |                     arr[j] = arr[j + 1];
23 |                     arr[j + 1] = temp;
24 |                 }
25 |             }
26 | 
27 |             System.out.print((i + 1) + "단계 : ");
28 |             print(arr);
29 |         }
30 |     }
31 | 
32 | private static void print(int[] arr) {
33 |         for (int i = 0; i < arr.length; i++) {
34 |             System.out.print(arr[i] + " ");
35 |         }
36 |         System.out.println();
37 |     }
38 | 
39 | // 단계별 결과.
40 | 1단계 : 6 2 4 3 7 1 9 
41 | 2단계 : 2 4 3 6 1 7 9 
42 | 3단계 : 2 3 4 1 6 7 9 
43 | 4단계 : 2 3 1 4 6 7 9 
44 | 5단계 : 2 1 3 4 6 7 9 
45 | 6단계 : 1 2 3 4 6 7 9 
46 | 7단계 : 1 2 3 4 6 7 9 
47 | ```
48 | 
49 | - 첫 번째 for문은 제외될 원소의 갯수를 의미한다. 1회전이 끝난 후, 배열의 마지막 위치에는 가장 큰 원소가 위치하기 때문에 하나씩 증가시켜준다. 2회전이 끝나면 배열의 마지막 두 위치에는 큰 원소 2개가 정렬된 상태로 위치할 것이기 때문에 2개를 제외하면 된다.
50 | - 두 번째 for문은 원소를 비교할 index를 뽑는 for문이다. j는 0부터 arr.lenght-i-1까지 증가한다. 현재 원소와 다음 원소를 가리키기 때문에 0부터 시작한다.
51 | - 세 번째 for문은 가리키고 있는 두 원소를 비교한다. 오름차순 정렬이므로 현재 원소가 다음 원소보다 크다면 다음 원소가 앞으로 오고 현재 원소가 뒤로 가야 하므로 서로 자리를 교환한다.
52 | 
53 | 
54 | 
55 | ### 시간 복잡도
56 | 
57 | (n-1)+(n-2)+(n-3)+ ... +2+1 => n(n-1)/2이므로, O(N^2)이다. 
58 | 
59 | 버블 정렬은 정렬이 되어있건, 안되어있건 2개의 원소를 비교하기 때문에 최악의 경우, 최선의 경우, 평균의 경우 모두 시간 복잡도가 O(N^2)으로 동일하다.
60 | 
61 | 
62 | 
63 | ### 공간 복잡도
64 | 
65 | 주어진 배열 안에서 교환을 통해 정렬이 수행되므로 O(N)이다.
66 | 
67 | 
68 | 
69 | 
70 | 
71 | ### 장점
72 | 
73 | - 구현이 간단하고 소스코드가 직관적이다.
74 | - 이미 정렬된 데이터를 정렬할 때, 가장 빠르다.
75 | - 정렬하고자 하는 배열 안에서 정렬하는 방식이므로, 다른 메모리 공간을 필요로 하지 않는다.
76 | - 안정 정렬이다.
77 | 
78 | 
79 | 
80 | ### 단점
81 | 
82 | - 시간 복잡도가 최악, 최선, 평균 모두 O(N^2)이므로 비효율적이다.
83 | - 다른 정렬에 비해 정렬 속도가 느리다.
84 | - 교환 횟수가 많다.
85 | - 역순배열을 정렬할 때, 가장 느리다.


--------------------------------------------------------------------------------
/Algorithm/병합 정렬(Merge Sort).md:
--------------------------------------------------------------------------------
  1 | ## 병합 정렬(Merge Sort)
  2 | 
  3 | 합병 정렬이라고도 부르며, 분할 정복 방법을 통해 구현한다.
  4 | 
  5 | 
  6 | 
  7 | ### 개념
  8 | 
  9 | - 빠른 정렬로 분류되며, Quick Sort와 함께 많이 언급되는 정렬 방식이다.
 10 | - Quick Sort와는 반대로 안정 정렬에 속한다.
 11 | 
 12 | 
 13 | 
 14 | **시간복잡도**
 15 | 
 16 | |   평균   |   최선   |   최악   |
 17 | | :------: | :------: | :------: |
 18 | | O(nlogn) | O(nlogn) | O(nlogn) |
 19 | 
 20 | 요소를 쪼갠 후, 다시 합병시키면서 정렬해나가는 방식으로 쪼개는 방식은 퀵 정렬과 유사.
 21 | 
 22 | 
 23 | 
 24 | **MergeSort()**
 25 | 
 26 | ```java
 27 | private static void mergeSort(int[] a, int left, int right) {
 28 |         if (left < right) {
 29 |             int mid = (left + right) / 2;
 30 | 
 31 |             mergeSort(a, left, mid); // 왼쪽 부분 배열을 나눈다.
 32 |             mergeSort(a, mid + 1, right); // 오른쪽 부분 배열을 나눈다.
 33 |             merge(a, left, mid, right);
 34 |             // 나눈 부분 배열을 합친다.
 35 |             // 핵심 로직이다.
 36 |         }
 37 |     }
 38 | ```
 39 | 
 40 | 
 41 | 
 42 | **Merge()**
 43 | 
 44 | ```java
 45 | /*
 46 |     * i : 왼쪽 부분 배열을 관리하는 인덱스
 47 |     * j : 오른쪽 부분 배열을 관리하는 인덱스
 48 |     * */
 49 |     private static void merge(int[] a, int left, int mid, int right) {
 50 |         int i, j, k, l;
 51 |         i = left;
 52 |         j = (mid + 1);
 53 |         k = left;
 54 | 
 55 |         // 왼쪽 부분 배열과 오른쪽 부분 배열을 비교하면서
 56 |         // 각각의 원소 중에서 작은 원소가 sorted 배열에 들어간다.
 57 |         // 왼쪽 혹은 오른쪽의 부분 배열 중 하나의 배열이라도 모든 원소가 sorted 배열에 들어간다면
 58 |         // 아래의 반복문은 조건을 만족하지 하지 않기 때문에 빠져 나온다.
 59 |         // sorted 배열에 들어가지 못한 부분 배열은 아래 쪽에서 채워진다.
 60 |         while (i <= mid && j <= right) {
 61 |             if (a[i] < a[j]) sorted[k++] = a[i++];
 62 |             else sorted[k++] = a[j++];
 63 |         }
 64 | 
 65 |         // mid < i 인 순간, i는 왼쪽 부분 배열의 인덱스를 관리하므로
 66 |         // 즉, 왼쪽 부분 배열이 sorted 에 모두 채워졌음을 의미한다.
 67 |         // 따라서 남아 있는 오른쪽 부분 배열의 값을 일괄 복사한다.
 68 |         if (mid < i) {
 69 |             for (l = j; l <= right; l++) sorted[k++] = a[l];
 70 |         } else {
 71 |             // mid > i 인 것은 오른쪽 부분 배열이 sorted 배열에 정렬된 상태로 모두 채워졌음을 의미한다.
 72 |             // 따라서, 왼쪽 부분 배열은 아직 남아 있는 상태이다.
 73 |             // 즉, 남아 있는 왼쪽 부분 배열의 값을 일괄 복사한다.
 74 |             for (l = i; l <= mid; l++) sorted[k++] = a[l];
 75 |         }
 76 | 
 77 |         // sorted 배열에 들어간 부분 배열을 합하여 정렬한 배열은
 78 |         // 원본 배열인 a 배열로 다시 복사한다.
 79 |         for (l = left; l <= right; l++) a[l] = sorted[l];
 80 |     }
 81 | ```
 82 | 
 83 | 
 84 | 
 85 | mergeSort()로 나누어진 왼쪽, 오른쪽의 두 부분 배열을 합치는 과정이 merge()에서 일어난다.
 86 | 
 87 | 자세한 내용을 말로 하기에는 아직 설명 능력이 부족하여, 코드 상의 주석으로 설명했으니 참고 바란다.
 88 | 
 89 | 
 90 | 
 91 | 참고로, 합병 정렬은 순차적인 비교로 정렬을 진행하므로, LinkedList의 정렬이 필요할 때, 사용하면 효율적이다.
 92 | 
 93 | LinkedList를 퀵 정렬에 사용해 정렬하면 성능이 좋지 않다. 
 94 | 
 95 | 이유는 퀵 정렬은 순차 접근이 아닌 임의 접근이기 때문이다.
 96 | 
 97 | LinkedList는 삽입과 삭제 연산에서는 유용하지만, 접근 연산에서는 비효율적이다.
 98 | 
 99 | > 배열은 인덱스를 사용해 임의 접근이 가능하지만, LinkedList는 Head부터 탐색해야 한다.
100 | >
101 | > 배열 : O(1)
102 | >
103 | > LinkedList : O(N)
104 | 
105 | 
106 | 
107 | ### 장점
108 | 
109 | - 데이터의 분포에 영향을 덜 받는다. 즉, 입력 데이터가 무엇이든 간에 정렬되는 시간은 동일하다. -> O(N logN)
110 | - 크기가 큰 레코드를 정렬한 경우, LinkedList를 사용한다면 병합 정렬은 퀵 정렬을 포함한 다른 어떤 정렬 방법보다 효율적이다.
111 | - 안정 정렬에 속한다.
112 | 
113 | 
114 | 
115 | ### 단점
116 | 
117 | - 레코드를 배열로 구성한다면, 임시 배열이 필요하다.
118 |   - 메모리 낭비를 초래한다.
119 |   - 제자리 정렬이 아니다.
120 | - 레코드의 크기가 큰 경우에는 이동 횟수가 많으므로 매우 큰 시간적 낭비를 초래한다.
121 | 
122 | 
123 | 
124 | ### 시간 복잡도
125 | 
126 | - 평균 : O(N logN)
127 | - 최악 : O(N logN)
128 | - 최선 : O(N logN)


--------------------------------------------------------------------------------
/Algorithm/삽입 정렬(Insertion Sort).md:
--------------------------------------------------------------------------------
 1 | ## 삽입 정렬(Insertion Sort)
 2 | 
 3 | 
 4 | 
 5 | ### 개념
 6 | 
 7 | - 손 안의 카드를 정렬하는 방법과 유사하다.
 8 | - 새로운 카드를 기존의 정렬된 카드 사이에 올바른 자리를 찾아 삽입한다.
 9 | - 2번째 원소부터 시작하여 그 앞(왼쪽)의 원소들과 비교하여 삽입할 위치를 지정한 후, 원소를 뒤로 옮기고 지정된 자리에 자료를 삽입하여 정렬하는 알고리즘이다.
10 | - 최선의 경우, O(N)이라는 엄청나게 빠른 효율성을 가지고 있어, 다른 정렬 알고리즘의 일부로 사용될만큼 좋은 정렬 알고리즘이다.
11 | 
12 | 
13 | 
14 | ### 로직
15 | 
16 | 1. 정렬은 2번째 위치(index)의 값을 standard에 저장한다
17 | 2. standard와 이전에 있는 원소들과 비교하여 자리를 바꾸며 삽입해 나간다.
18 | 3. 1번으로 돌아가서 다음 위치(index)의 값을 standard에 저장하고 이 과정을 반복한다.
19 | 
20 | ### Code
21 | 
22 | ```java
23 | private static void sort(int[] arr) {
24 |         for (int i = 1; i < arr.length; i++) { // 1
25 |             int standard = arr[i];
26 |             int index = i - 1;
27 | 
28 |             while ((0 <= index) && standard < arr[index]) {//2
29 |                 arr[index + 1] = arr[index];
30 |                 index--;
31 |             }
32 |             arr[index + 1] = standard; // 3
33 | 
34 |             print(arr, i);
35 |         }
36 |     }
37 | 
38 |     private static void print(int[] arr, int step) {
39 |         System.out.print(step + "단계 : ");
40 |         for (int i = 0; i < arr.length; i++) {
41 |             System.out.print(arr[i] + " ");
42 |         }
43 | 
44 |         System.out.println();
45 |     }
46 | // 단계별 결과.
47 | 1단계 : 6 7 2 4 3 9 1 
48 | 2단계 : 2 6 7 4 3 9 1 
49 | 3단계 : 2 4 6 7 3 9 1 
50 | 4단계 : 2 3 4 6 7 9 1 
51 | 5단계 : 2 3 4 6 7 9 1 
52 | 6단계 : 1 2 3 4 6 7 9
53 | ```
54 | 
55 | 
56 | 
57 | - 첫 번째 원소 앞(왼쪽)에는 원소가 없기 때문에 두 번째 위치(index)부터 탐색을 시작한다. standard에 임시로 기준 위치(index) 값을 저장하고, index에는 기준 위치(standard) 이전의 위치(index)를 저장한다.
58 | - 이전 위치를 가리키는 index는 음수가 되지 않고, 이전 위치의 값이 1번에서 선택한 기준 위치의 값보다 크다면 오른쪽으로 한 칸씩 이동시켜준다. 그리고 index가 더 이전 위치를 가리키도록 한다.
59 | - 2번에서 반복문이 끝나고 난 뒤, index에는 standard가 들어갈 위치의 인덱스-1의 위치를 가리키게 된다. 2번의 반복문에서 standard보다 큰 값들의 위치를 한 칸씩 오른쪽으로 밀었기 때문이다. 따라서 (index+1) 위치에 standard가 들어갈 위치이기 때문에, 삽입해준다.
60 | 
61 | 
62 | 
63 | ### 시간 복잡도
64 | 
65 | - 최악의 경우(역으로 정렬되어 있을 경우), 선택 정렬과 마찬가지로 (n-1)+(n-2)+ ... +2+1 => n(n-1)/2 즉, O(N^2)이다.
66 | - 하지만, 모두 정렬이 되어 있는 경우, 한번씩만 비교하므로 O(N)의 시간 복잡도를 가지게 된다. 또한, 이미 정렬되어 있는배열에 자료를 하나씩 삽입/제거하는 경우에는 현실적으로 최고의 정렬 알고리즘이 되는데, 탐색을 제외한 오버헤드가 매우 적기 때문이다.
67 | - 최선의 경우 : O(N)
68 | - 평균과 최악의 경우 : O(N^2)
69 | 
70 | 
71 | 
72 | ### 공간 복잡도
73 | 
74 | - 주어진 배열 안에서 교환을 통해 정렬이 이루어지기 때문에 O(N)이다.
75 | 
76 | 
77 | 
78 | ### 장점
79 | 
80 | - 알고리즘이 단순하다.
81 | - 대부분의 원소가 이미 정렬되어 있는 경우, 매우 효율적일 수 있다.
82 | - 정렬하고자 하는 배열 안에서 교환하는 방식이므로, 다른 메모리 공간을 필요로 하지 않는다. 
83 | - 선택 정렬이나 버블 정렬에 비하여 상대적으로 빠르다.
84 | 
85 | 
86 | 
87 | ### 단점
88 | 
89 | - 비교적 많은 수들의 이동을 포함한다.
90 | - 비교할 수가 많고 크기가 클 경우에 적합하지 않다.(배열의 길이가 길어질수록 비효율적)
91 | - 평균과 최악의 시간 복잡도가 O(N^2)이므로 비효율적이다.
92 | 


--------------------------------------------------------------------------------
/Algorithm/선택 정렬(Selection Sort).md:
--------------------------------------------------------------------------------
  1 | ## 선택 정렬(Selection Sort)
  2 | 
  3 | 정렬 알고리즘은 다음과 같이 나눠볼 수 있다.
  4 | 
  5 | - 단순하지만 비효율적인 방법 : 선택 정렬, 삽입 정렬, 버블 정렬
  6 | - 복잡하지만 조금 더 효율적인 방법 : 퀵 정렬, 힙 정렬, 합병 정렬, 기수 정렬
  7 | 
  8 | 
  9 | 
 10 | 그 중에서 이번에는 선택 정렬에 대해 알아보려 한다.
 11 | 
 12 | 
 13 | 
 14 | ### 개념
 15 | 
 16 | - 해당 순서에 원소를 넣을 위치는 이미 정해져있고, 어떤 원소를 넣을지 선택하는 알고리즘이다.
 17 | - 현재 위치에 저장될 값의 크기가 작냐, 크냐에 따라서 최소 선택 정렬(오름차순 정렬)과 최대 선택 정렬(내림차순 정렬)로 나뉜다.
 18 | 
 19 | 
 20 | 
 21 | ### 로직
 22 | 
 23 | 1. 주어진 배열에서 첫번째 인덱스를 기준으로 잡는다. 기준은 처음부터 시작한다.
 24 | 2. 주어진 배열에서 기준 이후의 값 중 최소값을 찾는다.
 25 | 3. 최소값과 그 기준의 값을 교체한다.
 26 | 4. 기준 이후의 나머지 배열을 같은 방법으로 교체한다.
 27 | 
 28 | 
 29 | 
 30 | ```java
 31 | int[] arr = {7, 6, 2, 4, 3, 9, 1};
 32 | 
 33 | private static void sort(int[] arr) {
 34 |         for (int i = 0; i < arr.length; i++) { // 1
 35 |             int standard = i;
 36 |             for (int j = i + 1; j < arr.length; j++) { // 2
 37 |                 if (arr[j] < arr[standard]) standard = j; // 3
 38 |             }
 39 |           	
 40 |           	// 4
 41 |             int temp = arr[standard];
 42 |             arr[standard] = arr[i];
 43 |             arr[i] = temp;
 44 | 
 45 |             print(arr);
 46 |         }
 47 |     }
 48 | 
 49 | private static void print(int[] arr) {
 50 |         for (int i = 0; i < arr.length; i++) {
 51 |             System.out.print(arr[i] + " ");
 52 |         }
 53 |         System.out.println();
 54 |     }
 55 | 
 56 | // 단계별 결과.
 57 | 1단계 : 1 6 2 4 3 9 7 
 58 | 2단계 : 1 2 6 4 3 9 7 
 59 | 3단계 : 1 2 3 4 6 9 7 
 60 | 4단계 : 1 2 3 4 6 9 7 
 61 | 5단계 : 1 2 3 4 6 9 7 
 62 | 6단계 : 1 2 3 4 6 7 9 
 63 | 7단계 : 1 2 3 4 6 7 9 
 64 | ```
 65 | 
 66 | - 먼저, 위치(index)를 **선택**한다. (주로 배열의 첫 번째부터 시작한다.)
 67 | - i+1번째 원소부터 선택한 위치의 값과 비교를 시작한다.
 68 | - 오름차순이므로 현재 선택한 자리에 있는 기준 값보다 순회하고 있는 값이 작다면 **위치(index)를 갱신해준다.**
 69 | - 코드의 2번 반복문이 끝난 뒤에는 작은 값을 찾아서 갱신했으므로 처음에 선택했던 기준값과 작은 값의 위치를 서로 교환해준다.
 70 | 
 71 | 
 72 | 
 73 | 쉽게 말해서 기준이 되는 수와 나머지 수를 비교해서 가장 작은 수를 앞으로 계속 보내는 정렬이다. 
 74 | 
 75 | 간단하지만, 매우 비효율적이다.
 76 | 
 77 | 
 78 | 
 79 | 1단계 => n개의 원소 비교
 80 | 
 81 | 2단계 => n-1개의 원소 비교
 82 | 
 83 | 3단계 => n-2개의 원소 비교
 84 | 
 85 | ...
 86 | 
 87 | 를 하여 비교 횟수는 
 88 | 
 89 | n(n-1)/2가 된다.
 90 | 
 91 | **즉, 시간 복잡도는 O(N^2)이 된다.**
 92 | 
 93 | **최악의 경우, 최선의 경우, 평균적인 경우 모두 시간 복잡도는 O(N^2)이 된다.**
 94 | 
 95 | 
 96 | 
 97 | **공간 복잡도는 주어진 배열 안에서 교환을 통해 정렬이 수행되므로 O(N)이다.**
 98 | 
 99 | 
100 | 
101 | ### 장점
102 | 
103 | - 알고리즘이 단순하다.
104 | - 정렬을 위한 비교는 여러번 수행되지만, 실제로 교환 횟수는 적기 때문에 많은 교환이 일어나야 하는 자료 상태에서 비교적 효율적인 면이 있다.
105 | - 정렬하고자 하는 배열 안에서 교환하는 방식이므로, 다른 메모리 공간을 필요로 하지 않는다.
106 | 
107 | 
108 | 
109 | ### 단점
110 | 
111 | - 시간 복잡도가 O(N^2)이므로 비효율적이다.
112 | - **불안정 정렬(Unstable Sort)이다.**


--------------------------------------------------------------------------------
/Algorithm/순열 구하기.md:
--------------------------------------------------------------------------------
  1 | ## 순열 구하기
  2 | 
  3 | 프로그래머스의 문제 중 [소수 찾기] 라는 문제를 풀다가 순열 알고리즘이 나와서 정리한 내용이다.
  4 | 
  5 | 1,2,3와 같은 숫자들이 있다. 이것을 중복하지 않고 순서를 끌어내보자.
  6 | 
  7 | 1,2,3
  8 | 
  9 | 1,3,2
 10 | 
 11 | 2,1,3
 12 | 
 13 | 2,3,1
 14 | 
 15 | 3,1,2
 16 | 
 17 | 3,2,1
 18 | 
 19 | 위와 같이 여섯가지의 방법이 존재한다.
 20 | 
 21 | 1,2,3,4의 경우에는 그 숫자가 훨씬 많아진다. 이를 알고리즘으로 어떻게 구현할 수 있을까?
 22 | 
 23 | ![img](https://t1.daumcdn.net/cfile/tistory/215AFC35562B178E37)
 24 | 
 25 | 위의 그림은 ABC 알파벳을 재귀함수를 통해서 순열을 만드는 방법이다. 
 26 | 
 27 | 먼저, ABC 중 첫번째 알파벳을 무엇으로 할 것인가? 종류는 3가지이다. (배열은 ABC 순서로 정해져있다고 가정한다.)
 28 | 
 29 | A
 30 | 
 31 | B
 32 | 
 33 | C
 34 | 
 35 | 위의 경우에서 첫번째가 A인 경우는 첫번째 인자[0]인 A를 첫번째 인자[0] A와 바꾼 것이다. (실질적으로는 바뀐게 없음.)
 36 | 
 37 | 첫번째 인자가 B로 설정되어 있는 경우는 첫번째 인자[0]인 A를 두번째 인자[1] B와 바꾼 것이다.
 38 | 
 39 | 첫번째 인자가 C로 설정되어 있는 경우는 첫번째 인자[0]인 A를 세번째 인자[2] C와 바꾼 것이다.
 40 | 
 41 | > [0] <-> [0]
 42 | >
 43 | > [0] <-> [1]
 44 | >
 45 | > [0] <-> [2]
 46 | 
 47 | 첫 번째 인자가 고정되었으니 두 번째와 세 번째 인자에 대해서는 위와 같은 과정을 반복하면 된다.
 48 | 
 49 | > [0] <-> [0] 이 경우에 한해서 확인해보자. A인 경우.
 50 | >
 51 | > [0] [1] <-> [0] [1] : 두번째 인자 [1]인 B와 두번째 인자 [1]인 B를 바꾼다. A B C
 52 | >
 53 | > [0] [1] <-> [0] [2] : 두번째 인자 [1]인 B와 세번째 인자 [2]인 C를 바꾼다. A C B
 54 | 
 55 | 마지막 경우를 살펴보자.
 56 | 
 57 | >[0] [1] <-> [0] [1] 이 경우에 한해서 확인해보자.
 58 | >
 59 | >[0] [1] [2] <-> [0] [1] [2] 바뀌는 건 없다. A B C
 60 | >
 61 | >
 62 | >
 63 | >[0] [1] <-> [0] [2] 이 경우에 한해서 확인해보자.
 64 | >[0] [2] [1] <-> [0] [2] [1] 바뀌는 건 없다. A C B
 65 | 
 66 | 
 67 | 
 68 | nPk의 순열을 구한다.
 69 | 
 70 | 즉, n개 중 k개로 이루어진 순열을 구하려 한다. 
 71 | 
 72 | perm(int[] arr, int depth, int n, int k)
 73 | 
 74 | - 배열 arr : 계속해서 데이터를 들고다니며 교환되고 있는 배열이다.
 75 | - depth : 현재 트리구조에서 어떤 깊이에서 교환 작업을 하고 있는지에 대한 변수이다. 즉, 맨처음 깊이라면 0의 위치에서 작업을 하고 있을 것이며 이는 
 76 |   첫 번째와 첫 번째 인자를 교환하거나(1,2,3,4)
 77 |   첫 번째와 두 번째 인자를 교환하거나(2,1,3,4)
 78 |   첫 번째와 세 번째 인자를 교환하거나(3,1,2,4)
 79 |   첫 번째와 네 번째 인자를 교환하는 중이다.(4,1,2,3)
 80 | - n : 총 배열 안에 들어 있는 숫자를 뜻하며, 배열의 길이이다. 고정 값이다.
 81 | - k : 몇 개를 뽑아내서 순열을 만들 것인지를 뜻하며 고정 값이다. 
 82 | 
 83 | 
 84 | 
 85 | ```java
 86 | private static void perm(int[] arr, int depth, int n, int k) {
 87 |         if (depth == k) {
 88 |             print(arr, k);
 89 |             return;
 90 |         }
 91 | 
 92 |         for (int i = depth; i < n; i++) {
 93 |             swap(arr, i, depth);
 94 |             perm(arr, depth + 1, n, k);
 95 |             swap(arr, i, depth);
 96 |         }
 97 |     }
 98 | ```
 99 | 
100 | 
101 | 
102 | depth를 검사해 k와 같으면 더이상 순열을 만들지 않는다. 내가 원하는 건 k개의 숫자가 있는 순열이기 때문이다. 여기서는 4에 도달하면 출력해야 하는 숫자 4개가 세팅되었다는 뜻이므로 출력하면 된다.
103 | 
104 | depth에 따라서 for문의 시작점이 다르다. depth가 0이라면 1XXX, 2XXX, 3XXX, 4XXX를 뽑아줘야 하기 때문에 총 네번의 루프가 돌아야 한다.
105 | 
106 | 
107 | 
108 | depth 0 -> 1XXX이 만들어지면, 여기서 재귀 함수를 통해서 perm을 호출하고 그 안의 depth 호출은 아래와 같다.
109 | 
110 | depth 1 -> 2XXX를 만드는 것이 아니라 12XX, 13XX, 14XX을 만들고
111 | 
112 | depth 2 -> 다음으로 123X
113 | 
114 | depth 3 -> 1234이 채워지며 
115 | 
116 | depth 4 -> 출력한다.
117 | 
118 | 
119 | 
120 | 
121 | 
122 | depth 0 -> 2XXX이 만들어지고 위의 과정을 반복한다.
123 | 
124 | 
125 | 
126 | 또한, 위의 코드에서는 swap 함수를 한번 더 호출한다. 처음에 등장하는 swap을 통해서 원본 배열의 순선를 바꾸고 있다. 따라서 다음에 순열을 만들려고 할 때 값이 바뀌기 때문에 제대로 된 값을 만들 수 없다. 그래서 원본 배열로 다시 복귀하는 것이다.
127 | 
128 | Ex) 
129 | 
130 | 1 2 3 4 에서 [1] <-> [2]을 바꿔서 1 3 2 4가 된다.
131 | 
132 | 여기서 재귀호출을 하여 끝까지 탐색하고 결과를 출력하고 돌아오면 배열은 1 3 2 4이다. 
133 | 
134 | 이제 [1] <-> [3]을 바꿔서 1 4 3 2을 처리해야 하지만 실제로는 1 4 2 3 이 된다. 
135 | 
136 | 따라서 예상하지 못한 배열이 처리된다. 따라서 바뀐 배열을 원래의 배열로 돌려줘야 한다.
137 | 
138 | 
139 | 
140 | 최종 Code
141 | 
142 | ```java
143 | private static void perm(int[] arr, int depth, int n, int k) {
144 |         if (depth == k) {
145 |             print(arr, k);
146 |             return;
147 |         }
148 | 
149 |         for (int i = depth; i < n; i++) {
150 |             swap(arr, i, depth);
151 |             perm(arr, depth + 1, n, k);
152 |             swap(arr, i, depth);
153 |         }
154 |     }
155 | 
156 |     private static void swap(int[] arr, int i, int j) {
157 |         int temp = arr[i];
158 |         arr[i] = arr[j];
159 |         arr[j] = temp;
160 |     }
161 | 
162 |     private static void print(int[] arr, int k) {
163 |         for (int i = 0; i < arr.length; i++) {
164 |             if (i == k - 1) System.out.println(arr[i]);
165 |             else System.out.print(arr[i] + ", ");
166 |         }
167 |     }
168 | ```
169 | 
170 | 
171 | 
172 | ### 참고
173 | 
174 | - [순열(PERMUTATION) 알고리즘](https://gorakgarak.tistory.com/522)
175 | 
176 | 


--------------------------------------------------------------------------------
/Algorithm/순열과 조합.md:
--------------------------------------------------------------------------------
  1 | ### 순열과 조합
  2 | 
  3 | 순열 : 순서를 고려하여 뽑는다.
  4 | 
  5 | 조합 : 순서와 상관없이 뽑는다.
  6 | 
  7 | 
  8 | 
  9 | #### 순열
 10 | 
 11 | - n,r을 입력으로 받아서 n개 중에서 r개를 뽑는 순열을 만들어보자.
 12 | - LinkedList와 boolean[] check 배열을 사용한다.
 13 | 
 14 | [Code]
 15 | 
 16 | ```java
 17 | import java.io.BufferedReader;
 18 | import java.io.IOException;
 19 | import java.io.InputStreamReader;
 20 | import java.util.LinkedList;
 21 | 
 22 | /**
 23 |  * created by victory_woo
 24 |  */
 25 | public class PermutationWithLinkedList {
 26 |     private static LinkedList<Integer> list;
 27 |     private static int[] check;
 28 | 
 29 |     public static void main(String[] args) throws IOException {
 30 |         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
 31 |         String[] in = br.readLine().split(" ");
 32 |         int n = Integer.parseInt(in[0]);
 33 |         int r = Integer.parseInt(in[1]);
 34 | 
 35 |         list = new LinkedList<>();
 36 |         check = new int[n + 1];
 37 |         permutation(n, r);
 38 |         //rePermutation(n, r);
 39 |     }
 40 | 
 41 |     // n개 중 r개를 뽑는 순열.(중복 X)
 42 |     // 재귀 호출의 개념을 사용한다.
 43 |     private static void permutation(int n, int r) {
 44 |         if (list.size() == r) {
 45 |             print();
 46 |             return;
 47 |         }
 48 | 
 49 |         for (int i = 1; i <= n; i++) {
 50 |             if (check[i] == 0) {
 51 |                 list.add(i);
 52 |                 check[i] = 1;
 53 |                 permutation(n, r);
 54 |                 check[i] = 0;
 55 |                 list.removeLast();
 56 |             }
 57 |         }
 58 |     }
 59 | 
 60 |   	// 중복을 허용하는 순열.
 61 |     private static void rePermutation(int n, int r) {
 62 |         if (list.size() == r) {
 63 |             print();
 64 |             return;
 65 |         }
 66 | 
 67 |         for (int i = 1; i <= n; i++) {
 68 |             list.add(i);
 69 |             rePermutation(n, r);
 70 |             list.removeLast();
 71 |         }
 72 |     }
 73 | 
 74 |     private static void print() {
 75 |         for (int value : list) {
 76 |             System.out.print(value + " ");
 77 |         }
 78 |         System.out.println();
 79 |     }
 80 | }
 81 | 
 82 | ```
 83 | 
 84 | - 중복을 허용하지 않는 순열(permutation)
 85 | 
 86 | ```
 87 | n : 3, r : 2
 88 | 1 2 
 89 | 1 3 
 90 | 2 1 
 91 | 2 3 
 92 | 3 1 
 93 | 3 2 
 94 | ```
 95 | 
 96 | - 중복을 허용하는 순열(repermutaiion)
 97 | 
 98 | ```
 99 | n : 3, r : 2
100 | 1 1 
101 | 1 2 
102 | 1 3 
103 | 2 1 
104 | 2 2 
105 | 2 3 
106 | 3 1 
107 | 3 2 
108 | 3 3 
109 | ```
110 | 
111 | 
112 | 
113 | #### 조합
114 | 
115 | - n,r을 입력으로 받아서 n개 중에서 r개를 뽑는 조합을 만들어보자.
116 | - comArr 배열을 사용한다.
117 | 
118 | ```java
119 | package 순열과조합;
120 | 
121 | import java.io.BufferedReader;
122 | import java.io.IOException;
123 | import java.io.InputStreamReader;
124 | import java.util.LinkedList;
125 | 
126 | /**
127 |  * created by victory_woo on 2020/04/03
128 |  */
129 | public class Combination {
130 |     private static int[] comArr;
131 |     private static LinkedList<Integer> list = new LinkedList<>();
132 | 
133 |     public static void main(String[] args) throws IOException {
134 |         BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
135 |         String[] in = br.readLine().split(" ");
136 |         int n = Integer.parseInt(in[0]);
137 |         int r = Integer.parseInt(in[1]);
138 | 
139 |         // 조합 : 순서는 관심 없고 뽑은 유무만 생각한다.
140 |         comArr = new int[r];
141 |         combination(n, r, 0, 1);
142 |         //reCombination(n, r, 0, 1);
143 | 
144 |     }
145 | 
146 |     private static void combination(int n, int r, int index, int target) {
147 |         if (r == 0) {
148 |             print();
149 |             return;
150 |         }
151 | 
152 |         if (target == n + 1) return;
153 | 
154 |         comArr[index] = target;
155 |         combination(n, r - 1, index + 1, target + 1); // 뽑는 경우.
156 |         combination(n, r, index, target + 1); // 안뽑는 경우.
157 |     }
158 | 
159 | 
160 |     private static void reCombination(int n, int r, int index, int target) {
161 |         if (r == 0) {
162 |             print();
163 |             return;
164 |         }
165 | 
166 |         if (target == n + 1) return;
167 | 
168 |         comArr[index] = target;
169 |         reCombination(n, r - 1, index + 1, target); // 뽑는 경우.
170 |         reCombination(n, r, index, target + 1); // 안뽑는 경우.
171 |     }
172 | 
173 | 
174 |     private static void print() {
175 |         for (int value : comArr) System.out.print(value + " ");
176 |         System.out.println();
177 |     }
178 | }
179 | 
180 | ```
181 | 
182 | - 중복을 허용하지 않는 조합(combination)
183 | 
184 | ```
185 | n : 3, r : 2
186 | 1 2 
187 | 1 3 
188 | 2 3 
189 | ```
190 | 
191 | - 중복을 허용하는 조합(reCombination)
192 | 
193 | ```
194 | n : 3, r : 2
195 | 1 1 
196 | 1 2 
197 | 1 3 
198 | 2 2 
199 | 2 3 
200 | 3 3 
201 | ```
202 | 
203 | 이처럼 조합은 [1,2]와 [2,1]은 순서가 고려되지 않아 같은 구성으로 생각된다.
204 | 
205 | 


--------------------------------------------------------------------------------
/Algorithm/이분 탐색(Binary Search).md:
--------------------------------------------------------------------------------
 1 | ### 이진 탐색(Binary Search)
 2 | 
 3 | - 이진 탐색 혹은 이분 탐색이라고 부른다.
 4 | - 이미 정렬되어 있는 자료 구조에서 특정 값을 찾을 때, 탐색 범위를 절반씩 나눠가면서 해당 값을 찾아가는 것이다.
 5 | - 즉, 탐색 범위를 두 부분으로 분할하면서 찾는 방식이다.
 6 | - 처음부터 끝까지 돌면서 탐색하는 것보다 훨씬 빠르다는 장점을 가지고 있다.
 7 | 
 8 | 
 9 | 
10 | **시간 복잡도**
11 | 
12 | - 전체 탐색 : O(N)
13 | - 이진 탐색 : O(logN)
14 | 
15 | 
16 | 
17 | **진행 순서**
18 | 
19 | - 정렬을 한다.
20 | - left와 right로 mid 값을 설정한다.
21 | - mid와 구하고자 하는 값을 비교한다.
22 | - 구할 값이 mid보다 크면 -> left = mid + 1
23 | - 구할 값이 mid보다 낮으면 -> right = mid - 1
24 | - right < left가 될 때까지 계속 반복한다.
25 | 
26 | 
27 | 
28 | **[Code]**
29 | 
30 | ```java
31 | package Study;
32 | 
33 | import java.util.Arrays;
34 | 
35 | /**
36 |  * created by victory_woo on 2020/04/30
37 |  */
38 | public class BinarySearch {
39 |     public static void main(String[] args) {
40 |         int[] arr = {2, 13, 6, 5, 12, 15, 23, 17, 19, 10,};
41 |         System.out.println(solution(17, arr));
42 |     }
43 | 
44 |     private static int solution(int target, int[] arr) {
45 |         Arrays.sort(arr);
46 |         int left = 0, right = arr.length - 1, mid = 0;
47 | 
48 |         while (left < right) {
49 |             mid = (left + right) / 2;
50 | 
51 |             if (target == arr[mid]) {
52 |                 System.out.println("Find Target : " + target + ", Value : " + arr[mid]);
53 |                 return arr[mid];
54 |             }
55 | 
56 |             if (target < arr[mid]) right = mid - 1;
57 |             else left = mid + 1;
58 |         }
59 | 
60 |         return -1;
61 |     }
62 | }
63 | ```
64 | 
65 | 
66 | 
67 | 결과를 찾은 경우, 찾았다는 메시지와 함께 찾은 결과를 반환한다. 결과를 찾지 못한 경우에는 -1을 반환한다.
68 | 
69 | 
70 | 
71 | ### 참고
72 | 
73 | - [[Java] 이진탐색(Binary Search)](https://blog.opid.kr/489)
74 | - [규글님 Github](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Algorithm/Binary%20Search.md)
75 | - [13. 이 탐색 (Binary Search)](https://code0xff.tistory.com/32)
76 | 


--------------------------------------------------------------------------------
/Algorithm/퀵 정렬(Quick Sort).md:
--------------------------------------------------------------------------------
  1 | ## 퀵 정렬(Quick Sort)
  2 | 
  3 | 
  4 | 
  5 | ### 개념
  6 | 
  7 | - 퀵 정렬은 분할 정복 방법을 통해 주어진 배열을 정렬한다.
  8 |   - **분할 정복(Divide and Conquer)** : 문제를 작은 2개의 문제로 분리하고 각각을 해결한 다음, 결과를 모아서 원래의 문제를 해결하는 전략이다.
  9 | - 불안정 정렬에 속하며, 다른 원소와의 비교만으로 정렬을 수행하는 비교 정렬에 속한다.
 10 | - 또한, Merge Sort와 달리 Quick Sort는 배열을 비균등하게 분할한다.
 11 | 
 12 | 
 13 | 
 14 | ### 로직
 15 | 
 16 | 1. 배열 가운데서 하나의 원소를 고른다. 이렇게 고른 원소는 피벗(pivot)이라고 한다.
 17 | 2. 피벗 앞에는 피벗보다 값이 작은 모든 원소들이 오고, 피벗 뒤에는 피벗보다 값이 큰 모든 원소들이 오도록 피벗을 기준으로 배열을 둘로 나눈다. 이렇게 배열을 둘로 나누는 것을 **분할**(Divide)이라고 한다. 분할을 마친 뒤에 피벗은 더 이상 움직이지 않는다.
 18 | 3. 분할 된 두 개의 작은 배열에 대해 재귀적으로 이 과정을 반복한다.
 19 | 
 20 | 재귀 호출이 한번 진행될 때마다 최소한 하나의 원소는 최종적으로 위치가 정해지므로, 이 알고리즘은 반드시 끝난다는 것을 보장할 수 있다.
 21 | 
 22 | 
 23 | 
 24 | - 분할(Divide) : 주어진 배열을 피벗을 기준으로 비균등하게 2개의 부분 배열로 분할한다.(피벗을 중으로 왼쪽 : 피벗보다 작은 요소들, 오른쪽 : 피벗보다 큰 요소들)
 25 | - 정복(Conquer) : 부분 배열을 정렬한다. 부분 배열의 크기가 충분히 작지 않으면 순환 호출을 이용해 다시 분할 정복 방법을 적용한다.
 26 | 
 27 | 
 28 | 
 29 | ```java
 30 |  private static void quickSort(int[] arr, int left, int right) {
 31 |         int L = left;
 32 |         int R = right;
 33 |         int pivot = arr[(left + right) / 2];
 34 |    			// 피벗을 배열의 가운데 위치한 요소로 설정.
 35 | 
 36 |         while (L <= R) {
 37 |           	// 피벗 왼쪽에는 피벗보다 작은 원소들이 위치해야 하고, 큰 원소가 있다면 반복문을 나온다.
 38 |             while (arr[L] < pivot) L++;
 39 | 			
 40 |           	// 피벗 오른쪽에는 피벗보다 큰 원소들이 위치해야 하고, 작은 원소가 있다면 반복문을 나온다.
 41 |             while (pivot < arr[R]) R--;
 42 | 
 43 |           	// L과 R이 역전되지 않고, 같은 경우가 아니라면 두 원소의 위치를 교환한다.
 44 |           	// 이를 통해서 피벗 기준으로 왼쪽에는 작은 원소가, 오른쪽에는 큰 원소가 위치하게 된다.
 45 |             if (L <= R) {
 46 |                 if (L != R) {
 47 |                     swap(arr, L, R);
 48 |                 }
 49 |                 L++;
 50 |                 R--;
 51 |             }
 52 |         }
 53 | 
 54 |    	// L과 R이 역전된 후에 피벗의 왼쪽과 오른쪽에는 정렬되지 않은 부분 배열이 남아있을 수 있다.
 55 |    	// 이 경우, 남아 있는 부분 배열에 대해서 퀵 정렬을 수행한다.
 56 |         if (left < R) quickSort(arr, left, R);
 57 | 
 58 |         if (L < right) quickSort(arr, L, right);
 59 |     }
 60 | 
 61 |     // 입력 받은 원소의 자리를 교환해준다.
 62 |     private static void swap(int[] arr, int left, int right) {
 63 |         int temp = arr[left];
 64 |         arr[left] = arr[right];
 65 |         arr[right] = temp;
 66 |     }
 67 | ```
 68 | 
 69 | 
 70 | 
 71 | ### Qucik Sort 개선
 72 | 
 73 | 위의 코드에서는 피벗을 배열의 가운데 원소로 지정함으로써 어느 정도 성능을 개선한 형태이다.
 74 | 
 75 | 하지만, 피벗 값이 최소나 최대값으로 지정되면 피벗을 기준으로 원소들이 들어갈 값을 찾는데 오래 걸린다. O(N^2)의 시간 복잡도를 갖는다.
 76 | 
 77 | 
 78 | 
 79 | 즉, 정렬하고자 하는 배열이 오름차순 혹은 내림차순 정렬되어 있으면 O(N^2)의 시간복잡도를 가진다. 이때, 배열에서 가장 앞에 있는 값과 중간값을 교환해준다면 확률적으로나마 시간 복잡도 O(N logN)으로 개선할 수 있다. 
 80 | 
 81 | 하지만, 이 방법으로 개선한다 하더라도 Quick Sort의 최악의 시간 복잡도가 O(N logN)이 되는 것은 아니다.
 82 | 
 83 | 
 84 | 
 85 | ### 시간 복잡도
 86 | 
 87 | 최선의 경우 : T(N) = O(N logN)
 88 | 
 89 | - 비교 횟수 : logN
 90 | 
 91 | 레코드의 개수 N이 2의 거듭제곱이라고 가정했을 때(N = 2^k), N = 2^3의 경우
 92 | 
 93 | 2^3 -> 2^2 -> 2^1 -> 2^0 순으로 줄어들어 순환 호출의 깊이가 3임을 알 수 있다.
 94 | 
 95 | ![img](https://github.com/GimunLee/tech-refrigerator/raw/master/Algorithm/resources/quick-sort-002.png)
 96 | 
 97 | 이것을 일반화하면 **N = 2^k의 경우, k = logN**임을 알 수 있다.
 98 | 
 99 | 
100 | 
101 | **[각 순환 호출 단계의 비교 연산]** (N)
102 | 
103 | 각 순환 호출에서는 전체 리스트의 대부분의 레코드를 비교해야 하므로 평균 N번 정도의 비교가 이루어진다.
104 | 
105 | 따라서, 최선의 시간 복잡도는 `순환 호출의 깊이(logn) x 각 순환 호출 단계의 비교 연산(n) = n logn`이 된다.
106 | 
107 | 이동 횟수는 비교 횟수보다 적으므로 무시할 수 있다.
108 | 
109 | 
110 | 
111 | 최악의 경우 : T(N) = O(N^2)
112 | 
113 | 최악의 경우는 정렬하고자 하는 배열이 오름차순 혹은 내림차순 정렬되어 있는 경우이다.
114 | 
115 | - 비교 횟수 : (N)
116 | 
117 | ![img](https://github.com/GimunLee/tech-refrigerator/raw/master/Algorithm/resources/quick-sort-003.png)
118 | 
119 | 레코드의 개수 N이 2의 거듭제곱이라고 가정했을 때(N = 2^k), 순환 호출의 깊이는 N임을 알 수 있다.
120 | 
121 | 
122 | 
123 | - 각 순환 호출 단계의 비교 연산
124 | 
125 | 각 순환 호출에서는 전체 리스트의 대부분의 레코드를 비교해야 하므로 평균 N번 정도의 비교가 이루어진다.
126 | 
127 | 따라서 최악의 시간 복잡도는 `순환 호출의 깊이 x 각 순환 호출 단계의 비교 연산 = N^2` 이다.
128 | 
129 | 이동횟수는 비교 횟수보다 적으므로 무시할 수 있다.
130 | 
131 | 
132 | 
133 | ### 공간 복잡도
134 | 
135 | 주어진 배열 안에서 교환을 통해 정렬이 수행되므로 O(N)이다.
136 | 
137 | 
138 | 
139 | ### 장점
140 | 
141 | - 불필요한 데이터의 이동을 줄이고 먼 거리의 데이터를 교환할 뿐만 아니라, 한번 결정된 피벗들이 추후 연산에서 제외되는 특성 때문에, 시간 복잡도가 O(N logN)을 가지는 다른 정렬 알고리즘과 비교했을 때도 가장 빠르다.
142 | - 정렬하고자 하는 배열 안에서 교환하는 방식이므로, 다른 메모리 공간을 필요로 하지 않는다.
143 | 
144 | 
145 | 
146 | ### 단점
147 | 
148 | - 불안정 정렬이다.
149 | - 정렬된 배열에 대해서는 Quick Sort의 불균형 분할에 의해 오히려 수행 시간이 더 많이 걸린다.
150 | 
151 | 
152 | 
153 | ### 결론
154 | 
155 | Quick Sort는 평균적으로 가장 빠른 정렬 알고리즘이다.
156 | 
157 | Java에서는 Arrays.sort()가 내부적으로 Dual Pivot Quick Sort로 구현되어 있을 정도로 효율적인 알고리즘이다.
158 | 
159 | 또한, 기술 면접에서 빈번하게 나오므로 반드시 숙지해야 한다.
160 | 
161 | 
162 | 
163 | ### 참고
164 | 
165 | - [퀵 정렬 (Quick Sort)](https://gyoogle.dev/blog/algorithm/Quick%20Sort.html)
166 | 


--------------------------------------------------------------------------------
/Algorithm/투포인터 알고리즘.md:
--------------------------------------------------------------------------------
  1 | ## 투포인터 알고리즘
  2 | 
  3 | 투포인터 알고리즘(Two Pointers Algorithm) 또는 슬라이딩 윈도우(Sliding Window)라고 부른다. 이번에 20년도 상반기 라인 공채 코딩 테스트에서 이를 활용할 만한 문제가 나왔다. 그래서 예전에 정리했던 내용을 떠올리며, 다시 정리하려 글을 쓴다.
  4 | 
  5 | 
  6 | 
  7 | 알고리즘 문제를 풀다 완전탐색으로 해결하면 시간 초과가 나는 문제가 종종 있다. 어떻게 풀어야 하는지 그 당시 검색했을 때, `투 포인터 알고리즘` 이 대안이었다.
  8 | 
  9 | > 1차원 배열이 있고, 이 배열에서 각자 다른 원소를 가리키고 있는 2개의 포인터를 조작해가면서 원하는 것을 얻는 형태이다. 이때문에 투포인터 알고리즘이라 부른다.
 10 | 
 11 | 
 12 | 
 13 | N칸의 1차원 배열이 있을 때, 부분 배열 중 그 원소의 합이 M이 되는 경우의 수를 구하는 것이다. 모든 경우의 수를 다 테스트 해보면 구간 합을 구간 배열로 O(1)만에 구한다고 해도 경우의 수는 O(N^2)이 된다. 따라서 문제를 풀 수 없다. N의 최대 범위가 너무 크기 때문이다. 
 14 | 
 15 | 
 16 | 
 17 | 이 문제에서 각 원소는 자연수이고 M 또한 자연수인데, 이 조건이 성립하면 사용할 수 있는 알고리즘은 다음과 같다.
 18 | 
 19 | - 포인터 2개를 준비한다. 시작과 끝을 알 수 있도록 start, end 라고 한다.
 20 | - 맨 처음에는 start = end = 0이며, 항상 start<=end을 만족해야 한다.
 21 | - 2개의 포인터는 현재 부분 배열의 시작과 끝을 가리키는 역할을 한다.
 22 | 
 23 | s=e일 경우 그건 크기가 0인, 아무것도 포함하지 않는 부분 배열을 뜻한다. 다음의 과정을 s < N인 동안 반복한다.
 24 | 
 25 | 1. 만약 현재 부분합이 M 이상이거나, 이미 e = N이면 s++
 26 | 2. 그렇지 않다면 e++
 27 | 3. 현재 부분합이 M과 같으면 결과 ++ 
 28 | 
 29 | 쉽게 이해하자면, start와 end 를 무조건 증가시키는 방향으로만 변화시켜가면서 도중에 부분 배열의 합이 정확히 M이 되는 경우를 세는 것이다. 
 30 | 
 31 | 
 32 | 
 33 | Ex) M = 5인 경우를 살펴보자.
 34 | 
 35 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_56/kks227_1471976777631dvMpe_PNG/1.png?type=w2)
 36 | 
 37 | 초기 상태이며, 빨간색 포인터 : start, 파란색 포인터 : end이다. S : 합.
 38 | 
 39 | **end**가 뒤로 움직일 때는 새로 포함한 원소를 S에 더하고, **start**가 뒤로 움직일 때는 새로 넘긴 원소를 S에서 빼는 식으로 현재 [start, end)의 합 S를 매번 쉽게 구할 수 있다.
 40 | 
 41 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_196/kks227_1471976777962Qks67_PNG/2.png?type=w2)
 42 | 
 43 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_274/kks227_1471976778508STsIS_PNG/3.png?type=w2)
 44 | 
 45 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_118/kks227_1471976778842HkF4H_PNG/4.png?type=w2)
 46 | 
 47 | 처음에는 이렇게 end만 증가하게 된다. S가 계속 M보다 작기 때문! 마지막엔 S>=M이 되었으므로 아래와 같다.
 48 | 
 49 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_101/kks227_1471976779156aosTT_PNG/5.png?type=w2)
 50 | 
 51 | start를 한 칸 옮겼는데, 동시에 S = 5인 경우를 만났다. 이때 결과를 1 증가시켜 준다.
 52 | 
 53 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_186/kks227_1471976779456z8WVP_PNG/6.png?type=w2)
 54 | 
 55 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_1/kks227_1471976779887ko5yw_PNG/7.png?type=w2)
 56 | 
 57 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_265/kks227_1471976780291PDw0Y_PNG/8.png?type=w2)
 58 | 
 59 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_139/kks227_1471976780603hkxD5_PNG/9.png?type=w2)
 60 | 
 61 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_284/kks227_1471976780877YjQiA_PNG/10.png?type=w2)
 62 | 
 63 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_101/kks227_1471976781212P3Li0_PNG/11.png?type=w2)
 64 | 
 65 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_188/kks227_14719767815252r1eQ_PNG/12.png?type=w2)
 66 | 
 67 | 이런 식으로 포인터들이 움직이게 된다. 여기서 2번째로 S = 5인 지점을 만났으므로 결과를 1 증가시켜 준다.
 68 | 
 69 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_80/kks227_14719767817475h0eo_PNG/13.png?type=w2)
 70 | 
 71 | 그 직후, start가 1 증가하면서 start = end인 경우가 나온다.
 72 | 
 73 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_240/kks227_1471976782107sRHbv_PNG/14.png?type=w2)
 74 | 
 75 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_240/kks227_14719767826459iErQ_PNG/15.png?type=w2)
 76 | 
 77 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_192/kks227_1471976782977RS8E6_PNG/16.png?type=w2)
 78 | 
 79 | 계속 가다 보면 세 번째로 S = 5인 지점을 만난다.
 80 | 
 81 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_147/kks227_1471976783270H1Bah_PNG/17.png?type=w2)
 82 | 
 83 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_44/kks227_1471976783607C4F3g_PNG/18.png?type=w2)
 84 | 
 85 | 그 이후 조건에 맞춰 포인터를 증가시키다 보면, end가 배열 끝을 가리키게 되어 더이상 증가할 수 없는 상태가 된다.
 86 | 
 87 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_197/kks227_1471976784071FLqRR_PNG/19.png?type=w2)
 88 | 
 89 | ![img](https://mblogthumb-phinf.pstatic.net/20160824_87/kks227_14719767845214em80_PNG/20.png?type=w2)
 90 | 
 91 | 그렇게 되면 그냥 start만 증가시켜 가다가 start 역시 배열 끝에 다다르면 종료해도 되고, 그냥 그 자리에서 루프를 끝내버려도 된다. 이렇게 해서 S = 5인 경우는 3개 발견되었다.
 92 | 
 93 | 
 94 | 
 95 | - 시간 복잡도 
 96 |   - 이 알고리즘은 매 루프마다 항상 두 포인터 중 하나는 1씩 증가하고 있고, 각 포인터가 N번 누적 증가해야 알고리즘이 끝난다. 따라서 각각 배열 끝에 다다르는데 O(N)이라서 합쳐도 O(N)이 된다.
 97 | - **추천 문제(백준 기준)**
 98 |   - 2003 : 수들의 합
 99 |   - 1644 : 소수의 연속합
100 |   - 1806 : 부분합
101 |   - 2230 : 수 고르기
102 |   - 1484 : 다이어트
103 |   - 2038 : 골룽 수열
104 |   - 2531 : 회전 초밥
105 |   - 2096 : 내려가기
106 |   - 2293 : 동전1
107 | 
108 | 
109 | 
110 | ## 참고
111 | 
112 | - [투 포인터(Two Pointers Algorithm), 슬라이딩 윈도우(Sliding Window) (수정: 2019-09-09)](https://m.blog.naver.com/kks227/220795165570)
113 | 


--------------------------------------------------------------------------------
/Algorithm/힙 정렬(Heap Sort).md:
--------------------------------------------------------------------------------
  1 | ## 힙 정렬(Heap Sort)
  2 | 
  3 | 완전 이진 트리를 기본으로 하는 힙 자료구조를 기반으로 한 정렬 방식이다.
  4 | 
  5 | 불안정 정렬에 속한다.
  6 | 
  7 | [완전 이진 트리?]
  8 | 
  9 | - 삽입할 때, 왼쪽부터 차례대로 추가하는 이진 트리
 10 | 
 11 | 
 12 | 
 13 | 
 14 | 
 15 | ### 시간 복잡도
 16 | 
 17 | - 평균 : O(N logN)
 18 | - 최선 : O(N logN)
 19 | - 최악 : O(N logN)
 20 | 
 21 | 
 22 | 
 23 | ### 로직
 24 | 
 25 | 1. 최대 힙을 구성한다.
 26 | 2. 현재 힙 루트는 가장 큰 값이 존재한다. 루트의 값을 마지막 요소와 바꾼 후, 힙의 사이즈를 하나 줄인다.
 27 | 3. 힙의 사이즈가 1보다 크면 위의 과정을 반복한다.
 28 | 
 29 | ![img](https://camo.githubusercontent.com/0104a65c5df44c342e310a24c1becd08c9596367/68747470733a2f2f74312e6461756d63646e2e6e65742f6366696c652f746973746f72792f393939383936343435414434393533303233)
 30 | 
 31 | 루트 노드를 마지막 노드로 대체한다. (11->4) 그리고 다시 최대 힙 구성.
 32 | 
 33 | ![img](https://camo.githubusercontent.com/000e4568cdab087691478961e100c8290df3af31/68747470733a2f2f74312e6461756d63646e2e6e65742f6366696c652f746973746f72792f393945314144343435414434393533303135)
 34 | 
 35 | 이와 같은 방식으로 최대 값을 하나씩 뽑아내면서 정렬하는 것이 Heap Sort이다.
 36 | 
 37 | ```java
 38 | private static void heapSort(int[] arr) {
 39 |         int n = arr.length;
 40 | 
 41 |   			// max heap 초기화.
 42 |         for (int i = (n / 2) - 1; i >= 0; i--) {
 43 |             heapify(arr, n, i); // 1
 44 |         }
 45 | 
 46 |   			// extract 연산. 
 47 |         for (int i = n - 1; i > 0; i--) {
 48 |             swap(arr, 0, i);
 49 |             heapify(arr, i, 0);
 50 |         }
 51 |     }
 52 | ```
 53 | 
 54 | 
 55 | 
 56 | 1번째 heapify
 57 | 
 58 | - 일반 배열을 힙으로 구성하는 역할을 한다.
 59 | - 자식노드로부터 부모 노드를 비교한다.
 60 | - (n/2)-1부터 0까지 인덱스를 돌리는 이유는?
 61 |   - 부모 노드의 인덱스를 기준으로 왼쪽 자식 노드 : ix2+1, 오른쪽 자식 노드 : ix2+2이기 때문이다.
 62 | 
 63 | 
 64 | 
 65 | 2번째 heapify
 66 | 
 67 | - 요소 하나가 제거된 이후에 다시 최대 힙을 구성하기 위함이다.
 68 | - 루트를 기준으로 진행한다.
 69 | 
 70 | ```java
 71 | private static void heapify(int[] arr, int n, int i) {
 72 |         int p = i; // 부모 노드.
 73 |         int l = i * 2 + 1; // 왼쪽 자식 노드.
 74 |         int r = i * 2 + 2; // 오른쪽 자식 노드.
 75 | 
 76 |         // 왼쪽 자식 노드와 부모 노드를 비교하여 큰 값을 부모 노드로 올린다.
 77 |         if (l < n && arr[p] < arr[l]) p = l;
 78 | 
 79 |         // 오른쪽 자식 노드와 부모 노드를 비교하여 큰 값을 부모 노드로 올린다.
 80 |         if (r < n && arr[p] < arr[r]) p = r;
 81 | 
 82 |         // 부모 노드를 가리키는 p 값이 바뀌면 위치를 교환하고
 83 |         // heapify()를 호출하여 과정을 반복한다.
 84 |         if (i != p) {
 85 |             swap(arr, p, i);
 86 |             heapify(arr, n, p);
 87 |         }
 88 |     }
 89 | ```
 90 | 
 91 | - 다시 최대 힙을 구성할 때까지 부모 노드와 자식 노드를 swap 하며 재귀를 호출한다.
 92 | - 퀵 정렬과 합병 정렬의 성능이 좋기 때문에 힙 정렬의 사용 빈도가 높지는 않다.
 93 | - 하지만, 힙 자료구조가 많이 활용되고 있으며, 이때 함께 따라오는 개념이 Heap Sort이다.
 94 | - Heap Sort가 유용할 때
 95 |   - **가장 크거나 가장 작은 값을 구할 때** : 최소 힙 or 최대 힙의 루트 값이기 때문에 한 번의 힙 구성을 통해 구하는 것이 가능하다.
 96 |   - **최대 k 만큼 떨어진 요소들을 정렬할 때** : 삽입 정렬보다 더욱 개선된 결과를 얻어낼 수 있다.
 97 | 
 98 | 
 99 | 
100 | **[Source Code]**
101 | 
102 | ```java
103 | package sort;
104 | 
105 | /**
106 |  * created by victory_woo on 2020/03/14
107 |  */
108 | public class HeapSort {
109 |     public static void main(String[] args) {
110 |         int[] arr = {230, 10, 60, 550, 40, 220, 20};
111 |         heapSort(arr);
112 | 
113 |         for (int i = 0; i < arr.length; i++) System.out.print(arr[i] + " ");
114 |     }
115 | 
116 |     private static void heapSort(int[] arr) {
117 |         int n = arr.length;
118 | 
119 |         // max heap 초기화.
120 |         for (int i = (n / 2) - 1; i >= 0; i--) {
121 |             heapify(arr, n, i);
122 |         }
123 | 
124 |         for (int i = n - 1; i > 0; i--) {
125 |             swap(arr, 0, i);
126 |             heapify(arr, i, 0);
127 |         }
128 |     }
129 | 
130 |     private static void heapify(int[] arr, int n, int i) {
131 |         int p = i; // 부모 노드.
132 |         int l = i * 2 + 1; // 왼쪽 자식 노드.
133 |         int r = i * 2 + 2; // 오른쪽 자식 노드.
134 | 
135 |         // 왼쪽 자식 노드와 부모 노드를 비교하여 큰 값을 부모 노드로 올린다.
136 |         if (l < n && arr[p] < arr[l]) p = l;
137 | 
138 |         // 오른쪽 자식 노드와 부모 노드를 비교하여 큰 값을 부모 노드로 올린다.
139 |         if (r < n && arr[p] < arr[r]) p = r;
140 | 
141 |         // 부모 노드를 가리키는 p 값이 바뀌면 위치를 교환하고
142 |         // heapify()를 호출하여 과정을 반복한다.
143 |         if (i != p) {
144 |             swap(arr, p, i);
145 |             heapify(arr, n, p);
146 |         }
147 |     }
148 | 
149 |     private static void swap(int[] arr, int a, int b) {
150 |         int temp = arr[a];
151 |         arr[a] = arr[b];
152 |         arr[b] = temp;
153 |     }
154 | 
155 | }
156 | ```
157 | 
158 | 
159 | 
160 | ### 참고
161 | 
162 | - [힙 정렬(Heap Sort)]([https://gyoogle.dev/blog/algorithm/Heap%20Sort.html](https://gyoogle.dev/blog/algorithm/Heap Sort.html))
163 | 
164 | 


--------------------------------------------------------------------------------
/Android/4대 컴포넌트.md:
--------------------------------------------------------------------------------
 1 | ## 4대 컴포넌트
 2 | 
 3 | Android 앱은 컴포넌트로 구성되어 있다. Activity, Service, Broadcast Receiver, Content Provider이다. 이를 4대 컴포넌트라 부른다.
 4 | 
 5 | 각 컴포넌트들은 하나의 독립된 형태로 존재하며, 정해진 역할을 수행한다. 컴포넌트들 간의 상호 통신은 **Intent**라는 일종의 메시지 객체를 사용하여 상호 통신을 진행한다.
 6 | 
 7 | **Activity**
 8 | 
 9 | - `사용자 인터페이스 화면`을 가지며 특정 작업을 담당하는 컴포넌트
10 | - UI를 갖는 하나의 스크린을 나타낸다.
11 | - 최소 하나 이상의 Activity를 가지고 있어야 한다.
12 | - 매니페스트 파일에 등록되어야 한다.
13 | - 하나 이상의 View를 가질 수 있다.
14 | 
15 | **Service**
16 | 
17 | - `백그라운드`에서 실행되는 컴포넌트로 오랫동안 실행되는 작업이나 원격 프로세스를 위한 작업을 할 때 사용된다.
18 | - UI가 없다.
19 | - 한 번 시작된 Service는 애플리케이션이 종료되고 다른 앱으로 이동해도 계속 백그라운드에서 실행된다.
20 | - ex) 음악 재생, 네트워크를 통해 데이터를 꺼내오는 작업 등등
21 | 
22 | **Broadcast Receiver**
23 | 
24 | - 안드로이드 `단말기`에서 발생하는 다양한 `이벤트, 정보`를 받고 반응하는 컴포넌트이다.
25 | - 단말기에서 발생하는 일 중 애플리케이션이 알아야 하는 상황이 발생하면 방송해준다.
26 | - 수신기를 통해 상황을 감지하고 적절한 작업을 수행한다.
27 | - UI 가 없다.
28 | - ex) 배터리 부족,시스템 부팅, 전화나 문자 수신 등등.
29 | 
30 | **Content Provider**
31 | 
32 | - 데이터를 관리하고 다른 애플리케이션 데이터를 제공하는 컴포넌트.
33 | - 데이터는 파일 시스템이나 SQLite 데이터베이스, 웹 상에 저장될 수 있다.
34 | 
35 | **Intent**
36 | 
37 | - 독립적으로 동작하는 4대 컴포넌트들 간의 상호 통신을 위한 장치이다.
38 | - 4대 컴포넌트의 통신 수단
39 | - 인텐트를 통해 다른 애플리케이션의 컴포넌트를 활성화 시킬 수 있다.


--------------------------------------------------------------------------------
/Android/Activity Lifecycle.md:
--------------------------------------------------------------------------------
 1 | ## Activity Lifecycle
 2 | 
 3 | **onCreate()**
 4 | 
 5 | - 액티비티가 만들어지고 나서 최초에 실행될 때 호출된다. (한 번만 호출된다.)
 6 | - 액티비티에 필요한 리소스 초기화, View들의 일반적인 상태 설정.
 7 | - 이전 상태가 저장되어 있을 경우, 번들 객체를 참조하여 이전 상태로 복원이 가능하다.
 8 | - 다음으로 onStart()가 호출된다.
 9 | 
10 | **onStart()**
11 | 
12 | - 액티비티가 화면에 보이기 바로 전에 호출된다.
13 | - 매우 빠르게 끝나고 onResume() 단계로 넘어간다.
14 | - 액티비티가 시작되기 전에 호출되는 함수, 액티비티가 멈춘 후 다시 시작되기 전에 호출되는 함수.
15 | 
16 | **onResume()**
17 | 
18 | - 액티비티가 사용자와 상호작용하기 바로 직전에 호출되는 함수.
19 | - 이 함수가 호출되고 나서 바로 액티비티가 사용자에게 보인다.
20 | - 액티비티가 화면에 보인다.
21 | - 사용자에게 Focus를 잡은 상태이다.
22 | 
23 | **onRestart()**
24 | 
25 | - 액티비티가 **중지된(Stopped)** 이후에 호출되는 메소드로 다시 시작되기 바로 전에 호출된다.
26 | - 액티비티가 멈춰 있다가 다시 호출될 때 불리는 함수.
27 | 
28 | **`다른 액티비티가 호출되는 경우`**
29 | 
30 | **onPause()**
31 | 
32 | - 다른 액티비티가 위에 올라와서 Focus를 잃었을 때 호출된다.
33 | - 액티비티가 완전히 가려지지 않고, **부분만 가려진 상태**에서 호출되는 함수이다. 즉, 일부분이 보이거나 투명상태일 경우에 호출된다.
34 | - 다른 액티비티가 호출되기 전에 실행되기 때문에 onPause() 함수에서 시간이 많이 소요되는 작업이나 많은 일을 처리하면 다른 액티비티가 호출되는 시간이 지연되기 때문에 많은 일을 처리하지 않도록 한다.
35 | - 영구적인 Data는 여기서 저장한다.
36 | - 액티비티가 이 상태에 들어가면 시스템은 액티비티를 강제 종료할 수 있다.
37 | - ex) A 액티비티에서 B 액티비티를 호출하는 경우, A 액티비티의 onPause() 함수가 먼저 호출되고 나서 B 액티비티가 실행된다.
38 | 
39 | **onStop()**
40 | 
41 | - 액티비티 위에 **다른 액티비티가 완전히 올라와 100% 가려질 때** 호출되는 함수.
42 | - 액티비티가 사용자에게 더 이상 보이지 않을 때 호출된다.
43 | - 이 상태에서 액티비티가 다시 불려지면 `onRestart()` 함수가 호출된다.
44 | 
45 | **onDestroy()**
46 | 
47 | - 액티비티가 완전히 스택에서 없어질 때 호출되는 함수.
48 | - 즉, 제거되는 경우.
49 | - finish() 메소드가 호출되거나 시스템 메모리 확보를 위해서 시스템이 강제로 종료시키는 경우에 호출될 수 있다.


--------------------------------------------------------------------------------
/Android/Android_Interview.md:
--------------------------------------------------------------------------------
 1 | ### Android - 인터뷰 질문
 2 | 
 3 | Q. Android의 4대 컴포넌트에 관한 설명
 4 | 
 5 | Q. Activity, Fragment의 차이점은?
 6 | 
 7 | Q. Activity, Fragment의 생명주기에 대한 설명
 8 | 
 9 | Q. ListView vs RecyclerView
10 | 
11 | Q. Intent에 관한 설명
12 | 
13 | Q. Android에서 Thread 구조에 대한 설명
14 | 
15 | Q. ANR이란?
16 | 
17 | Q. Thread, Looper, Handler에 대한 설명
18 | 
19 | Q. Annotation이란?
20 | 
21 | Q. Context란?
22 | 
23 | Q. Inflate란?
24 | 
25 | Q. Singleton 패턴에 관한 설명
26 | 
27 | Q. MVC, MVP, MVVM 각각에 대한 설명
28 | 
29 | Q. Dependency Injection이란?
30 | 
31 | Q. Koin vs Dagger 비교해서 설명
32 | 
33 | Q. SharedPreferences란?
34 | 
35 | Q. Image Loading 라이브러리에 대한 설명
36 | 
37 | Q. DiffUtil이란?
38 | 
39 | Q. 함수형 프로그래밍이란?
40 | 
41 | Q. 직렬화 vs 역직렬화에 대한 설명
42 | 
43 | Q. Java vs Kotlin에 관한 설명
44 | 
45 | Q. RxJava에서 map, flatMap의 차이점
46 | 
47 | Q. Immutable이란?
48 | 
49 | Q. Android enum을 자제시키는 이유는?
50 | 
51 | Q. Android Process와 Thread에 대한 설명


--------------------------------------------------------------------------------
/Android/Android에서 Enum 사용.md:
--------------------------------------------------------------------------------
 1 | ## Android에서 Enum 사용
 2 | 
 3 | - Android에서 Enum 사용을 자제시키는 이유
 4 | 
 5 | Enum의 각 값은 객체이며, 각 선언은 단순히 객체를 참조하기 위해서 런타임 메모리를 사용한다. 따라서 정수 또는 문자열 상수보다 더 많은 메모리를 차지하게 된다.
 6 | 
 7 | 게다가 단일 Enum을 추가하면 최종 DEX 파일의 크기를 증가시키기에 런타임시 오버헤드가 발생할 수 있고, 앱의 크기가 증가하게 된다.
 8 | 
 9 | 안드로이드에서는 Enum 대신 TypeDef 어노테이션의 사용을 권장한다.
10 | 
11 | 


--------------------------------------------------------------------------------
/Android/RecyclerView's setHasFixedSize.md:
--------------------------------------------------------------------------------
 1 | ### 서론
 2 | 
 3 | ***RecyclerView***는 앱에서 거의 필수적인 존재라고 생각이 든다. 대부분의 서비스가 리스트 형식이 존재하기 때문이다. 이렇듯 리스트를 효율적으로 보여주기 위해 사용하는 것이 ***RecyclerView***이다. 그렇다면 우리가 자주 사용하는 `setHasFixedSize`를 true로 설정한다는 게 무엇을 의미할까??
 4 | 
 5 | 
 6 | 
 7 | ### 본론
 8 | 
 9 | 
10 | 
11 | 필자는 `setHasFixedSize = true`의 문장을 별 의미 없이 타이핑했다. 이렇게 하는 것은 정말 좋지 않은 습관이다. 필자도 이 코드만 이렇게 했을 뿐, 다른 코드는 다 생각하고 작성한다. 아무튼, 저 함수는 무엇을 의미하는지 살펴보자.
12 | 
13 | 
14 | 
15 | 
16 | 
17 | ***[setHasFixedSize]***
18 | 
19 | - [StackOverflow](https://stackoverflow.com/questions/28709220/understanding-recyclerview-sethasfixedsize)의 답변을 해석했다.
20 | 
21 | - 아래의 함수를 보자
22 | 
23 | ```java
24 | void onItemsInsertedOrRemoved() {
25 | 
26 |    if (hasFixedSize) layoutChildren();
27 | 
28 |    else requestLayout();
29 | 
30 | }
31 | ```
32 | 
33 | 
34 | 
35 | - 기본적으로 아이템을 삽입, 이동 혹은 제거할 때마다 RecyclerView의 크기 및 너비나 높이가 변경될 수 있으며, 뷰 계층 구조의 다른 뷰의 크기가 변경될 수 있다.
36 | 
37 | - 따라서 항목을 자주 추가하거나 제거하는 경우, 특히 문제가 될 수 있다.
38 | 
39 | - 어댑터의 내용을 변경해도 높이나 너비가 변경되지 않는 경우, setHasFixedSize를 true로 설정하여 불필요한 레이아웃 패스를 피하라.
40 | 
41 | 
42 | 
43 | 
44 | 
45 | 결국, 아이템 항목을 추가할 때마다 RecyclerView의 크기는 변경된다. ***크기가 변경되기 때문에 레이아웃을 그릴 때, 크기를 측정하고 다시 그리는 것을 반복할 것이다.*** `setHasFixedSize`의 기능은 RecyclerView의 크기 변경이 일정하다는 것을 사용자의 입력으로 확인한다. 항목의 높이나 너비가 변경되지 않으며, 추가 또는 제거된 모든 항목은 동일하다. `setHasFixedSize`를 설정하지 않으면 항목의 크기가 변경되어 비용이 많이 드는 작업을 하는지 확인한다.
46 | 
47 | 
48 | 
49 | ### 결론
50 | 
51 | 대부분 RecyclerView를 사용하는 목적은 동일한 크기의 아이템 항목을 사용자에게 리스트로 보여주기 위해서다. 따라서 아이템의 크기가 변하는 경우는 없을 것이고, 그렇다면 ***setHasFixedSize를 true로 설정함으로써 변경되지 않는다는 것을 명시하는게 좋다.*** 따라서 레이아웃을 다시 그리는 비용이 많이 드는 작업을 피하도록 하여 성능 하락을 방지할 수 있다고 생각한다. 
52 | 
53 | 
54 | 
55 | 
56 | 
57 | **Reference**
58 | 
59 | - [stack overflow](https://stackoverflow.com/questions/28709220/understanding-recyclerview-sethasfixedsize)
60 | 
61 | - [안드로이드 리사이클러뷰 사용법](https://godog.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EB%A6%AC%EC%82%AC%EC%9D%B4%ED%81%B4%EB%9F%AC%EB%B7%B0RecyclerView-1)


--------------------------------------------------------------------------------
/Data Structure/Trie(트라이).md:
--------------------------------------------------------------------------------
 1 | ## Trie(트라이)
 2 | 
 3 | ### Trie 자료구조란?
 4 | 
 5 | - 일반 트리 자료구조 중 하나로, Digital Tree, Radix Tree, Prefix Tree라고도 불린다.
 6 | 
 7 | - 텍스트 자동 완성 기능과 같이 문자열을 저장하고 탐색하는데 유용한 자료구조이다.
 8 | 
 9 | 
10 | 
11 | ### Trie 자료구조의 형태는?
12 | 
13 | - 각 노드는 <Key, Value> 맵을 가지고 있다. **Key**는 하나의 알파벳이 되고, **Value**는 그 Key에 해당하는 자식 노드가 된다. 
14 | 
15 | - 다음은 DEV, DEAR, PIE, POP, POW라는 단어가 들어있는 Trie 자료구조를 도식화한 것이다. 휴대폰 전화번호부에서 검색을 하거나 사전에서 단어를 찾는 것과 같다.
16 | 
17 | - 예를 들어, 아래 그림에서 'DEV'라는 문자열을 찾으려면 루트 노드에서부터 순차적으로 [D] -> [E] -> [V] 를 탐색한다.
18 | 
19 | 
20 | 
21 | 
22 | <img src="https://woovictory.github.io/img/trie_sample.png" />
23 | 
24 | 
25 | 
26 | - 그림에서 볼 수 있듯이 `루트 노드는 특정 문자를 의미하지 않고, 자식 노드만 가지고 있다.`
27 | - 유의할 점은 **'부모 노드'나 '자신이 어떤 알파벳(Key)에 해당하는 노드(Value)'인지를 가지고 있는게 아니라는 점입니다.**
28 | 
29 | 
30 | 
31 | 
32 | 
33 | - 즉, 루트 노드는 [D], [P]라고 하는 알파벳을 Key로 하는 자식 노드들을 가지고 있고, [D]는 [E]를 Key로 하는 자식 노드, [P]는 [I]와 [O]를 Key로 하는 자식 노드들을 가지고 있는 것이다.
34 | 
35 | - 또 루트 노드를 제외한 `노드의 자손들은 해당 노드와 공통 접두어를 가진다는 특징이 있다.` 즉, 'DE' 노드의 자손인 'DEAR'와 'DEV'는 'DE-'를 공통 접두어로 가지며, 'P'의 자손인 'POW'와 'PIE'는 'P-'를 공통 접두어로 가진다.
36 | 
37 | 
38 | 
39 | <img src="https://woovictory.github.io/img/trie_sample2.png"/>
40 | 
41 | 
42 | 
43 | ### Trie 자료구조의 특징
44 | 
45 | -  정렬된 트리 구조이다.(데이터에 따라 이진트리일 때도 있다.)
46 | 
47 | - Trie는 자식 노드를 Map<Key, Value> 형태로 가지고 있다.
48 | 
49 | - 루트 노드를 제외한 노드의 자손들은 해당 노드와 공통 접두어를 가진다.
50 | 
51 | - 루트 노드는 빈 문자와 연관있다.(특정 문자가 할당되어 있지 않다.)
52 | 
53 | 
54 | 
55 | ## 참고
56 | - [[자료구조] Trie(트라이)-1 : 기초 개념](https://the-dev.tistory.com/2)
57 | 


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] Array vs LinkedList.md:
--------------------------------------------------------------------------------
 1 | ## Array vs LinkedList
 2 | 
 3 | Array와 LinkedList의 비교이다.
 4 | 
 5 | 
 6 | 
 7 | - Array
 8 |   - 배열이며, 논리적 저장순서와 물리적 저장순서가 일치한다.
 9 |   - 특정 자료형들이 메모리 공간 상에서 연속적으로 이루어져 있다.
10 |   - immutable하다.
11 |   - 인덱스로 해당 원소에 접근할 수 있으며, 인덱스를 알고 있다면 O(1)의 시간 복잡도로 원소에 접근이 가능하다. 즉, `Random Access`가 가능하다.
12 |   - 삭제 또는 삽입 과정에서는 해당 원소에 접근하여 작업을 완료한 뒤, shift해줘야 하므로 비용이 발생한다. O(n)
13 |   - 메모리 공간 활용에 제약이 있다.
14 | 
15 | 
16 | 
17 | - LinkedList
18 |   - 데이터 검색 시 처음 노드부터 순회해야 한다. 이유는 논리적 저장 순서와 물리적 저장 순서가 다르기 때문이다. O(n)
19 |   - 메모리 공간 상에서 각 노드들이 연속적으로 이루어져 있지 않고 흩어져 있으며, 각각의 노드가 자신의 다음 노드의 위치를 알고 있는 형태이다. 
20 |   - 각 노드들이 메모리 공간 상의 어디에 위치하는지는 각각의 노드들만 알고 있고, 사용자는 제일 첫 번째 노드의 위치만 알고 있는 상태이다.
21 |   - 어떤 원소를 삽입, 삭제 시 그 원소를 찾기 위해 O(n)의 시간이 발생하고 추가적으로 작업을 완료하는 시간까지 O(n)의 시간이 걸린다.
22 |   - 결국, LinkedList는 검색과 삽입, 삭제 과정 모두 O(n)의 시간 복잡도를 갖는다.
23 | 
24 | 
25 | 
26 | ### 데이터 접근 속도
27 | - Array
28 |   - 인덱스를 사용하여 빠르게 접근하므로 시간 복잡도는 O(1)이다. 
29 |   - Random Access가 가능하다.
30 | - LinkedList
31 |   - 특정 원소에 접근하기 위해서는 처음부터 순차적으로 검색하기 때문에 시간 복잡도는 O(N)이다.
32 | 
33 | 
34 | 
35 | ### 데이터 삽입 속도
36 | 
37 | - Array
38 |   - 데이터를 중간이나 맨 앞에 삽입할 경우, 이후의 데이터를 Shift해야 하므로 추가 과정과 시간이 소요된다. 
39 |   - 따라서 데이터가 많은 경우, 비효율적이다.
40 |   - O(N)의 시간이 걸린다.
41 | - LinkedList
42 |   - 중간 삽입 없이 맨 앞과 맨 뒤에만 삽입한다면 O(1)의 시간 복잡도를 갖는다.
43 |   - 그렇지 않다면 삽입할 위치를 찾고(O(N))과 삽입 연산을 진행하기 때문에 O(N)의 시간 복잡도를 갖는다.
44 |   - 그럼에도 불구하고 Array보다 빠른 성능을 갖는다.
45 | 
46 | Array의 경우, 데이터를 삽입하여 모든 공간이 꽉 차게 되면 새로운 메모리 공간을 할당받아 옮겨야 하지만, LinkedList를 그럴 필요가 없다. 추가할 때마다 동적으로 메모리 공간을 할당받는다.
47 | 
48 | 
49 | 
50 | ### 데이터 삭제 속도
51 | 
52 | - Array
53 |   - 데이터 삭제의 경우, 그 위치의 데이터를 삭제한 후 전체적으로 Shift해줘야 하기 때문에 O(N)의 시간 복잡도를 갖는다.
54 | - LinkedList
55 |   - 삭제할 원소를 찾기 위해 O(N)의 시간 복잡도를 갖고 삭제한다. 하지만, Array보다 빠르게 삭제 연산을 수행한다.
56 | 
57 | 
58 | 
59 | ### 메모리 할당
60 | 
61 | - Array 
62 |   - 메모리에는 Array가 선언되자 마자 Compile time에 할당되어 진다.
63 |   - 정적 메모리 할당이라고 한다.
64 | - LinkedList
65 |   - 메모리는 새로운 Node가 추가될 때 runtime에 할당되어 진다.
66 |   - 동적 메모리 할당이라고 한다. 
67 | 
68 | 
69 | 
70 | ### 결론
71 | 
72 | - 삽입과 삭제가 빈번하게 일어난다면 LinkedList를 사용하는 것이 좋다.
73 | - 데이터에 접근하는 것이 빈번하게 일어난다면 Array를 사용하는 것이 좋다.
74 | 


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] B Tree & B+ Tree.md:
--------------------------------------------------------------------------------
 1 | ## B Tree & B+ Tree
 2 | 
 3 | > 이진 트리는 하나의 부모가 두 개의 자식밖에 가지지 못하고, 균형이 맞지 않으면 검색 효율이 선형 검색 급으로 떨어진다. 하지만 이진 트리 구조의 간결함과 균형만 맞다면 검색, 삽입, 삭제 모두 O(logN)의 성능을 보이는 장점이 있기 때문에 계속 개선시키기 위한 노력이 이루어지고 있다.
 4 | 
 5 | 
 6 | 
 7 | ### [B Tree]
 8 | 
 9 | - 데이터 베이스, 파일 시스템에서 널리 사용되는 트리 자료구조의 일종이다.
10 | 
11 | - 이진 트리를 확장해서, 더 많은 수의 자식을 가질 수 있게 일반화 시킨 것이 B Tree.
12 | 
13 | - 자식 수에 대한 일반화를 진행하면서, 하나의 레벨에 더 저장되는 것 뿐만 아니라 트리의 균형을 자동으로 맞춰주는 로직까지 갖추었다. 단순하고 효율적이며, 레벨로만 따지면 완전히 균형을 맞춘 트리이다.
14 | 
15 | - Ex)
16 | 
17 |   - 대량의 데이터를 처리해야 할 때, 검색 구조의 경우 하나의 노드에 많은 데이터를 가질 수 있다는 점은 상당히 큰 장점이다. 
18 | 
19 |   - 대량의 데이터는 메모리보다 블럭 단위로 입출력하는 하드디스크 or SSD에 저장해야 하기 때문!
20 | 
21 |   - 한 블럭이 1024 바이트이면, 2바이트를 읽으나 1024바이트를 읽으나 똑같은 입출력 비용이 발생한다. 
22 | 
23 |   - 따라서 하나의 노드를 모두 1024바이트로 꽉 채워서 조절할 수 있으면 입출력에 있어서 효율적인 구성을 갖출 수 있다.
24 | 
25 |     -> B-Tree는 이러한 장점을 토대로 많은 데이터베이스 시스템의 인덱스 저장 방법으로 애용하고 있다. 
26 | 
27 | 
28 | 
29 | **규칙**
30 | 
31 | - 노드의 자료수가 N이면, 자식 수는 N+1이어야 한다.
32 | - 각 노드의 자료는 정렬된 상태여야 한다.
33 | - 루트 노드는 적어도 2개 이상의 자식을 가져야 한다.
34 | - 루트 노드를 제외한 모든 노드는 적어도 M/2개의 자료를 가지고 있어야 한다.
35 | - 외부 노드로 가는 경로의 길이는 모두 같다.
36 | - 입력 자료는 중복될 수 없다. 
37 | 
38 | 
39 | 
40 | ### [B+ Tree]
41 | 
42 | - 데이터의 빠른 접근을 위한 인덱스 역할만 하는 비단말 노드가 추가로 있다. 
43 | - 기존의 B-Tree와 데이터의 연결리스트로 구현된 색인구조.
44 | - B-Tree의 변형 구조로 index 부분과 leaf 노드로 구성된 순차 데이터 부분으로 이루어진다. 인덱스 부분의 key 값은 leaf에 있는 key 값을 직접 찾아가는데 사용한다.
45 | 
46 | 
47 | 
48 | **장점**
49 | 
50 | - 블럭 사이즈를 더 많이 이용할 수 있다. (Key 값에 대한 하드디스크 액세스 주소가 없기 때문)
51 | - Leaf 노드끼리 연결 리스트로 연결되어 있어서 범위 탐색에 매우 유리하다.
52 | 
53 | 
54 | 
55 | **단점**
56 | 
57 | - B-Tree의 경우 최상 케이스에서는 루트에서 끝날 수 있지만, B+Tree는 무조건 leaf 노드까지 내려가봐야 한다.
58 | 
59 | 
60 | 
61 | ### [비교]
62 | 
63 | - B-Tree : 각 노드에 데이터가 저장된다.
64 |   - 각 노드에서 key와 data 모두 들어갈 수 있고, data는 disk block으로 포인터가 될 수 있다.
65 | - B+ Tree : index 노드와 leaf 노드로 분리되어 저장된다.
66 |   - 각 노드에서 key만 들어간다. 따라서 data는 leaf 노드에만 존재한다.
67 |   - add, delete 연산 모두 leaf 노드에서만 이루어진다.
68 | - 또한, leaf 노드는 서로 연결되어 있어서 임의 접근이나 순차 접근 모두 성능이 우수하다.


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] Hash(해시).md:
--------------------------------------------------------------------------------
  1 | ### Hash(해시)
  2 | 
  3 | - Hash Or HashTable은 내부적으로 배열을 사용해 데이터를 저장한다.
  4 | - 해시 알고리즘을 이용해 고유한 인덱스를 얻는다. 
  5 | - 인덱스를 이용하여 빠른 검색 속도를 갖는다.
  6 | - 해시란 다양한 길이를 가진 데이터를 고정된 길이의 데이터로 매핑한 값을 말한다.
  7 | 
  8 | 
  9 | 
 10 | **[해시 함수]**
 11 | 
 12 | - 데이터를 효율적으로 관리하기 위해, 임의의 길이의 데이터를 수학적 연산을 통해 고정된 길이의 데이터로 매핑하는 함수이다. 해시 함수에 의해 얻어지는 값을 해시 코드, 해시라고 한다.
 13 | 
 14 | 
 15 | 
 16 | **[해시 테이블]**
 17 | 
 18 | - 키와 값을 매핑해둔 데이터 구조이다. 해시 함수로 얻은 해시를 키로 활용하여 index로 사용하고 해당 index에 데이터를 저장하여 효율적인 검색을 위해 사용된다.
 19 | - 동기화를 지원한다.
 20 | - key, value에 널 값을 허용하지 않는다.
 21 | 
 22 | 
 23 | 
 24 | ```
 25 | Lee -> 해시 함수 -> 5
 26 | Koo -> 해시 함수 -> 2
 27 | Kim -> 해시 함수 -> 1
 28 | ...
 29 | ...
 30 | Choi -> 해시 함수 -> 5 // Lee와 해싱값 충돌.
 31 | ```
 32 | 
 33 | 
 34 | 
 35 | 결국 데이터가 많아지면, 다른 데이터가 같은 해시 값을 가지게 되어 충돌이 발생하게 된다. 
 36 | 
 37 | 해시 테이블의 근본적인 문제는 결국 index의 충돌이다. 해시는 원래 데이터가 같으면 해시값도 항상 같다. 그러나 서로 다른 데이터 또한 동일한 해시값을 가질 수 있기 때문에 해시 충돌이 발생한다.
 38 | 
 39 | -> Collision 현상.
 40 | 
 41 | 
 42 | 
 43 | 
 44 | 
 45 | *그럼에도 해시 테이블을 쓰는 이유?*
 46 | 
 47 | > 적은 자원으로 많은 데이터를 효율적으로 관리하기 위함이다.
 48 | >
 49 | > 하드 디스크나 클라우드에 존재하는 무한한 데이터들을 유한한 개수의 해시값으로 매핑하면 작은 메모리로도 프로세스 관리가 가능해진다.
 50 | 
 51 | - 언제나 동일한 해시 값을 리턴, index를 알면 빠른 검색이 가능해진다.
 52 | - 해시 테이블의 시간 복잡도 : O(1) [이진 탐색 트리는 O(logN)]
 53 | 
 54 | 
 55 | 
 56 | ### [충돌 해결 방법]
 57 | 
 58 | 1. `Separate Chaining`
 59 | 
 60 | <img src = "https://user-images.githubusercontent.com/33534771/74128107-bdc93a00-4c1f-11ea-9cfb-32f0035eee33.png" width="60%"/>
 61 | 
 62 | - Key에 대한 index가 가리키는 자료구조를 LinkedList를 이용하는 방식이다.
 63 | - index로 인해서 충돌이 발생하면 그 index가 가리키고 있는 LinkedList에 노드를 추가한다.
 64 | - 데이터를 검색할 때, 선형 탐색을 하기 때문에 느리다는 단점이 있다. 
 65 |   - 시간 복잡도 : O(N)
 66 | - LinkedList 대신 트리를 이용하면 성능을 개선시킬 수 있다.
 67 | - JDK 1.8의 경우 index에 노드가 8개 이하인 경우에는 LinkedList를 사용하고 8개를 넘어갈 경우에는 트리 구조로 데이터 저장 구조를 바꾸도록 설계되어 있다.
 68 | 
 69 | 
 70 | 
 71 | 2. `Open Addressing`
 72 | 
 73 | - 해시 충돌이 발생하면 해시 함수로 얻은 주소가 아닌 다른 주소 공간에 데이터를 저장하는 방식이다. (해당 키 값에 데이터가 저장되어 있다면 다음 주소에 저장.)
 74 | - 선형 탐사(Linear Probing)
 75 |   - 현재 주소에서 고정 크기(ex.1)만큼 다음 주소로 이동하여 데이터를 저장한다.
 76 | - 제곱 탐사(Quadratic Probing)
 77 |   - 고정 크기만큼 이동하는 것이 아닌 이동 크기가 제곱수로 늘어나는 방식이다. (1,4,9,16...)
 78 | - 이중 해싱(Double Hashing)
 79 |   - 해시 충돌 시 다른 해시 함수를 한번 더 적용하는 방식이다.
 80 | - 재해싱(Rehashing)
 81 |   - 해시 테이블의 크기를 늘리고, 늘어난 해시 테이블의 크기에 맞추어 모든 데이터를 다시 해싱하는 방식이다.
 82 | 
 83 | 
 84 | 
 85 | Open Addressing 방식은 삭제 처리시에 문제가 발생할 수 있다. 
 86 | 
 87 | 데이터 A를 저장하고 데이터 B를 저장할 때 충돌(A와 같은 값)이 발생한다고 가정하자.
 88 | 
 89 | 이때, 데이터 A가 삭제될 경우 찾으려고 하는 index를 찾기 전에 데이터가 삭제되어서 검색을 멈추기 때문에 데이터 B를 조회할 수 없게 된다.
 90 | 
 91 | 
 92 | 
 93 | 이러한 문제점을 해결하기 위해 데이터를 삭제한 후에 더미 노드를 삽입한다. 실제로 값을 가지진 않지만 검색 시 다음 index까지 연결하는 역할을 한다. 데이터 삭제가 빈번하여 더미 노드가 증가한 경우, 조회할 데이터가 존재하지 않음에도 불구하고 더미 노드 때문에 검색을 수행하므로 더미 노드가 일정 갯수가 넘어가면 해시 테이블을 리빌딩해야 한다.
 94 | 
 95 | 
 96 | ### HashTable ve HashMap
 97 | - HashMap : Map 인터페이스를 구현하기 위해 HashTable을 사용한 클래스로 key와 value에 Null이 허용된다. 동기화를 지원하지 않는다.
 98 | - HashTable : HashMap보다 속도는 느리지만, 동기화를 지원하며 key와 value에 null이 허용되지 않는다.
 99 | 
100 | ### 읽어보면 좋은 글
101 | - [[Algorithm] 6-1. Hashing 개요 - Chaining, Open Addressing, SUHA](https://ict-nroo.tistory.com/76)
102 | - [Item 11. Equals를 재정의하려거든 Hashcode도 재정의하라](https://jaehun2841.github.io/2019/01/12/effective-java-item11/#equals-%EB%A9%94%EC%84%9C%EB%93%9C%EB%8A%94-%EC%9E%AC%EC%A0%95%EC%9D%98%ED%96%88%EC%A7%80%EB%A7%8C-hashcode%EB%A5%BC-%EC%9E%AC%EC%A0%95%EC%9D%98%ED%95%98%EC%A7%80-%EC%95%8A%EC%9D%80-%EA%B2%BD%EC%9A%B0)
103 | - [Java HashMap은 어떻게 동작하는가?](https://d2.naver.com/helloworld/831311)
104 | - [[자료구조] 코드로 알아보는 java의 Hashmap](https://sabarada.tistory.com/57)
105 | 


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] Heap.md:
--------------------------------------------------------------------------------
  1 | ## Heap
  2 | 
  3 | >1. 개요
  4 | >2. 개념
  5 | 
  6 | 
  7 | 
  8 | 힙은 자료구조의 일종으로 우선 순위 큐를 위해서 만들어졌다. 
  9 | 
 10 | - **우선 순위 큐** : 우선순위의 개념을 큐에 도입한 자료구조.
 11 |   - 데이터들이 우선순위를 가지고 있으며, 우선순위가 높은 데이터가 큐에서 먼저 빠져 나간다.
 12 | - 언제 사용?
 13 |   - 시뮬레이션 시스템, 작업 스케줄링, 수치해석 계산.
 14 |   - 우선 순위 큐는 배열, 연결 리스트, 힙으로 구현한다. (힙으로 구현하는 게 가장 효율적이다.)
 15 | - 시간 복잡도 
 16 |   - 삽입 : O(logN)
 17 |   - 삭제 : O(logN)
 18 | 
 19 | - 스택 : LIFO,  큐 : FIFO
 20 | 
 21 | 
 22 | 
 23 | 
 24 | 
 25 | ### [개념]
 26 | 
 27 | - Tree의 형식을 취하고 있으며 Tree 중에서도 **배열을 기반으로 한 (Complete Binary Tree)완전 이진 트리**이다. 
 28 | - 최대값 및 최소값을 찾아내는 연산을 빠르게 하기 위해 고안된 완전 이진 트리이다.
 29 | - 배열에 트리의 값을 넣어줄 때는 0번째는 건너뛰고 1번째부터 루트 노드가 시작된다. 이유는 노드의 고유 번호와 index를 일치시켜 혼동을 줄이기 위함이다.
 30 | - 중복된 값을 허용. (이진 탐색 트리는 중복 값을 허용하지 않음.)
 31 | - 힙의 종류로는 최대힙과 최소힙이 존재한다.
 32 |   - 최대힙 : 각 노드의 값이 자식 노드의 값보다 크거나 같은 Complete Binary Tree를 말한다.
 33 |   - 최소힙은 최대힙의 반대이다.
 34 |   - 최대힙에서는 Root Node에 있는 값이 제일 크므로, 최대값을 찾는데 소요되는 연산의 시간 복잡도는 O(1)이다.
 35 |   - Complete Binary Tree이기 때문에 **배열을 이용해 관리할 수 있으며**, **인덱스를 통한 Random Access**가 가능하다.
 36 |   - Index 번호는 노드 개수가 n개일 때, i번째 노드에 대하여 왼쪽 자식은 ix2, 오른쪽 자식은 ix2+1가 된다.
 37 | 
 38 | 
 39 | 
 40 | 
 41 | <img src = "https://user-images.githubusercontent.com/33534771/74101428-04198d00-4b7d-11ea-859d-99999fe545c2.png" width="60%"/>
 42 | 
 43 | 
 44 | 
 45 | 
 46 | ### 구현
 47 | 
 48 | 힙을 저장하는 표준적인 자료구조는 배열이다.
 49 | 
 50 | 구현을 쉽게 하기 위해 배열의 첫 번째 인덱스인 0은 사용되지 않고, 1부터 시작한다.
 51 | 
 52 | 특정 위치의 노드 번호는 새로운 노드가 추가되어도 변하지 않는다.
 53 | 
 54 | 
 55 | 
 56 | <부모 노드와 자식 노드의 관계>
 57 | 
 58 | - 왼쪽 자식 index : (부모 index) * 2
 59 | - 오른쪽 자식 index : (부모 index) * 2 + 1
 60 | - 부모 index : (자식 index) / 2
 61 | 
 62 | 
 63 | 
 64 | 1. <힙의 삽입>
 65 | 
 66 | - 힙에 새로운 요소가 들어오면, 일단 새로운 노드를 힙의 마지막 노드에 삽입.
 67 | - 새로운 노드를 검사해서 부모 노드와 교환한다.
 68 | 
 69 | 
 70 | 
 71 | [최대 힙 삽입 구현]
 72 | 
 73 | ```java
 74 | void insert_max_heap(int x){
 75 |   maxHeap[++heapSize] = x;
 76 |   // 힙 크기를 하나 증가시키고, 마지막 노드에 x를 삽입.
 77 |   
 78 |   for(int i=heapSize; i>1; i--){
 79 |     // 마지막 노드가 자신의 부모 노드보다 크면 swap
 80 |     if(maxHeap[i / 2] < maxHeap[i]){
 81 |       swap(i / 2, i);
 82 |     } else {
 83 |       break
 84 |     }
 85 |   }
 86 | }
 87 | ```
 88 | 
 89 | 부모 노드 : 자신의 인덱스 / 2 이므로 마지막 노드와 비교하여 마지막 노드가 더 크면 위치를 바꿔준다.
 90 | 
 91 | 
 92 | 
 93 | 2. <힙의 삭제>
 94 | 
 95 | - 최대 힙에서 최대값은 루트 노드이므로 루트 노드가 삭제된다. (최대 힙에서 삭제 연산은 최대값 요소를 삭제하는 것이다.)
 96 | - 삭제된 루트 노드에서는 힙의 마지막 노드를 가져온다.
 97 | - 힙을 재구성 한다.
 98 | 
 99 | 
100 | 
101 | [최대 힙 삭제 구현]
102 | 
103 | ```java
104 | int delete_map_heap(){
105 |   if(heapSize == 0) return 0; // 비어있음을 의미하므로 리턴.
106 |   
107 |   int root = maxHeap[1]; // 루트 노드의 값을 저장.
108 |   maxHeap[1] = maxHeap[heapSize]; // 마지막 노드를 루트 노드로 이동.
109 |   maxHeap[heapSize--] = 0; // 힙 크기를 하나 줄이고 마지막 노드를 0으로 초기화.
110 |   
111 |   // 힙을 구현하는 배열을 정렬하는 부분.
112 |   for(int i=1; i*2 <= heapSize;){
113 |     // 마지막 노드가 왼쪽 노드와 오른쪽 노드보다 크면 끝. 
114 |     if(maxHeap[i] > maxHeap[i * 2] && maxHeap[i] > maxHeap[i * 2 + 1]){
115 |       break;
116 |       // 왼쪽 노드가 더 큰 경우, swap
117 |     } else if(maxHeap[i * 2] > maxHeap[i * 2 + 1]){
118 |       swap(i, i * 2);
119 |       i = i * 2;
120 |       // 오른쪽 노드가 더 큰 경우, swap
121 |     } else {
122 |       swap(i, i * 2 + 1);
123 |       i = i * 2 + 1;
124 |     }
125 |   }
126 |   
127 |   return root;
128 | }
129 | ```
130 | 
131 | 
132 | 
133 | ### Heapify
134 | 
135 | - 두 개의 서브 트리가 최대힙(최소힙)일 때, root를 포함하는 전체가 heap이 되도록 위치를 조정하는 과정을 말한다.
136 | - 루트에서 작은 값이 흘러 내려가면서 처리되는 방식으로 진행된다. 최대힙의 경우 root가 child보다 작으면 두 개의 child node 중 값이 큰 노드를 root와 교체하고 교체할 노드가 없을 때까지 반복한다. 
137 | 


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] Stack과 Queue.md:
--------------------------------------------------------------------------------
  1 | ## Stack과 Queue
  2 | 
  3 | 스택과 큐는 선형 자료구조이다.
  4 | 
  5 | 
  6 | 
  7 | - Stack
  8 |   - 나중에 들어간 원소가 먼저 나오는 구조이다.
  9 |   - LIFO(Last in First Out)의 구조.
 10 |   - 안드로이드의 액티비티를 관리하는 데 스택이 사용된다.
 11 |   - 시간 복잡도 : O(n)
 12 |   - 공간 복잡도 : O(n)
 13 |   - 언제 사용? 함수의 콜 스택, 문자열 역순 출력, 연산자 후위 표기법 등
 14 | - Queue
 15 |   - 먼저 들어간 원소가 먼저 나오는 구조이다.
 16 |   - FIFO(First in First out)의 구조.
 17 |   - 큐는 활용 분야가 되게 많다. 안드로이드의 경우, 루퍼의 메시지 큐가 예시 중 하나이다.
 18 |   - 시간 복잡도 : O(n)
 19 |   - 공간 복잡도 : O(n)
 20 |   - 언제 사용? 버퍼, 마구 입력된 것을 처리하지 못하고 있는 상황, bfs 탐색 등
 21 | 
 22 | 
 23 | 
 24 | ### 2개의 스택으로 큐 구현
 25 | 
 26 | 가끔 이런 문제가 면접에서 나온다고 한다. 어렵다고 생각했는데, 그리 어렵지 않고 간단하게 구현할 수 있다.
 27 | 
 28 | ![img](https://t1.daumcdn.net/cfile/tistory/222BDF4E5462B1E00D)
 29 | 
 30 | 1. inbox에 데이터를 삽입한다(push) -> A,B
 31 | 2. inbox에 있는 데이터를 추출(pop)하여 outbox에 삽입(push) 한다. -> B,A
 32 | 3. outbox에 있는 데이터를 추출(pop)한다. -> A,B 순으로 출력된다.
 33 | 
 34 | 
 35 | 
 36 | 즉, inbox 스택에 A,B 순으로 데이터를 삽입하면 위의 그림처럼 스택에 데이터가 쌓인다. 그리고 inbox 스택에 있는 데이터를 pop해서 outbox로 옮긴다. 그렇게 되면 outbox에는 B,A 순서로 데이터가 쌓인다.
 37 | 
 38 | 그리고 다시 outbox 스택에 있는 데이터를 pop하게 되면 A,B 순으로 데이터가 출력된다.
 39 | 
 40 | 
 41 | 
 42 | [Code]
 43 | 
 44 | ```java
 45 | package Stack;
 46 | 
 47 | import java.util.Stack;
 48 | 
 49 | /**
 50 |  * created by victory_woo on 2020/05/06
 51 |  * Stack 2개를 이용해서 Queue 구현하기.
 52 |  */
 53 | public class StackWithQueue {
 54 |     public static void main(String[] args) {
 55 |         StackQueue<String> queue = new StackQueue<>();
 56 |         queue.enQueue("A");
 57 |         queue.enQueue("B");
 58 |         queue.enQueue("C");
 59 | 
 60 |         System.out.println(queue.deQueue());
 61 |         System.out.println(queue.deQueue());
 62 |         System.out.println(queue.deQueue());
 63 |     }
 64 | 
 65 |     static class StackQueue<T> {
 66 |         private Stack<T> inBox;
 67 |         private Stack<T> outBox;
 68 | 
 69 |         StackQueue() {
 70 |             inBox = new Stack<>();
 71 |             outBox = new Stack<>();
 72 |         }
 73 | 
 74 |         void enQueue(T item) {
 75 |             inBox.push(item);
 76 |         }
 77 | 
 78 |         Object deQueue() {
 79 |             if (outBox.isEmpty()) {
 80 |                 while (!inBox.isEmpty()) {
 81 |                     outBox.push(inBox.pop());
 82 |                 }
 83 |             }
 84 | 
 85 |             return outBox.pop();
 86 |         }
 87 |     }
 88 | }
 89 | 
 90 | ```
 91 | 
 92 | 
 93 | 
 94 | 위의 내용은 [Creator Developer](https://creatordev.tistory.com/83) 님의 블로그를 참고했다.
 95 | 
 96 | 
 97 | 
 98 | 
 99 | 
100 | ### Stack 구현
101 | 
102 | TODO
103 | 
104 | 
105 | 
106 | ### Queue 구현
107 | 
108 | TODO
109 | 
110 | 


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] Tree.md:
--------------------------------------------------------------------------------
 1 | ## Tree
 2 | 
 3 | 1. 트리의 개념.
 4 | 2. 트리의 구성 요소.
 5 | 3. 트리의 종류.
 6 | 
 7 | 
 8 | 
 9 | ### 트리의 개념
10 | 
11 | 트리라는 이름이 나온 이유는 실제 나무를 거꾸로 세워놓은 듯한 모양이라서 트리라고 부른다.
12 | 
13 | ![img](https://k.kakaocdn.net/dn/bt7oXo/btqud7Jtl34/BZIJCBLvY19OsQPWTKMar0/img.png)
14 | 
15 | 선형 자료구조에서 배열이나 리스트 등도 존재하지만, 트리가 나온 이유는 뭘까?
16 | 
17 | 일반 배열에서 삽입이나 삭제를 하는데 O(N)의 시간이 걸린다. 배열의 첫번째 원소에 삽입하는 경우 나머지 모든 요소들을 한 칸씩 뒤로 미뤄야 하므로 최악의 시간 복잡도 O(N)이 나온다. 하지만, 트리는 편향 트리가 아닌 이상 일반적인 트리에서는 O(log N) 정도의 시간으로 줄여진다.
18 | 
19 | 
20 | 
21 | 또한 트리는 계층 구조를 이루는 경우에 굉장히 좋다.
22 | 
23 | ![img](https://k.kakaocdn.net/dn/bYGp1n/btqucn0M1cx/QO7cyWwxy9qJICKO1jmSf0/img.png)
24 | 
25 | 회사의 조직도를 생각해보면, 맨 위에 회장님, 사장님이 있고, 부서별, 팀별로 각각 트리가 생길 것이다. 이런 경우, 원하는 부서를 타고 내려가기만 하면 되므로 다른 자료 구조보다 찾기가 훨씬 쉬울 것이다.
26 | 
27 | 
28 | 
29 | **특징**
30 | 
31 | - Tree는 Stack이나 Queue와 같이 선형 구조가 아닌 비선형 자료구조이다. 
32 | - 계층적 관계를 표현한다.
33 | - 루트 노드를 제외한 모든 노드는 단 하나의 부모 노드만을 갖는다.
34 | 
35 | 
36 | 
37 | ### [트리의 구성 요소]
38 | 
39 | ![img](https://k.kakaocdn.net/dn/cAInQg/btqudSFLXUP/ovj1R8NfO1cF85W1zbuAmk/img.png)
40 | 
41 | - Node : 트리를 구성하는 각각의 요소.
42 | - Edge : 트리를 구성하기 위해 노드와 노드를 연결하는 선.
43 | - Root Node : 트리 구조에서 최상위에 있는 노드.
44 | - Terminal Node : 하위에 다른 노드가 연결되어 있지 않은 노드.
45 | - Internal Node : 단말 노드를 제외한 모든 노드로 루트 노드를 포함한다. 
46 | 
47 | 
48 | 
49 | ### [Binary Tree(이진 트리)]
50 | 
51 | ![img](https://k.kakaocdn.net/dn/ZKPe7/btquds1DgyR/Q2T6uYRNDVEHSEqN7Ql5QK/img.png)
52 | 
53 | - 루트 노드를 중심으로 두 개의 서브 트리로 나뉘어 진다. (노드가 없을 수도 있다.) 나뉘어진 두 서브 트리도 모두 이진 트리어야 한다.
54 | - 각 층별로 숫자를 매겨서 이를 트리의 레벨이라고 한다. 레벨은 1부터 시작하고 루트 노드의 레벨은 1이다. 트리의 최고 레벨을 가리켜 트리의 높이라고 한다.
55 | - 종류
56 |   - **Full Binary Tree(포화 이진 트리)** : 모든 레벨이 꽉 찬 이진 트리를 의미한다.
57 |     - 레벨 별로 노드의 개수가 1,2,4,8,16 ... 으로 늘어난다. 따라서 일반적인 이진트리에서 각 레벨 별 최대 노드의 개수는 2^(k - 1)이 된다.
58 |     - 레벨 별 노드는 공비가 2인 등비 수열이라고 볼 수 있으므로 등비수열의 합으로 생각하면 높이가 h인 이진트리가 가질 수 있는 최대 노드 수는 2^h - 1이라고 할 수 있다. 
59 |   - **Complete Binary Tree(완전 이진 트리)** : 왼쪽에서 오른쪽으로 순서대로 차곡 차곡 채워진 이진 트리를 의미한다.
60 |     - 노드를 삽입할 때 왼쪽부터 차례대로 삽입하는 트리이다. 왼쪽이 비어있고 오른쪽이 들어가있는 트리는 완전 이진 트리가 아니다.
61 |   - **Skewed Binary Tree(편향 이진 트리)** : 모든 노드가 부모의 왼쪽 자식이기 때문에 왼쪽으로 편향되어 있거나 반대로 모든 노드가 부모의 오른쪽 자식이기 때문에 오른쪽으로 편향되어 있는 이진 트리를 말한다.
62 | 
63 | 
64 | 
65 | ### 참고
66 | 
67 | - [[Java][자료구조] Tree (1) - 트리의 정의와 특성, 이진트리에 대하여](https://ju-nam2.tistory.com/25?category=868623)
68 | 


--------------------------------------------------------------------------------
/Data Structure/[Data Structure] 이진 탐색 트리.md:
--------------------------------------------------------------------------------
 1 | ## 이진 탐색 트리 BST(Binary Search Tree)
 2 | 
 3 | **이진 탐색 트리의 목적은?**
 4 | 
 5 | -> 이진 탐색 + 연결 리스트
 6 | 
 7 | - 이진 탐색
 8 |   - **탐색에 소요되는 시간 복잡도는 O(logN)**
 9 |   - 하지만 삽입, 삭제가 불가능.
10 | - 연결 리스트
11 |   - **삽입, 삭제의 시간 복잡도는 O(1)**
12 |   -  하지만 탐색하는 시간 복잡도는 O(N)
13 | - 이 두 가지를 합하여 장점을 모두 얻기 위해 고안된 것이 `이진 탐색 트리`
14 | - 즉, 효율적인 탐색 능력을 가지고 자료의 삽입, 삭제도 가능하게 만드는 것이다.
15 | 
16 | ![img](https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fk.kakaocdn.net%2Fdn%2Fk074C%2FbtqwZZvI1D3%2FeVUanrpKdIRKnZpkKiQMe0%2Fimg.png)
17 | 
18 | ### [특징]
19 | 
20 | - 이진 트리의 일종으로 이진 탐색 트리에는 데이터를 저장하는 규칙이 있다.
21 | 
22 | - 이진 탐색 트리의 노드에 저장된 키는 유일하다.
23 |   1. 루트 노드의 키가 왼쪽 서브 트리를 구성하는 어떠한 노드의 키보다 크다.
24 |   2. 루트 노드의 키가 오른쪽 서브 트리를 구성하는 어떠한 노드의 키보다 작다.
25 |   3. 왼쪽과 오른쪽 서브 트리도 이진 탐색 트리이다.
26 | - 탐색의 시간 복잡도는 O(logN)이다. 최악의 경우, 편향 트리가 되어 O(N)이 될 수도 있다.
27 | - 이진 탐색 트리의 순회는 **중위 순회**(in order) 방식이다.(왼쪽 - 루트 - 오른쪽)
28 | - 중위 순회로 **정렬된 순서**를 읽을 수 있다.
29 | - 중복된 노드가 없어야 한다.
30 | 
31 | **중복이 없어야 하는 이유는??**
32 | 
33 | 검색을 목적으로 하는 자료구조인데, 굳이 중복이 많은 경우에 이 트리를 사용해 검색 속도를 느리게 할 필요가 없다. 트리에 삽입하는 것보다 노드에 count를 가지게 하여 처리하는 것이 훨씬 효율적이다.
34 | 
35 | 
36 | 
37 | **[BST 핵심 연산]**
38 | 
39 | - 검색
40 | - 삽입
41 | - 삭제
42 | - 트리 생성
43 | - 트리 삭제
44 | 
45 | 
46 | 
47 | **[시간 복잡도]**
48 | 
49 | - 균등 트리 : 노드 개수가 N개일 때, O(logN)
50 | - 편향 트리 : 노드 개수가 N개일 때, O(N)
51 | 
52 | > 삽입, 검색, 삭제 시간 복잡도는 트리의 Depth에 비례.
53 | 
54 | 
55 | 
56 | 삭제의 3가지 case
57 | 
58 | 1. 자식이 없는 단말 노드일 때 -> 그냥 삭제
59 | 2. 자식이 1개인 노드일 때 -> 지워진 노드에 자식을 올리기
60 | 3. 자식이 2개인 노드일 때 -> 오른쪽 자식 노드에서 가장 작은 값 or 왼쪽 자식 노드에서 가장 큰 값 올리기 
61 | 
62 | 
63 | 
64 | 편향된 트리(정렬된 상태 값을 트리로 만들면 한쪽으로 뻗음)는 시간 복잡도가 O(N) 이므로 트리를 사용할 이유가 사라진다. 이를 바로 잡도록 도와주고 개선된 트리는 AVL Tree, RedBlack Tree가 있다.
65 | 
66 | 
67 | 
68 | **[이진 트리의 순회 방법]**
69 | 
70 | 1. 전위 순회(Pre Order) : 루트 -> 왼쪽 -> 오른쪽
71 | 2. 중위 순회(In Order) : 왼쪽 -> 루트 -> 오른쪽
72 | 3. 후위 순회(Post Order) : 왼쪽 -> 오른쪽 -> 루트


--------------------------------------------------------------------------------
/Data Structure/[Data Sturcture] ArrayList vs LinkedList.md:
--------------------------------------------------------------------------------
 1 | ## Dynamic Array vs LinkedList
 2 | 
 3 | ++2020.06.01
 4 | 
 5 | 자료구조에 해당하는 파트이지만, 자바를 기반으로 설명을 진행했다. 
 6 | 
 7 | 그러다보니 Collection에서 사용하는 네이밍을 따라 ArrayList라고 표기를 했다. 
 8 | 
 9 | 필자의 글을 보고 있던 분의 조언으로 Dynamic Array로 네이밍을 변경한다.
10 | 
11 | - Java : ArrayList
12 | - C++ : Vector
13 | 
14 | 기본적이면서도 면접 질문에 빠지지 않고 등장하는 단골 질문이다. 
15 | 
16 | 그래서 정리하려 한다.
17 | 
18 | 
19 | - Dynamic Array(ArrayList)
20 |   - 이름처럼 내부적으로 배열을 사용하여 데이터를 관리한다.
21 |   - 인덱스를 가지고 있어 데이터 검색에 적합하고 속도가 빠르다.
22 |     - 시간 복잡도 : O(1)
23 |   - 데이터의 삽입, 삭제 시 해당 데이터를 제외한 모든 데이터를 임시 배열을 생성해 복사하므로 삽입, 삭제가 빈번할 경우 속도가 느리며 부적합하다.
24 |     - 시간 복잡도 : O(n)
25 |   - 동기화를 지원하지 않아 Vector보다 빠르다. 
26 | 
27 | 
28 | 
29 | - LinkedList
30 |   - 데이터를 저장하는 각 노드가 이전 노드와 다음 노드의 상태만 알고 있으면 된다.
31 |   - 데이터 검색 시에는 처음부터 노드를 순회하기 때문에 오래 걸리며 성능상 좋지 않다. 
32 |     - 시간 복잡도 : O(n)
33 |   - 데이터의 삽입, 삭제시 불필요한 데이터의 복사가 없어 데이터의 삽입, 삭제 시 유리하다.
34 |     - 시간 복잡도 : O(1)
35 |     - 하지만, 경우에 따라서 다르기도 하다.
36 |     - 왜냐하면 삽입, 삭제를 하기 위한 노드를 찾기 위해서는 결국 O(n)이 걸리고 삽입, 삭제를 위한 시간 복잡도까지 계산하면 결국 O(n)이 걸린다.
37 |     - 만약, 중간 요소의 삽입, 삭제가 없고 맨 앞과 뒤 요소의 삽입, 삭제만 한다면 O(1)이 걸린다. 그렇지 않으면 O(n).
38 | 
39 | 
40 | 
41 | 따라서 데이터의 검색이 주가 되는 경우에는 Dynamic Array(ArrayList)를 사용하는 게 좋다. 
42 | 
43 | 데이터의 삽입, 삭제가 빈번하다면 Dynamic Array(ArrayList)보다는 LinkedList를 사용하는 편이 낫다.
44 | 
45 | ++추가
46 | 
47 | 실제로 백준에 있는 삼성 기출 문제 중 **나무 재테크** 문제를 풀 때, ArrayList를 사용하면 시간 초과로 문제를 해결할 수 없다. 이 문제에서는 나무를 관리하는 리스트가 존재하는데, 죽은 나무의 경우 나무 리스트에서 나무를 제거해야 한다. 따라서 빈번한 삭제 및 삽입이 발생하기 때문에 LinkedList를 사용하는 게 더 효율적이다. 
48 | [나무 재테크](https://www.acmicpc.net/problem/16235) 문제를 꼭 풀어보는 것을 추천한다.
49 | 
50 | 
51 | 
52 | 


--------------------------------------------------------------------------------
/Data Structure/우선순위 큐.md:
--------------------------------------------------------------------------------
  1 | ### 우선순위 큐(Priority Queue)
  2 | 
  3 | 일반적인 큐는 먼저 들어간 데이터가 먼저 나오는 구조이다. **이런 큐의 특성과 달리 우선순위 큐(Priority Queue)는 들어간 순서에 상관없이 일정한 규칙에 따라 우선순위를 선정하고 우선순위가 가장 높은 데이터가 가장 먼저 나오게 된다.** 대표적인 예로는 병원의 응급 환자를 생각할 수 있으며, 은행의 업무를 기다리는 상황과 달리 위급한 우선순위에 따라 먼저 처리된다.
  4 | 
  5 | 
  6 | 
  7 | #### 사용하기
  8 | 
  9 | - 우선순위 큐도 Java에서 내부적으로 구현되어 있어 사용이 용이하다.
 10 | - 큐와 동일하게 add(), peek(), poll() 등의 메소드를 사용할 수 있다.
 11 | 
 12 | [Code]
 13 | 
 14 | ```java
 15 |  public class Sample {
 16 |     public static void main(String[] args) {
 17 |         PriorityQueue<Integer> pq = new PriorityQueue<>();
 18 |         pq.add(4);
 19 |         pq.add(19);
 20 |         pq.add(2);
 21 |         pq.add(1);
 22 |         System.out.println(pq.poll()); // 1이 출력된다.
 23 |     }
 24 | }
 25 | ```
 26 | 
 27 | - add() 대신 offer() 메소드를 사용해도 동일한 결과를 얻는다.
 28 | 
 29 | 
 30 | 
 31 | #### 우선순위 변경하기
 32 | 
 33 | - 우선순위를 정하는 기준은 Java의 정렬 기준과 동일하다.
 34 | - Java는 기본적으로 낮은 숫자부터 큰 숫자까지 오름차순으로 정렬하게 되는데, 만약 다른 오름차순으로 정렬하고 싶다면 Comparator 클래스나 Comparable 인터페이스를 이용해야 한다.
 35 | - Ex) 객체의 어떤 값에 따라 우선순위를 정해 정렬해야 할때, 오름차순이 아닌 내림차순 정렬을 할때 등등
 36 | - Integer는 Collections.reverseOrder()를 사용해 내림차순 정렬을 할 수 있다.
 37 | 
 38 | [Code]
 39 | 
 40 | ```java
 41 | public class Sample {
 42 |     public static void main(String[] args) {
 43 |         PriorityQueue<Integer> pq = new PriorityQueue<>(Collections.reverseOrder());
 44 |         pq.add(4);
 45 |         pq.add(19);
 46 |         pq.add(2);
 47 |         pq.add(1);
 48 | 
 49 |         System.out.println(pq.poll()); // 19가 출력된다.
 50 |     }
 51 | }
 52 | ```
 53 | 
 54 | 
 55 | 
 56 | #### 우선순위 큐 예제
 57 | 
 58 | - 고양시에서 강남까지 가는 방법이 있다고 하자.
 59 | 
 60 | - 대중교통, 자가용, 도보, 자전거 총 4가지의 방법이 존재한다.
 61 |   - 대중 교통 : 1시간 10분
 62 |   - 자가용 : 45분
 63 |   - 도보 : 6시간 40분
 64 |   - 자전거 : 2시간 5분
 65 | - 시간이 제일 적게 걸리는 순서로 정렬하면 -> 자가용, 대중교통, 자전거, 도보 순이다.
 66 | - 우선순위 큐에 저장한 뒤, 데이터를 추출하면 위의 순서대로 추출된다.
 67 | - 하지만, 큐는 들어간 순으로 나온다.
 68 | 
 69 | [Code]
 70 | 
 71 | ```java
 72 | package programmers;
 73 | 
 74 | import java.util.PriorityQueue;
 75 | 
 76 | /**
 77 |  * created by victory_woo on 2020/05/12
 78 |  */
 79 | public class Sample {
 80 |     public static void main(String[] args) {
 81 |         PriorityQueue<Vehicle> pq = new PriorityQueue<>();
 82 |         pq.add(new Vehicle("대중교통", 70));
 83 |         pq.add(new Vehicle("자가용", 45));
 84 |         pq.add(new Vehicle("오토바이", 45));
 85 |         pq.add(new Vehicle("도보", 400));
 86 |         pq.add(new Vehicle("자전거", 125));
 87 | 
 88 |         while (!pq.isEmpty()) {
 89 |             System.out.println(pq.poll());
 90 |         }
 91 |     }
 92 | 
 93 |     static class Vehicle implements Comparable<Vehicle> {
 94 |         private String name;
 95 |         private int time;
 96 | 
 97 |         Vehicle(String name, int time) {
 98 |             this.name = name;
 99 |             this.time = time;
100 |         }
101 | 
102 |         public String getName() {
103 |             return name;
104 |         }
105 | 
106 |         public int getTime() {
107 |             return time;
108 |         }
109 | 
110 |         @Override
111 |         public String toString() {
112 |             return "Vehicle{" +
113 |                     "name='" + name + '\'' +
114 |                     ", time=" + time +
115 |                     '}';
116 |         }
117 | 
118 |         @Override
119 |         public int compareTo(Vehicle that) {
120 |             if (this.time == that.time) return this.name.compareTo(that.name);
121 |             return this.time - that.time;
122 |         }
123 |     }
124 | }
125 | // 결과
126 | Vehicle{name='오토바이', time=45}
127 | Vehicle{name='자가용', time=45}
128 | Vehicle{name='대중교통', time=70}
129 | Vehicle{name='자전거', time=125}
130 | Vehicle{name='도보', time=400}
131 | ```
132 | 
133 | - Vehicle 클래스를 만들었다. 그리고 자바에서 PriorityQueue를 사용하기 위해서는(객체인 경우) 우선순위 큐에 저장할 객체는 필수적으로 Comparable 인터페이스를 구현해야 한다.
134 | - compareTo 메소드를 오버라이드 하여 우선순위 조건을 설정하면 PriorityQueue가 우선순위가 높은 객체를 추출하게 된다.
135 | - 시간이 작은 순서로 정렬해야 하기 때문에 오름차순 정렬을 한다.
136 | - 다만, 시간이 같은 경우에는 이름의 사전순 정렬을 한다.(오름차순) name이 String이기 때문에 `this.name.compareTo(that.name)` 을 활용한다.
137 | - Int 형인 time 간의 연산에서 Integer.compareTo() 를 사용하지 않은 이유는 Integer와 int의 size가 메모리 차이 때문이다. int의 size가 훨씬 작아 연산시 적은 메모리를 사용한다는 점에서 서로의 값을 뺄셈하여 계산했다. 
138 | - 관련 내용은 해당 Repository에 있으니 확인하면 좋을 것 같다.
139 | 
140 | ### 참고
141 | 
142 | - [우선순위 큐 - Java에서 다루기](https://siyoon210.tistory.com/117)
143 | - [자바로 정리한 우선순위큐(PriorityQueue)](https://pangsblog.tistory.com/23)
144 | 
145 | 


--------------------------------------------------------------------------------
/Database/Key(키).md:
--------------------------------------------------------------------------------
 1 | ## Key
 2 | 
 3 | - Key란? 검색이나 정렬 시 Tuple을 구분할 수 있는 기준이 되는 Attribute.
 4 | 
 5 | <img src="https://user-images.githubusercontent.com/33534771/75773133-a4d02680-5d90-11ea-8ad0-ac4b85e438d2.png" width="60%"/>
 6 | 
 7 | 
 8 | ### 1. Candidate Key(후보키)
 9 | 
10 | - 릴레이션을 구성하는 속성들 중에서 **Tuple을 유일하게 식별할 수 있는 속성들의 부분 집합**을 의미한다.(기본키로 사용할 수 있는 속성들을 후보키라 한다.)
11 | - **모든 릴레이션은 반드시 하나 이상의 후보 키를 가져야 한다.**
12 | - 릴레이션에 있는 모든 튜플에 대해서 **유일성과 최소성을 만족**시켜야 한다.
13 | 
14 | **아래 2가지 조건을 만족해야 한다.**
15 | 
16 | - 유일성 : Key로 하나의 Tuple을 유일하게 식별할 수 있음.
17 | - 최소성 : 꼭 필요한 속성으로만 구성.
18 | 
19 | Ex)
20 | 
21 | [학생] 릴레이션에서 학번이나 주민번호는 다른 레코드를 유일하게 구별할 수 있는 기본키로 사용할 수 있으므로 후보키가 될 수 있다. 즉, 기본키가 될 수 있는 키들을 후보키라 한다.
22 | 
23 | ### 2. Primary Key(기본키)
24 | 
25 | - 후보 키 중 선택한 Main key
26 | - 한 릴레이션에서 **특정 튜플을 유일하게 구별할 수 있는 속성**
27 | - **Null 값을 가질 수 없다.(개체 무결성의 첫 번째 조건)**
28 | - **기본 키로 정의된 속성에는 동일한 값이 중복되어 저장될 수 없다.(개체 무결성의 두 번째 조건)**
29 | 
30 | 아래 조건을 만족해야 한다.
31 | 
32 | - `유일성` : 기본키를 구성하는 컬럼은 테이블에서 레코드를 식별할 수 있도록 유일해야 한다.
33 | - `최소성` : 유일성을 만족하는 한도 내에서 최소한의 컬럼(하나 이상)으로 구성되어야 한다.
34 | - `개체 무결성` : 기본키가 가지고 있는 값의 유일성을 보장받아야 한다. 
35 | 
36 | Ex)
37 | 
38 | [학생] 릴레이션에는 **학번**이나 **주민 번호**가 기본키가 될 수 있고, [수강] 릴레이션에는 **학번+과목명**으로 조합해야 기본키가 만들어질 수 있다. 왜냐하면 [수강] 릴레이션에서는 **학번** 속성과 **과목명** 속성은 개별적으로 기본키로 사용할 수 없다. 다른 튜플들과 구별되지 않기 때문이다.
39 | 
40 | ### 3. Alternate Key(대체키)
41 | 
42 | - 후보키가 둘 이상일 때, 기본 키를 제외한 나머지 후보키들을 말한다.
43 | - 보조키라고도 한다.
44 | 
45 | Ex)
46 | 
47 | [학생] 릴레이션에서 **학번**을 기본키로 정하면 **주민번호** 는 대체키가 된다.
48 | 
49 | ### 4. Super Key(슈퍼키)
50 | 
51 | - **한 릴레이션 내에 있는 속성들의 집합으로 구성된 키**로서 릴레이션을 구성하는 모든 튜플 중 슈퍼키로 구성된 속성의 집합과 동일한 값을 나타내지 않는다.
52 | - 릴레이션을 구성하는 모든 튜플에 대해서 **유일성은 만족하지만, 최소성은 만족시키지 못한다.**
53 | 
54 | Ex)
55 | 
56 | [학생] 릴레이션에서는 **학번, 주민번호, 학번+주민번호, 학번+주민번호+성명** 등으로 슈퍼키를 구성할 수 있다. 또한, 여기서 최소성을 만족시키지 못한다는 말은 **학번+주민번호+성명**이 슈퍼키인 경우, 3개의 속성 조합을 통해 다른 튜플과 구별이 가능하지만, **성명** 단독적으로 슈퍼키를 사용했을 때는 구별이 가능하지 않기 때문에 최소성을 만족시키지 못한다.
57 | 
58 | 즉, 뭉쳤을 경우 유일성이 생기고 흩어지면 몇몇 속성들은 독단적으로 유일성이 있는 키로 사용할 수 없다. 이것을 최소성을 만족하지 못한다고 한다.
59 | 
60 | ### 5. Foreignn Key(외래키)
61 | 
62 | - 관계(Relation)를 맺고 있는 릴레이션 R1,R2에서 릴레이션 R1이 참조하고 있는 릴레이션 R2의 기본키와 같은 R1 릴레이션의 속성을 외래키라고 한다.
63 | - 외래키는 **참조되는 릴레이션의 기본키와 대응되어 릴레이션 간에 참조 관계를 표현하는 데 중요한 도구로 사용된다**.
64 | - **외래키로 지정되면 참조 테이블의 기본키에 없는 값은 입력할 수 없다**.(참조 무결성의 조건)
65 | 
66 | 
67 | 
68 | Ex) 
69 | 
70 | [수강] 릴레이션이 [학생] 릴레이션을 참조하고 있으므로, [학생] 릴레이션의 **학번**은 기본키이고, [수강] 릴레이션의 **학번**은 외래키이다.
71 | 
72 | 즉, 각 릴레이션의 입장에서 속성은 기본키가 되기도 하고, 외래키가 되기도 한다.
73 | 
74 | -> [수강] 릴레이션의 **학번**에는 [학생] 릴레이션의 **학번**에 없는 값은 입력할 수 없다.
75 | 
76 | 
77 | 
78 | ### 기타
79 | 
80 | **Null 값?**
81 | 
82 | 데이터베이스에서 아직 알려지지 않았거나, 모르는 값으로서 "해당 없음" 등의 이유로 정보 부재를 나타내기 위해 사용하는, 이론적으로 아무것도 없는 특수한 데이터를 뜻한다.
83 | 
84 | 
85 | 
86 | ### 참고
87 | 
88 | [[DataBase] 키(Key)의 개념 및 종류](https://limkydev.tistory.com/108)
89 | 
90 | 


--------------------------------------------------------------------------------
/Database/SQL - Injection.md:
--------------------------------------------------------------------------------
 1 | ## SQL Injection
 2 | 
 3 | - 해커에 의해 조작된 SQL 쿼리문이 데이터베이스에 그대로 전달되어 비정상적 명령을 실행시키는 공격 기법을 말한다.
 4 | 
 5 | 
 6 | 
 7 | ### 공격 방법
 8 | 
 9 | **1) 인증 우회**
10 | 
11 | 보통 로그인을 할 때, 아이디와 비밀번호를 input 창에 입력한다. 
12 | 
13 | 예를 들어, 아이디가 abc 비밀번호가 1234일 때, 쿼리는 아래와 같은 방식으로 전송될 것이다.
14 | 
15 | ```sql
16 | SELECT * FROM USER WHERE ID = "abc" AND PASSWORD = "1234";
17 | ```
18 | 
19 | 
20 | 
21 | SQL Injection으로 공격할 때, input 창에 비밀번호를 입력함과 동시에 다른 쿼리문을 함께 입력하는 것이다.
22 | 
23 | ```sql
24 | 1234; DELETE * FROM USER WHERE ID = "1";
25 | ```
26 | 
27 | 
28 | 
29 | 보안이 완벽하지 않은 경우, 이처럼 비밀번호가 아이디와 일치해서 True가 되고 뒤에 작성한 DELETE문도 데이터베이스에 영향을 줄 수도 있게 되는 치명적인 상황이다.
30 | 
31 | 이 밖에도 기본 쿼리문의 WHERE절에 OR문을 추가하여 ` '1' = '1'` 과 같은 true문을 작성하여 무조건 적용되도록 수정한 뒤 DB를 마음대로 조작할 수도 있다.
32 | 
33 | 
34 | 
35 | **2) 데이터 노출**
36 | 
37 | 시스템에서 발생하는 에러 메시지를 이용해 공격하는 방법이다. 
38 | 
39 | 보통 에러는 개발자가 버그를 수정하는 면에서 도움을 받을 수 있는 존재이다. 해커들은 이를 역이용해 악의적인 구문을 삽입하여 에러를 유발시킨다.
40 | 
41 | 예를 들면, 해커는 **GET 방식으로 동작하는 URL 쿼리 스트링을 추가하여 에러를 발생**시킨다.
42 | 
43 | 이에 해당하는 오류가 발생하면 이를 통해 해당 웹앱의 데이터베이스 구조를 유추할 수 있고 해킹에 활용한다.
44 | 
45 | 
46 | 
47 | ### 방어 방법
48 | 
49 | **1) input 값을 받을 때, 특수 문자 여부 검사하기**
50 | 
51 | 로그인 전, 검증 로직을 추가하여 미리 설정한 특수문자들이 들어왔을 때 요청을 막아낸다.
52 | 
53 | 
54 | 
55 | **2) SQL 서버 오류 발생 시, 해당하는 에러 메시지 감추기**
56 | 
57 | view를 활용해 원본 데이터베이스 테이블에는 접근 권한을 높인다. 일반 사용자는 view로만 접근하여 에러를 볼 수 없도록 만든다.
58 | 
59 | 
60 | 
61 | **3) prepare statement 사용하기**
62 | 
63 | prepare statement를 사용하면 특수문자를 자동으로 escaping 해준다.
64 | 
65 | (statement와는 다르게 쿼리문에서 전달인자 값을 ?로 받는것)이를 활용해 서버 측에서 필터링 과정을 통해서 공격을 방어한다.


--------------------------------------------------------------------------------
/Database/SQL - Join.md:
--------------------------------------------------------------------------------
  1 | ## SQL Join
  2 | 
  3 | **조인이란**
  4 | 
  5 | - 두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색하는 방법을 말한다.
  6 | - 테이블을 연결하려면, 적어도 하나의 칼럼을 서로 공유하고 있어야 하므로 이를 이용하여 데이터 검색에 활용한다.
  7 | 
  8 | 
  9 | 
 10 | ### Join 종류
 11 | 
 12 | - INNER JOIN
 13 | - LEFT OUTER JOIN
 14 | - RIGHT OUTER JOIN
 15 | - FULL OUTER JOIN
 16 | - CROSS JOIN
 17 | - SELF JOIN
 18 | 
 19 | ```sql
 20 | 문법
 21 | SELECT
 22 | 테이블별칭.조회할컬럼,
 23 | 테이블별칭.조회할컬럼
 24 | FROM 기준테이블 별칭
 25 | INNER JOIN 조인테이블 별칭 ON 기준테이블별칭.기준키 = 조인테이블별칭.기준키 ...
 26 | ```
 27 | 
 28 | 
 29 | 
 30 | **1) INNER JOIN**
 31 | 
 32 | <img src="https://user-images.githubusercontent.com/33534771/75853566-c1706b00-5e31-11ea-83bc-1e2ebe4d9f61.png" />
 33 | 
 34 | - 쉽게 말해 **교집합**이라고 생각하면 된다.
 35 | - 기준 테이블과 Join한 테이블의 **중복된 값**을 보여준다.
 36 | - 결과값은 A의 테이블과 B 테이블이 모두 가지고 있는 데이터만 검색된다.
 37 | 
 38 | ```sql
 39 | Ex)
 40 | SELECT
 41 | A.NAME, 
 42 | B.AGE
 43 | FROM EX_TABLE A
 44 | INNER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
 45 | ```
 46 | 
 47 | 
 48 | 
 49 | **2) LEFT OUTER JOIN**
 50 | 
 51 | <img src="https://user-images.githubusercontent.com/33534771/75853627-e238c080-5e31-11ea-89bb-a5afe1058cfd.png" />
 52 | 
 53 | - **기준 테이블의 값 + 테이블과 기준테이블의 중복된 값**을 보여준다.
 54 | - 왼쪽 테이블을 기준으로 Join을 하겠다고 생각하면 된다.
 55 | - 결과값은 A 테이블의 모든 값과 A 테이블과 B 테이블의 중복되는 값이 검색된다.
 56 | 
 57 | ```sql
 58 | SELECT
 59 | A.NAME,
 60 | B.AGE
 61 | FROM EX_TABLE A
 62 | LEFT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
 63 | ```
 64 | 
 65 | 
 66 | 
 67 | **3) RIGHT OUTER JOIN**
 68 | 
 69 | <img src="https://user-images.githubusercontent.com/33534771/75853699-f8468100-5e31-11ea-8c0f-5109f2852c59.png"/>
 70 | 
 71 | - LEFT OUTER JOIN의 반대이다.
 72 | - 오른쪽 테이블을 기준으로 Join을 하겠다고 생각하면 된다.
 73 | - 결과값은 B 테이블의 모든 데이터와 A 테이블과 B 테이블에서 중복되는 값이 검색된다.
 74 | 
 75 | ```sql
 76 | SELECT
 77 | A.NAME,
 78 | B.AGE
 79 | FROM EX_TABLE A
 80 | RIGHT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
 81 | ```
 82 | 
 83 | 
 84 | 
 85 | **4) FULL OUTER JOIN**
 86 | 
 87 | <img src="https://user-images.githubusercontent.com/33534771/75853732-072d3380-5e32-11ea-8cda-53eb71de966e.png"/>
 88 | 
 89 | - 쉽게 말해 **합집합**을 생각하면 된다.
 90 | - A 테이블이 가지고 있는 데이터, B 테이블이 가지고 있는 **데이터 모두 검색된다.**
 91 | - 사실상, 기준 테이블의 의미가 없다.
 92 | 
 93 | ```sql
 94 | SELECT
 95 | A.NAME,
 96 | B.AGE
 97 | FROM EX_TABLE A
 98 | FULL OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
 99 | ```
100 | 
101 | 
102 | **5) CROSS JOIN**
103 | 
104 | <img src="https://user-images.githubusercontent.com/33534771/75853764-16ac7c80-5e32-11ea-9942-04adab33ddb2.png"/>
105 | 
106 | - **모든 경우의 수를 전부 표현해주는 방식**이다.
107 | - 기준 테이블이 A일 경우, A의 데이터 한 ROW를 B 테이블 전체와 JOIN하는 방식이다.
108 | - 결과값은 N*M이다.
109 | - 위의 경우 A 테이블에 데이터가 3개, B 테이블에 데이터가 4개가 있으므로 총 12개가 검색된다.
110 | 
111 | ```sql
112 | --첫 번째 방식--
113 | SELECT
114 | A.NAME,
115 | B.AGE
116 | FROM EX_TABLE A
117 | CROSS JOIN JOIN_TABLE B
118 | 
119 | --두 번째 방식--
120 | SELECT
121 | A.NAME,
122 | B.AGE
123 | FROM EX_TABLE A, JOIN_TABLE B
124 | ```
125 | 
126 | 
127 | 
128 | 6) SELF JOIN
129 | 
130 | <img src="https://user-images.githubusercontent.com/33534771/75853799-2926b600-5e32-11ea-94ce-4974aade41ca.png"/>
131 | 
132 | - 자기 자신과 자기 자신을 조인한다는 의미이다.
133 | - 하나의 테이블을 여러번 복사해서 조인한다고 생각하면 된다.
134 | - 자신이 가지고 있는 칼럼을 다양하게 변형시켜 활용할 경우에 자주 사용한다.
135 | 
136 | ```sql
137 | SELECT
138 | A.NAME,
139 | B.AGE
140 | FROM EX_TABLE A, EX_TABLE B
141 | ```
142 | 
143 | 
144 | 
145 | ### 참고
146 | 
147 | [JOIN의 종류설명 및 사용법 & 예제](https://coding-factory.tistory.com/87)
148 | 


--------------------------------------------------------------------------------
/Database/SQL vs NoSQL.md:
--------------------------------------------------------------------------------
  1 | ## SQL vs NoSQL
  2 | 
  3 | 백엔드 개발을 주로 하지 않기 때문에 정확한 차이를 모른다. 
  4 | 
  5 | 그래서 각각이 언제 쓰이고 무슨 특징과 차이점을 갖는지 공부하고 정리하려 한다.
  6 | 
  7 | 
  8 | 
  9 | 웹 앱을 개발할 때, 데이터베이스를 선택할 때 고민하게 된다.
 10 | 
 11 | - MySQL과 같은 SQL을 사용할까? 아니면 MongoDB와 같은 NoSQL을 사용할까?
 12 | 
 13 | 보통 Spring에서 개발할 때는 MySQL을, Node.js에서 사용할 때는 MongoDB를 주로 사용했을 것이다. 하지만 단순히 프레임워크에 따라 결정하는 것이 아니다.
 14 | 
 15 | 프로젝트를 진행하기 앞서 적합한 데이터베이스를 택해야 한다. 
 16 | 
 17 | 이에 대해 알아보자.
 18 | 
 19 | 
 20 | 
 21 | ### SQL (관계형 DB)
 22 | 
 23 | - SQL을 사용하면 RDBMS에서 데이터를 저장, 수정, 삭제 및 검색할 수 있다.
 24 | - 관계형 데이터베이스에는 핵심적인 두 가지 특징이 있다.
 25 |   1. 데이터는 **정해진 데이터 스키마에 따라 테이블에 저장**된다.
 26 |   2. 데이터는 **관계를 통해 여러 테이블에 분산**된다.
 27 | 
 28 | 데이터는 테이블에 레코드로 저장되는데, 각 테이블마다 명확하게 정의된 구조가 있다. 해당 구조는 필드의 이름과 데이터 유형으로 정의된다.
 29 | 
 30 | 
 31 | 
 32 | 따라서 **스키마를 준수하지 않은 레코드는 테이블에 추가할 수 없다.** 즉, 스키마를 수정하지 않는 이상은 정해진 구조에 맞는 레코드만 추가가 가능한 것이 관계형 데이터베이스의 특징 중 하나이다.
 33 | 
 34 | 
 35 | 
 36 | 또한, 데이터의 중복을 피하기 위해 `관계`를 이용한다.
 37 | 
 38 | <img src="https://user-images.githubusercontent.com/33534771/75773355-14deac80-5d91-11ea-82e2-5557552c74a7.png"/>
 39 | 
 40 | 하나의 테이블에서 중복 없이 하나의 데이터만을 관리하기 때문에 다른 테이블에서 부정확한 데이터를 다룰 위험이 줄어드는 장점이 있다.
 41 | 
 42 | 
 43 | 
 44 | 
 45 | 
 46 | ### NoSQL(비관계형 DB)
 47 | 
 48 | - 말그대로 관계형 DB의 반대이다.
 49 | - 스키마도 없고 관계도 없다.
 50 | - NoSQL에서는 레코드를 문서(documents)라고 부른다.
 51 | 
 52 | 
 53 | 
 54 | 여기서 SQL과 핵심적인 차이가 있다. SQL은 정해진 스키마를 따르지 않으면 데이터 추가가 불가능했다.
 55 | 
 56 | 하지만 NoSQL에서는 다른 구조의 데이터를 같은 컬렉션에 추가가 가능하다.
 57 | 
 58 | 
 59 | 
 60 | 문서(documents)는 Json과 비슷한 형태로 가지고 있다. 관계형 데이터베이스처럼 여러 테이블에 나누어담지 않고, 관련 데이터를 동일한 '컬렉션'에 넣는다.
 61 | 
 62 | 따라서 위의 사진의 SQL에서 진행한 Orders, Users, Products 테이블로 나눈 것을 NoSQL에서는 Orders에 한꺼번에 포함해서 저장하게 된다.
 63 | 
 64 | 따라서 여러 테이블에 조인할 필요없이 이미 필요한 모든 것을 갖춘 문서를 작성하는 것이 NoSQL이다.
 65 | 
 66 | (NoSQL에는 조인이라는 개념이 존재하지 않는다.)
 67 | 
 68 | 
 69 | 
 70 | 그러면 조인하고 싶을 때 NoSQL은 어떻게 할까?
 71 | 
 72 | > 컬렉션을 통해 데이터를 복제하여 각 컬렉션 일부분에 속하는 데이터를 정확하게 산출하도록 한다.
 73 | 
 74 | 하지만, 이러면 데이터가 중복되어 서로 영향을 줄 위험이 있다. 따라서 조인을 잘 사용하지 않고 자주 변경되지 않는 데이터일 때, NoSQL을 쓰면 상당히 효율적이다.
 75 | 
 76 | 
 77 | 
 78 | ### 확장 개념
 79 | 
 80 | 두 데이터베이스를 비교할 때 중요한 Scaling 개념도 존재한다.
 81 | 
 82 | 데이터베이스 서버의 확장성은 **수직적** 확장과 **수평적** 확장으로 나누어진다.
 83 | 
 84 | - 수직적 확장 : 단순히 데이터베이스 서버의 성능을 향상시키는 것(ex. CPU 업그레이드)
 85 | - 수평적 확장 : 더 많은 서버가 추가되고 데이터베이스가 전체적으로 분산됨을 의미한다.(하나의 데이터베이스에서 작동하지만, 여러 호스트에서 작동)
 86 | 
 87 | 데이터 저장 방식으로 인해 SQL DB는 일반적으로 수직적 확장만 지원한다.
 88 | 
 89 | 수평적 확장은 NoSQL DB에서만 가능하다.
 90 | 
 91 | 둘 중에 뭘 선택하느냐에 대한 정답은 없다. 어떤 데이터를 다루느냐에 따라 원하는 방식에 맞게 선택을 고려하면 된다.
 92 | 
 93 | 
 94 | 
 95 | ### SQL 장/단점
 96 | 
 97 | **[장점]**
 98 | 
 99 | - 명확하게 정의된 스키마, 데이터 무결성 보장
100 | - 관계는 각 데이터를 중복 없이 한번만 저장.
101 | 
102 | 
103 | 
104 | [단점]
105 | 
106 | - 덜 유연하다. 데이터 스키마를 사전에 계획하고 알려야 한다.(나중에 수정하기 힘듦.)
107 | - 관계를 맺고 있어서 조인문이 많은 복잡한 쿼리가 만들어질 수 있음.
108 | - 대체로 수직적 확장만 가능하다.
109 | 
110 | 
111 | 
112 | ### NoSQL 장/단점
113 | 
114 | [장점]
115 | 
116 | - 스키마가 없어서 유연하다. 언제든지 저장된 데이터를 조정하고 새로운 필드 추가가 가능하다.
117 | - 데이터는 애플리케이션이 필요로 하는 형식으로 저장된다. 데이터를 읽어오는 속도가 빨라진다.
118 | - 수직 및 수평 확장이 가능해서 애플리케이션이 발생시키는 모든 읽기/쓰기 요청 처리가 가능하다.
119 | 
120 | 
121 | 
122 | [단점]
123 | 
124 | - 유연성으로 인해 데이터 구조 결정을 미루게 될 수 있다.
125 | - 데이터 중복을 계속 업데이트 해야 한다.
126 | - 데이터가 여러 컬렉션에 중복되어 있기 때문에 수정시 모든 컬렉션에서 수행해야 한다. (SQL에서는 중복 데이터가 없으므로 한번만 수행이 가능)
127 | 
128 | 
129 | 
130 | ### SQL DB 사용이 더 좋을 때
131 | 
132 | - 관계를 맺고 있는 데이터가 자주 변경되는 애플리케이션의 경우
133 | 
134 |   > NoSQL에서는 여러 컬렉션을 모두 수정해야 하기 때문에 비효율적
135 | 
136 | - 변경될 여지가 없고, 명확한 스키마가 사용자와 데이터에게 중요한 경우
137 | 
138 | 
139 | 
140 | ### NoSQL DB 사용이 더 좋을 때
141 | 
142 | - 정확한 데이터 구조를 알 수 없거나 변경/확장이 될 수 있는 경우
143 | - 읽기를 자주 하지만, 데이터 변경은 자주 없는 경우
144 | - 데이터베이스를 수평으로 확장해야 하는 경우(막대한 양의 데이터를 다뤄야 하는 경우)
145 | 


--------------------------------------------------------------------------------
/Database/데이터베이스 기본 용어.md:
--------------------------------------------------------------------------------
 1 | ## 데이터베이스 - 용어정리
 2 | 
 3 | 다양한 용어가 사용되는데, 데이터베이스에 대한 지식이 별로 없어서 이를 정리하려 한다.
 4 | 
 5 | 
 6 | 
 7 | ### 테이블(Table)
 8 | 
 9 | - 행과 열로 이루어진 데이터의 집합을 테이블이라고 한다.
10 | - 흔히 생각하는 엑셀을 떠올리면 편하다.
11 | - 일반적인 데이터베이스에서는 행과 열만 있으면 테이블이라고 하지만, **관계형 데이터베이스**에서는 여기에 특별한 제약을 추가해서 **릴레이션(Relation)**이라고 부른다.
12 | - 아래 조건을 충족하는 테이블만이 릴레이션이 될 수 있기 때문에 모든 릴레이션은 테이블이지만, 모든 테이블이 릴레이션인건 아니다.
13 | 
14 | 1. 모든 값은 유일한 값을 가진다.
15 | 2. 하나의 릴레이션에서 중복되는 행이 존재하면 안된다.
16 | 
17 | 
18 | 
19 | 
20 | 
21 | ### 행(Row)
22 | 
23 | - 테이블을 구성하는 데이터들 중 가로로 묶은 데이터셋을 의미한다.
24 | - 일반적으로 행은 한 객체에 대한 정보를 가지고 있다. 
25 | - 이또한 관계형 데이터베이스에서는 **튜플** 또는 **레코드**라는 이름으로 불린다.
26 | 
27 | 
28 | 
29 | ### 열(Colum)
30 | 
31 | - 테이블을 구성하는 데이터들 중 세로로 묶은 데이터셋을 의미한다.
32 | - 일반적으로 열은 그 테이블의 속성을 의미하며 열을 구성하는 값들은 같은 **도메인(Domain)**으로 되어 있다.
33 | - 이또한 관계형 데이터베이스에서는 **속성(Attribute)**이라는 이름으로 불린다.
34 | 
35 | 
36 | 
37 | ### 도메인(Domain)
38 | 
39 | - 데이터베이스에서 필드(Field)에 채워질 수 있는 값의 집합이다.
40 | - 예를 들어, 도메인이 1에서 10사이의 정수인 속성의 필드에 11이나 -1처럼 도메인을 벗어나는 값 또는 "고양이"처럼 아예 자료형이 다른 값이 들어갈 수 없다.
41 | 
42 | 
43 | 
44 | ### 스키마(Schema)
45 | 
46 | - 데이터베이스의 구조를 전반적으로 기술한 것을 말한다.
47 | - 구체적으로 데이터베이스를 구성하는 데이터 레코드의 크기, 키의 정의, 레코드 간의 관계 등을 정의한 것을 말한다.
48 | - 사용자의 관점에 따라 외부 스키마, 개념 스키마, 내부 스키마로 구분한다.
49 | - DBMS는 외부 스키마에 명세된 사용자의 요구를 개념 스키마 형태로 변환하고, 이를 다시 내부 스키마 형태로 변환한다.
50 | 
51 | 
52 | 
53 | 외부 스키마
54 | 
55 | - 사용자의 입장에서 정의한 데이터베이스의 논리적 구조
56 | - 데이터들을 어떤 형식, 구조, 화면을 통해 사용자에게 보여줄 것인가에 대한 명세를 말하며 하나의 데이터베이스에는 여러 개의 외부 스키마가 있을 수 있다.
57 | - 일반 사용자에게는 질의어를 이용해 DB를 쉽게 사용할 수 있도록 하고 응용 프로그래머는 언어를 사용해서 DB에 접근하도록 한다.
58 | 
59 | 
60 | 
61 | 개념 스키마
62 | 
63 | - 조직체 전체를 관장하는 입장에서 DB를 정의한 스키마.
64 | - DB에 대한 모든 논리적 구조를 기술하기 때문에 데이터베이스에 하나만 존재하며, 통상 스키마라고 하면 개념 스키마를 일컫는다.
65 | 
66 | 
67 | 
68 | 내부 스키마
69 | 
70 | - 데이터베이스가 어떻게 저장 장치에 저장될 지에 대한 명세.
71 | - 물리적인 저장 장치와 데이터베이스 간의 관계를 정의하므로 시스템 프로그래머나 시스템 설계자가 보는 관점의 스키마이다.
72 | 
73 | 
74 | 
75 | ### 참고
76 | 
77 | [데이터베이스 - 용어정리](https://eastroot1590.tistory.com/entry/데이터베이스-용어-튜플Tuple과-어트리뷰트Attribute)
78 | 


--------------------------------------------------------------------------------
/Database/이상(Anomaly).md:
--------------------------------------------------------------------------------
 1 | ## Anomaly
 2 | 
 3 | 정규화를 해야 하는 이유는 잘못된 테이블 설계로 인해 Anomaly(이상 현상)가 나타나기 때문이다.
 4 | 
 5 | 여기서 Anomaly가 무엇인지 알아보자.
 6 | 
 7 | 
 8 | 
 9 | Ex)
10 | 
11 | {Student ID, CourseID, Department, Course ID, Grade}
12 | 
13 | 
14 | 
15 | **1) 삽입 이상(Insertion Anomaly)**
16 | 
17 | 기본키가 {Student ID, Course ID} 인 경우
18 | 
19 | Course를 수강하지 않은 학생은 Course ID가 없는 현상이 발생한다. 결국, Course ID를 Null로 할 수 밖에 없는데, 기본키는 Null이 될 수 없으므로 테이블에 추가될 수 없다.
20 | 
21 | 굳이 삽입하기 위해서는 '미수강'과 같은 Course ID를 만들어야 한다.
22 | 
23 | **불필요한 데이터를 추가해야 삽입할 수 있는 상황 => Insertion Anomaly**
24 | 
25 | 
26 | 
27 | **2) 갱신 이상(Update Anomaly)**
28 | 
29 | 만약 어떤 학생의 전공 {Department}이 "컴퓨터 -> 음악"으로 바뀌는 경우
30 | 
31 | 모든 Department를 "음악"으로 바꾸어야 한다. 그러나 일부를 깜빡하고 바꾸지 못하는 경우, 제대로 파악하지 못한다.
32 | 
33 | **일부만 변경하여 데이터가 불일치하는 모순의 문제 => Update Anomaly**
34 | 
35 | 
36 | 
37 | **3) 삭제 이상(Deletion Anomaly)**
38 | 
39 | 만약 어떤 학생이 수강을 철회하는 경우, {Student ID, Course ID, Department, Course ID, Grade}의 정보 중 Course ID를 삭제하면 Student ID, Department와 같은 학생에 대한 정보도 함께 삭제된다.
40 | 
41 | **튜플 삭제로 인해 꼭 필요한 데이터까지 함께 삭제되는 문제 => Deletion Anomaly**


--------------------------------------------------------------------------------
/Database/인덱스(INDEX).md:
--------------------------------------------------------------------------------
  1 | ## 인덱스
  2 | 
  3 | ### INDEX의 의미
  4 | 
  5 | - RDBMS에서 검색 속도를 높이기 위해 사용하는 하나의 기술이다.
  6 | - INDEX는 색인이다.
  7 | - 해당 Table의 컬럼을 색인화(따로 파일로 저장)하여 검색시 해당 Table의 레코드를 full scan하는게 아니라 색인화 되어있는 INDEX 파일을 검색하여 검색 속도를 빠르게 한다.
  8 | - INDEX 구조는 Tree 구조로 색인화한다.
  9 | - RDBMS에서 사용하는 INDEX는 Balance Search Tree를 사용한다.
 10 | 
 11 | 
 12 | 
 13 | ### INDEX의 원리
 14 | 
 15 | INDEX를 해당 컬럼에 주게 되면 초기 Table 생성시, **FRM, MYD, MYI** 3개의 파일이 만들어진다.
 16 | 
 17 | - FRM : 테이블 구조가 저장되어 있는 파일
 18 | - MYD : 실제 데이터가 있는 파일
 19 | - MYI : INDEX 정보가 들어있는 파일
 20 | 
 21 | 
 22 | 
 23 | INDEX를 사용하지 않는 경우, MYI 파일은 비어져 있다. 
 24 | 
 25 | 그러나 INDEX를 해당 컬럼에 만들게 되면 해당 컬럼을 따로 인덱싱하여 MYI 파일에 입력한다.
 26 | 
 27 | 이후에 사용자가 SELECT 쿼리로 INDEX를 사용하는 쿼리를 사용시 해당 Table을 검색하는 것이 아니라 MYI 파일의 내용을 검색한다.
 28 | 
 29 | 
 30 | 
 31 | 만약, INDEX를 사용하지 않은 SELECT 쿼리라면 해당 Table Full scan하여 모두 검색한다.
 32 | 
 33 | 이는 책의 뒷부분에 <찾아보기>와 같은 의미로 정리해둔 단어 중에서 원하는 단어를 찾아서 페이지수를 보고 쉽게 찾을 수 있는 개념과 같다. 만약, 이 <찾아보기>가 없다면 처음부터 끝까지 모든 페이지를 보고 찾아와야할 것이다.
 34 | 
 35 | 
 36 | 
 37 | ### INDEX 장점
 38 | 
 39 | - 키 값을 기초로 하여 테이블에서 검색과 정렬 속도를 향상시킨다.
 40 | - 인덱스를 사용하면 테이블 행의 고유성을 강화시킬 수 있다.
 41 | - 테이블의 기본키는 자동으로 인덱스된다.
 42 | - 필드 중에는 데이터 형식 때문에 인덱스 될 수 없는 필드도 있다.
 43 | - 여러 필드로 이루어진(다중 필드)인덱스를 사용하면 첫 필드 값이 같은 레코드도 구분할 수 있다.
 44 | 
 45 | 참고로 액세스에서 다중 필드 인덱스는 최대 10개의 필드를 포함할 수 있다.
 46 | 
 47 | 
 48 | 
 49 | ### INDEX 단점
 50 | 
 51 | - 인덱스를 만들면 .mdb 파일 크기가 늘어난다.
 52 | - 사용자가 한 페이지를 동시에 수정할 수 있는 병행성이 줄어든다.
 53 | - 인덱스된 필드에서 데이터를 업데이트하거나 **레코드를 추가 또는 삭제할 때 성능이 떨어진다.**
 54 | - 인덱스가 데이터베이스 공간을 차지재 추가적인 공간이 필요해진다.(DB의 10% 내외의 공간이 추가로 필요하다.)
 55 | - 인덱스를 생성하는데 시간이 많이 소요될 수 있다.
 56 | - **데이터 변경 작업이 자주 일어날 경우에 인덱스를 재작성해야 할 필요가 있기에 성능에 영향을 끼칠 수 있다.**
 57 | 
 58 | 
 59 | 
 60 | 따라서 어느 필드를 인덱스해야 하는지 미리 시험해보고 결정하는 것이 좋다. 인덱스를 추가하면 쿼리 속도가 1초 정도 빨라지지만, 데이터 행을 추가하는 속도는 2초 정도 느려지게 되어 여러 사용자가 사용하는 경우, 레코드 잠금 문제가 발생할 수 있다.
 61 | 
 62 | 
 63 | 
 64 | 또, 다른 필드에 대한 인덱스를 만들게 되면 성능이 별로 향상되지 않을 수도 있다. 예를 들어, 테이블에 회사 이름 필드와 성 필드가 이미 인덱스된 경우에 우편 번호를 필드로 추가해 인덱스에 포함해도 성능이 거의 향상되지 않는다. 만드는 쿼리의 종류와 관계 없이 가장 고유한 값을 갖는 필드만 인덱스해야 한다.
 65 | 
 66 | 
 67 | 
 68 | ### INDEX의 목적
 69 | 
 70 | RDBMS에는 INDEX가 있다. 인덱스의 목적은 RDBMS의 검색 속도를 높이는데 있다.
 71 | 
 72 | SELECT 쿼리의 WHERE절이나 JOIN 예약어를 사용했을 때만 인덱스를 사용하며, **SELECT 쿼리의 검색 속도를 빠르게 하는데 목적을 두고 있다.**
 73 | 
 74 | - DELETE, INSERT, UPDATE 쿼리에는 해당 사항이 없으며 INDEX 사용시 오히려 좀 느려진다.
 75 | 
 76 | 
 77 | 
 78 | ### 상황 분석
 79 | 
 80 | **[사용하면 좋은 경우]**
 81 | 
 82 | 1) Where절에서 자주 사용되는 Column
 83 | 
 84 | 2) 외래키가 사용되는 Column
 85 | 
 86 | 3) Join에 자주 사용되는 Column
 87 | 
 88 | 
 89 | 
 90 | **[Index 사용을 피해야 하는 경우]**
 91 | 
 92 | - Data 중복도가 높은 Column
 93 | - DML이 자주 일어나는 Column
 94 | 
 95 | 
 96 | 
 97 | ### DML에 취약
 98 | 
 99 | 1. `INSERT`
100 |    - **indext split** : 인덱스의 Block들이 하나에서 두개로 나누어지는 현상.
101 |    - 인덱스는 데이터가 순서대로 정렬되어야 한다. 기존 블록에 여유 공간이 없는 상황에서 그 블록에 새로운 데이터가 입력되어야 할 경우, 오라클이 기존 블록의 내용 중 일부를 새 블록에다가 기록한 후, 기존 블록에 빈 공간을 만들어서 새로운 데이터를 추가하게 된다.
102 |    - 성능면에서 매우 불리하다.
103 |      - Index split은 새로운 블록을 할당받고 Key를 옮기는 복잡한 작업을 수행한다. 모든 수행 과정이 Redo에 기록되고 많은 양의 Redo를 유발한다.
104 |      - Index split이 이루어지는 동안 해당 블록에 대해 키 값이 변경되면 안되므로 DML이 블로킹된다.
105 | 
106 | 
107 | 
108 | 2. DELETE
109 |    - 테이블에서 데이터가 Delete될 경우, 지워지고 다른 데이터가 그 공간을 사용할 수 있다.
110 |    - **index에서 데이터가 delete될 경우, 데이터가 지워지지 않고 사용 안됨 표시만 해둔다.**
111 |    - 즉, 테이블에 데이터가 1만건 있는 경우, 인덱스에는 2만건이 있을 수 있다는 뜻이다.
112 |    - 인덱스를 사용해도 수행 속도를 기대하기 힘들다.
113 | 
114 | 
115 | 
116 | 3. UPDATE
117 |    - **인덱스에는 Update 개념이 없다.**
118 |    - 테이블에 update가 발생할 경우, 인덱스에서는 delete가 먼저 발생한 후 새로운 작업의 insert 작업이 발생한다. 
119 |    - **delete와 insert 두 개의 작업이 인덱스에서 동시에 일어나 다른 DML보다 더 큰 부하를 주게 된다.**
120 | 
121 | ### 참고
122 | 
123 | [DB INDEX란?](https://lalwr.blogspot.com/2016/02/db-index.html)


--------------------------------------------------------------------------------
/Database/트랜잭션.md:
--------------------------------------------------------------------------------
 1 | ## 트랜잭션
 2 | 
 3 | - 데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위
 4 | - **상태를 변화시킨다는 것은 SQL 질의어를 통해 DB에 접근하는 것이다.**
 5 | 
 6 | ```sql
 7 | SELECT
 8 | INSERT
 9 | DELETE
10 | UPDATE
11 | ```
12 | 
13 | - 작업 단위 -> **많은 SQL  명령문들을 사람이 정하는 기준에 따라 정하는 것**
14 | 
15 | - Ex) 게시판에서 사용자가 글을 작성하고 올리기 버튼을 누른 후 게시판에 다시 돌아오면 게시판에 내가 쓴 글이 업데이트된 상태를 볼 수 있다.
16 | - 이때 DB 작업
17 |   - 올리기 버튼을 누른다. : INSERT문을 사용해 사용자가 입력한 게시글 데이터를 옮김.
18 |   - 게시판 새로 구성 : SELECT문을 사용해 최신 정보를 유지.
19 | - 현재 작업 단위 : INSERT문+SELECT문
20 |   - 이를 통틀어 하나의 트랜잭션이라고 한다.
21 | - **즉, 하나의 트랜잭션 설계를 잘 만드는 것이 데이터를 다룰 때 많은 이점을 가져다준다.**
22 | 
23 | 
24 | 
25 | 
26 | 
27 | ### 트랜잭션 특징
28 | 
29 | - 원자성(Atomicity)
30 |   - 트랜잭션이 DB에 모두 반영되거나 혹은 전혀 반영되지 않아야 한다.
31 | - 일관성(Consistency)
32 |   - 트랜잭션의 작업 처리 결과는 항상 일관성 있어야 한다.
33 | - 독립성(Isolation)
34 |   - 둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다.
35 | - 지속성(Durability)
36 |   - 트랜잭션이 성공적으로 완료되었으면, 결과는 영구적으로 반영되어야 한다.
37 | 
38 | 
39 | 
40 | `Commit`
41 | 
42 | - 하나의 트랜잭션이 성공적으로 끝났고, DB가 일관성있는 상태일 때 이를 알려주기 위해 사용하는 연산이다.
43 | 
44 | `Rollback`
45 | 
46 | - 하나의 트랜잭션 처리가 비정상적으로 종료되어 트랜잭션의 원자성이 깨진 경우
47 | - 트랜잭션이 정상적으로 종료되지 않았을 때, last consistent state(ex. 트랜잭션의 시작 상태)로 roll back할 수 있다.


--------------------------------------------------------------------------------
/Java/HashSet vs HashMap.md:
--------------------------------------------------------------------------------
 1 | ### HashSet, HashMap
 2 | 
 3 | HashMap과 HashSet은 모두 Collection Framework에 속한다.   
 4 | 기본적으로 Collection Framework는 Set, List, Queue 인터페이스로 나뉘어진다.
 5 | 
 6 | - Set : 객체를 받지만, 중복되는 값은 허용하지 않는다.(순서가 없다.)
 7 | - List : 인덱싱하여 중복을 허용한다.
 8 | - Queue : 선입선출(FCFS) 알고리즘을 기반으로 한다.
 9 | 
10 | 
11 | 
12 | #### HashSet
13 | 
14 | Set 인터페이스를 구현한 것으로 중복된 값을 허용하지 않는다.
15 | HashSet에 들어가는 객체들은 반드시 equals()와 hashCode() 메소드를 구현해야 하는데, 이 메소드들을 가지고 HashSet에 들어갈 때, 중복된 객체가 있는지 여부를 체크하게 된다. 
16 | 
17 | 
18 | 
19 | #### HashMap
20 | 
21 | Map 인터페이스를 구현한 것으로 Key-Value 형태의 데이터를 저장한다.   
22 | 중복된 Key 값은 허용되지 않는다. 다만, 중복된 값의 저장은 허용한다.  
23 | null value, null key 를 허용한다.
24 | 
25 | - HashMap : 집어 넣은 순서를 유지하지 않는다.
26 | - TreeMap : 내부적으로 RedBlack Tree로 저장되며, Key 값을 기준으로 알파벳 순서대로 정렬한다.
27 | - LinkedHashMap : 집어 넣은 순서를 유지한다.
28 | 
29 | 
30 | 
31 | #### 차이점
32 | 
33 | [HashMap]
34 | 
35 | 1. Map 인터페이스 구현
36 | 2. 데이터를 Key-Value 형식으로 저장한다.
37 | 3. HashMap에서 hashCode 값은 key value를 이용하여 생성한다.
38 | 4. HashMap은 unique key를 이용하여 데이터에 바로 접근하기에 HashSet에 비해서 빠르다.
39 | 
40 | 
41 | 
42 | [HashSet]
43 | 
44 | 1. Set 인터페이스를 구현
45 | 2. 객체만 저장할 수 있다.
46 | 3. 들어가는 객체를 이용하여 hashCode를 생성하고, equals() 메소드를 이용해 hashCode를 비교해서 중복된 객체가 있는지 체크한다. (equals() 메소드는 중복된 객체가 있으면 true, 없으면 false 반환)
47 | 4. HashMap에 비해서 느리다.
48 | 
49 | 
50 | 
51 | ### HashMap vs HashTable vs ConcurrentHashMap
52 | 
53 | - 컬렉션의 Map 인터페이스를 구현한 클래스이다.
54 | - key, value를 이용하여 값을 저장하는 구조이다.
55 | 
56 | 
57 | 
58 | 1. HashTable
59 |    - 동기화를 지원하므로 멀티 스레드 환경에서 사용할 수 있다.
60 |    - Key, Value에 Null을 허용하지 않는다.
61 |    - put, get과 같은 주요 메소드에 synchronized 키워드가 선언되어 있다.
62 | 
63 | 2. HashMap
64 |    - 동기화를 지원하지 않으므로 멀티 스레드 환경에는 적합하지 않다.
65 |    - Key, Value에 Null을 허용한다. 
66 |    - 주요 메소드에 synchronized 키워드가 없다.
67 | 
68 | 3. ConcurrentHashMap
69 |    - HashMap에 ThreadSafe를 추가한 것으로서 멀티 스레드 환경에서 HashMap을 동기화 시킨 Collections이다.
70 |    - HashTable은 메소드 전체에 synchronized를 선언하는 반면 **ConcurrentHashMap은 동기화가 필요한 부분에만 동기화를 적용했기 때문에 동기화에서 발생하는 오버헤드가 줄어든다.**
71 | 
72 | 
73 | 
74 | [결론]
75 | 
76 | 멀티 스레드 환경이라면 HashMap보단 HashTable 혹은 ConcurrentHashMap을 사용하는 것을 고려해야하고,
77 | HashTable보다는 Java 5부터 제공하는 ConcurrentHashMap을 사용하는 것이 성능적인 면에서 더 좋다고 볼 수있다.
78 | 
79 | 
80 | 
81 | ### 참고
82 | 
83 | - [[Java]HashSet과 HashMap](https://postitforhooney.tistory.com/entry/JavaHashSet과-HashMap)
84 | - [[Java] HashMap과 HashTable 차이](https://odol87.tistory.com/3)
85 | - [Hashtable, HashMap, ConcurrentHashMap 비교](https://jdm.kr/blog/197)
86 | - [[Java]HashSet과 HashMap](https://postitforhooney.tistory.com/entry/JavaHashSet과-HashMap)
87 | 
88 | 


--------------------------------------------------------------------------------
/Java/Integer vs int.md:
--------------------------------------------------------------------------------
 1 | ### Integer vs int
 2 | 
 3 | 사실, 이 둘의 차이는 대부분 알 것이라고 생각한다. 
 4 | 
 5 | 정리하는 이유는 최근에 알게 된 사실 때문이다.
 6 | 
 7 | int
 8 | 
 9 | - Primitive 자료형
10 | - 산술 연산이 가능하며, null 값을 가질 수 없다.
11 | 
12 | Integer
13 | 
14 | - Wrapper 클래스(객체)
15 | - Unboxing을 하지 않으면 산술 연산이 불가능하지만, null 값을 가질 수 있다.
16 | - Collection, null 값이 필요한 경우 사용한다.
17 | 
18 | 
19 | 
20 | ### Integer와 int의 size 비교
21 | 
22 | - Integer 및 int 배열을 1,000,000개 생성한다.
23 | - 결과
24 |   - Integer :  19986824 byte
25 |   - int : 3998536 byte
26 |   - 4.99배(약 5배)
27 | 
28 | 
29 | 
30 | **요약**
31 | 
32 | - Object : 8 byte
33 | - Integer : 16 byte
34 | - Integer를 참조하는데 4 byte
35 | - 따라서 Integer의 size = 20 byte
36 | - int의 size : 4 byte
37 | - 5배 차이가 난다.
38 | 
39 | 
40 | 
41 | ### 참고
42 | 
43 | - [[Java] Integer와 int의 차이](https://includestdio.tistory.com/1)
44 | 
45 | 


--------------------------------------------------------------------------------
/Java/[Java] ==와 equals() 차이.md:
--------------------------------------------------------------------------------
 1 | ## ==와 equals() 차이
 2 | 
 3 | - == 
 4 |   - 비교를 위한 연산자.
 5 |   - 비교하고자 하는 대상의 **주소값**을 비교한다. 
 6 | - equals()
 7 |   - 메소드이며, 객체끼리 내용을 비교할 수 있다.
 8 |   - 비교하고자 하는 **대상의 내용 자체**를 비교한다.
 9 | 
10 | 
11 | 
12 | [Code]
13 | 
14 | ```java
15 | String a = "a";
16 | String b = a;
17 | String c = new String("a"); // 새로운 객체 생성. 주소가 다름.
18 | 
19 | // 주소값을 비교. 
20 | a == b; // true
21 | a == c; // false
22 | 
23 | // 내용(값)을 비교. 
24 | a.equals(b); // true
25 | a.equals(c); // true
26 | ```
27 | 
28 | 


--------------------------------------------------------------------------------
/Java/[Java] Call by Value vs Call by Reference.md:
--------------------------------------------------------------------------------
 1 | ## Call by value vs Call by Reference
 2 | 
 3 | 간단하면서도 헷갈리는 개념 중 하나이다. 
 4 | 
 5 | 결론 : 자바는 `Call by Value`이다.
 6 | 
 7 | 
 8 | 
 9 | Primitive Type(원시 자료형)의 경우 Call by Value
10 | 
11 | - int, short, long, float, double, char, boolean
12 | 
13 | 
14 | 
15 | Reference Type(참조 타입)의 경우 Call by Value
16 | 
17 | - Array, 참조 타입
18 | 
19 | 
20 | 
21 | 자바에서는 함수의 인자로 전달되는 타입이 기본형(원시 자료형)인 경우 값을 넘기게 되어있다. 이 경우 메모리에는 함수를 위한 별도의 공간이 생성된다. 이는 함수 종료시 사라진다. 따라서 함수 안에서 해당 인자의 값을 변경하더라도 원본 값은 바뀌지 않는 특징이 있다.
22 | ```java
23 | public class Test {
24 |     public static void main(String[] args) {
25 |         int n = 10;
26 |         System.out.println(n);
27 |         test(10);
28 |         System.out.println(n);
29 |         // 값이 바뀌지 않는다는 걸 볼 수 있다. 
30 |     }
31 | 
32 |     public static void test(int n) {
33 |         n -= 5;
34 |         System.out.println(n);
35 |     }
36 | }
37 | // 결과
38 | 10
39 | 5
40 | 10
41 | ```
42 | 
43 | 참조형(참조 타입)인 경우, 변수가 가지는 값이 주소 값이므로 Call by Value에 의해 주소 값이 전달된다. 따라서 함수 안에서 해당 인자의 값을 변경하게 되면 주소값을 통해 참조하고 있는 값을 변경하기 때문에 원본 값도 바뀌게 되는 특징이 있다.
44 | 
45 | ```java
46 | public class Test {
47 |     public static void main(String[] args) {
48 |         int[] arr = {1, 2, 3};
49 |         for (int num : arr) System.out.print(num + " ");
50 |         System.out.println();
51 |         test(arr);
52 | 
53 |         for (int num : arr) System.out.print(num + " ");
54 |     }
55 | 
56 |     // 참조형의 경우, 주소값이 전달되므로 값을 변경하면 원본도 영향을 받는다.
57 |     public static void test(int[] a) {
58 |         for (int i = 0; i < a.length; i++) {
59 |             a[i] *= 10;
60 |         }
61 |     }
62 | }
63 | // 결과
64 | 1 2 3 
65 | 10 20 30 
66 | ```
67 | 
68 | 
69 | 
70 | Ref : https://bcp0109.tistory.com/360
71 | 


--------------------------------------------------------------------------------
/Java/[Java] Garbage Collection.md:
--------------------------------------------------------------------------------
 1 | ## Garbage Collection
 2 | 
 3 | <img src = "https://user-images.githubusercontent.com/33534771/83469636-33049780-a4bb-11ea-8135-9bae85b79a10.png" />
 4 | 
 5 | ### [Minor GC]
 6 | 
 7 | - 새로 생성된 대부분의 객체는 Eden 영역에 위치한다. 
 8 | - Eden 영역이 꽉 차게 되면 GC가 발생한다. GC가 발생한 이후, 살아남은 객체는 Survivor 영역 중 하나로 이동한다.
 9 | - 이 과정을 반복하다가 계속해서 살아남은 객체는 일정 시간 참조되고 있다는 뜻이므로 Old 영역으로 이동한다.
10 | 
11 | 
12 | 
13 | ### [Major GC]
14 | 
15 | - Old 영역에 있는 모든 객체들을 검사하여 참조되고 있지 않은 객체들을 한꺼번에 삭제한다. 
16 | - 시간이 오래 걸리고 실행 중 프로세스가 정지된다. 이것은 'Stop-the-World'라고 하는데, Major GC가 발생하면 GC를 실행하는 스레드를 제외한 나머지 스레드는 모두 작업을 멈춘다. GC 작업을 완료한 이후에야 중단했던 작업을 다시 시작한다.
17 | - GC의 튜닝은 이 'Stop-the-World'의 시간을 줄이는 것이다. 
18 | 
19 | 
20 | 
21 | ### [GC는 어떤 원리로 소멸시킬 대상을 선정하는가?]
22 | 
23 | - 알고리즘에 따라 동작 방식이 매우 다양하지만 공통적인 원리가 있다. 
24 | - Garbage Collector는 힙 내의 객체 중에서 가비지를 찾아내고 찾아낸 가비지를 처리해서 힙의 메모리를 회수한다. 
25 | - **참조되고 있지 않은 객체를 가비지**라고 하며, 객체가 가비지인지 아닌지 판단하기 위해서 `Reachability`라는 개념을 사용한다.
26 | - 어떤 힙 영역에 할당된 객체가 유효한 참조가 있으면 Reachability
27 | - 없다면  UnReachability로 판단한다.
28 | - 하나의 객체는 다른 객체를 참조하고 다른 객체는 또 다른 객체를 참조할 수 있기 때문에 참조 사슬이 형성된다. 이 참조 사슬 중 최초에 참조한 것을 Root Set이라고 한다. 
29 | - 힙 영역에 있는 객체들을 총 4가지 경우에 대한 참조를 하게 된다. 
30 | 
31 | <img src = "https://user-images.githubusercontent.com/33534771/83470789-0605b400-a4be-11ea-84e6-6044596242d3.png" />
32 | 
33 | 
34 | 유효한 최초의 참조가 이루어지지 않은 객체들은 Unreachable Objects로 판단하며, GC에 의해 수거된다. 
35 | 
36 | 
37 | 
38 | 인스턴스가 가비지 컬렉션의 대상이 되었다고 해서 바로 소멸이 되는 것은 아니다. 빈번한 가비지 컬렉션의 실행은 시스템에 부담이 될 수 있기 때문이다. 그래서 성능에 영향을 미치지 않도록 가비지 컬렉션 실행 타이밍은 별도의 알고리즘을 기반으로 계산이 되며, 이 계산 결과를 바탕으로 GC가 수행된다.
39 | 
40 | 
41 | 
42 | 참고할 만한 블로그
43 | 
44 | - [네이버 D2 블로그](https://d2.naver.com/helloworld/329631)
45 | - [Jungwoon Blog](https://jungwoon.github.io/java,%20gc/2019/07/27/Garbage-Collection.html)
46 | 
47 | 


--------------------------------------------------------------------------------
/Java/[Java] JVM.md:
--------------------------------------------------------------------------------
  1 | ## JVM(Java Virtual Machine)
  2 | 
  3 | - 스택 기반의 가상 머신.
  4 | - JVM의 역할은 자바 애플리케이션을 클래스 로더를 통해 읽어들여 자바 API와 함께 실행하는 것이다.
  5 | - Java와 OS 사이에서 중개자 역할을 수행하여 Java가 OS에 구애받지 않고 재사용 가능하게 해준다.
  6 | - 메모리 관리, Garbage Collection(GC를 통해 자원을 관리)을 수행한다.
  7 | - 자바 바이트 코드를 실행할 수 있는 주체이다.
  8 | 
  9 | 
 10 | 
 11 | **[JVM을 알야아 하는 이유는 뭘까?]**
 12 | 
 13 | -> 한정된 메모리를 효율적으로 사용하여 최고의 성능을 내기 위해서라 할 수 있다. 동일한 기능의 프로그램이더라도 메모리 관리에 따라서 성능이 좌우되기 때문에 JVM이 하는 역할을 이해하고 메모리를 효율적으로 사용하여 최고의 성능을 낼 수 있을 것이다.
 14 | 
 15 | 
 16 | 
 17 | **[자바 프로그램 실행 과정]**
 18 | 
 19 | 1. 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다.
 20 |    JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.
 21 | 2. 자바 컴파일러(javac)가 자바 소스 코드를 읽어들여 자바 바이트 코드(.class)로 변환시킨다.
 22 | 3. Class Loader를 통해 class 파일들을 JVM으로 로딩한다. 
 23 | 4. 로딩된 class 파일들은 Execution Engine을 통해 해석된다.
 24 | 5. 해석된 바이트 코드는 Runtime Data Area에 배치되어 실질적인 수행이 이루어지게 된다. 
 25 |    이러한 실행 과정 속에서 JVM은 필요에 따라 Thread Synchronization과 GC 같은 관리 작업을 수행한다.
 26 | 
 27 | 
 28 | <img src = "https://user-images.githubusercontent.com/33534771/83471568-f7200100-a4bf-11ea-810f-3ea08018317f.png" width="70%" />
 29 | 
 30 | 
 31 | ### 각각의 역할
 32 | 
 33 | 
 34 | 
 35 | **[Class Loader(클래스 로더)]**
 36 | 
 37 | - Runtim시에 JVM내로 클래스(.class 파일)를 로드하고 링크를 통해 배치하는 작업을 수행한다. (Runtime : 클래스를 처음으로 참조할 때.)
 38 | - 사용하지 않는 클래스들은 메모리에서 삭제한다.
 39 | - 동적 로드를 담당한다.
 40 | 
 41 | 
 42 | 
 43 | **[Execution Engine(실행 엔진)]**
 44 | 
 45 | - 클래스를 실행시키는 역할이다.
 46 | - 클래스 로더가 JVM 내의 Runtime Data Area에 바이트 코드를 배치시키고 이것은 실행 엔진에 의해서 실행된다.
 47 | - 자바 바이트 코드는 비교적 인간이 보기 편한 형태로 기술된 것이다. 그래서 실행 엔진은 이와 같은 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경한다. 
 48 | - 실행 엔진은 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.
 49 | - 2가지 방식이 존재한다.
 50 |   - 최초의 JVM은 인터프리터 방식이었기 때문에 속도가 느린 단점이 존재했지만, JIT 컴파일러 방식을 통해 이 점을 보완했다. 
 51 | 
 52 | 1) Interpreter(인터프리터)
 53 | 
 54 | - 자바 바이트 코드를 명령어 단위로 읽어서 실행한다.
 55 | - 한 줄씩 실행하기 때문에 느리다.
 56 | 
 57 | 2) JIT(Just-In-Time) Compiler
 58 | 
 59 | - 인터프리터 방식의 단점을 보완하기 위해 등장했다.
 60 | - 인터프리터 방식으로 실행하다가 적절한 시점에 바이트 코드 전체를 컴파일하여 네이티브 코드로 변경하고 이후에는 더 이상 인터프리팅하지 않고 네이티브 코드로 직접 실행하는 방식이다.
 61 | - 네이티브 코드는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행된다.
 62 | - 한 번만 실행되는 코드라면 JIT 컴파일러가 컴파일하는 게 인터프리팅하는 것보다 오래 걸리므로 인터프리팅하는 것이 유리하다.
 63 | - 이처럼 해당 메소드가 얼마나 자주 수행되는지 체크하고 일정 정도를 넘을 때만 컴파일을 수행하는 게 좋다. 
 64 | 
 65 | 
 66 | 
 67 | **[Garbage Collector]**
 68 | 
 69 | - GC를 수행하는 모듈이 존재한다.
 70 | 
 71 | 
 72 | 
 73 | **[Runtime Data Area]**
 74 | 
 75 | - JVM이 프로그램을 수행하기 위해 OS로부터 할당받은 메모리 공간이다.
 76 | - 이 공간은 용도에 따라 여러 영역으로 나누어 관리한다.
 77 | 
 78 | <img src = "https://user-images.githubusercontent.com/33534771/83472428-2fc0da00-a4c2-11ea-90a9-dac474fada4b.png" width ="70%"/>
 79 | 
 80 | 
 81 | 1. PC Register
 82 | 
 83 |    - Thread가 시작될 때, 각각의 Thread 별로 생성되는 공간으로 현재 수행 중인 JVM 명령어 주소를 가지게 된다.
 84 | 
 85 | 2. JVM 스택 영역
 86 | 
 87 |    - 프로그램의 실행 과정에서 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다.
 88 |    - 메소드의 매개변수, 지역 변수 등 메소드의 정보를 저장한다.
 89 | 
 90 | 3. Natvie Method Stack
 91 | 
 92 |    - Java외의 언어로 작성된 네이티브 코드를 위한 영역이다.
 93 |    - 자바 프로그램이 컴파일 되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역이다. 
 94 | 
 95 | 4. Method Area(Class Area, Static Area)
 96 | 
 97 |    - 클래스 정보를 처음 메모리 공간에 올릴 때, 초기화 되는 대상을 저장하기 위한 메모리 공간.
 98 |    - 모든 쓰레드가 **공유하는 메모리 영역**이다. 클래스, 인터페이스, 메소드, 필드, Static 변수 등의 바이트 코드를 보관한다.
 99 |    - Runtime Constant Pool이라는 것이 존재하며, 이는 별도의 관리 영역으로 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다. (각 클래스와 인터페이스의 상수, 메소드와 필드에 대한 모든 레퍼런스를 담고 있는 테이블이다.)
100 |    - Java 7부터 String Constant Pool은 Heap 영역으로 변경되어 GC의 관리 대상이 되었다.
101 | 
102 | 5. Heap(힙 영역)
103 | 
104 |    - **객체**를 저장하는 가상 메모리 공간이다.
105 |    - 런타임시 동적으로 할당하여 사용하는 영역.
106 |    - `new` 연산자로 **생성된 객체와 배열을 저장**한다.
107 |    - 클래스 영역에 올라온 클래스들로만 객체로 생성할 수 있으며, 세 부분으로 나눌 수 있다.
108 |    - **GC의 관리 대상에 포함된다.**
109 | 
110 | <img src = "https://user-images.githubusercontent.com/33534771/83472881-3f8cee00-a4c3-11ea-942c-9b7aa0f4ea04.png" width = "70%" />
111 | 
112 | 
113 | - New/Young 영역
114 |   - Eden : 객체들이 최초로 생성되는 공간.
115 |   - Survivor 0/1 : Eden에서 참조되는 객체들이 저장되는 공간. 
116 | 
117 | - Old 영역
118 |   - New 영역에서 일정 시간 참조되고 살아남은 객체들이 저장되는 공간이다.
119 |   - Eden 영역에서 인스턴스가 가득차게 되면 첫 번째 GC가 발생한다. (minor GC)
120 |   - Eden 영역에 있는 값들을 Survivor 1 영역에 복사하고, 이 영역을 제외한 나머지 영역의 객체를 삭제한다.
121 |   - Eden 영역에서 GC가 한 번 발생한 후 살아남은 객체는 Survivor 영역으로 이동한다. 이 과정을 반복하다가 살아남은 객체는 Old 영역으로 이동된다. 
122 | <!--  - 여기서 일어나는 GC도 Major GC에 포함된다.-->
123 |   
124 | - Permanent Generation
125 |   - 생성된 객체들의 주소값이 저장되는 공간이다.
126 |   - 리플렉션을 사용하여 동적으로 클래스가 로딩되는 경우 사용된다.
127 |   - Old 영역에서 살아남은 객체가 영원히 남아있는 곳이 아니다. 
128 |   - 이 영역에서 발생하는 GC는 Major GC의 횟수에 포함된다.
129 | 


--------------------------------------------------------------------------------
/Java/[Java] Java에서 Thread.md:
--------------------------------------------------------------------------------
  1 | ## Java에서 Thread
  2 | 
  3 | 먼저, 멀티 태스킹이 무엇인지 알 필요가 있다. 
  4 | 
  5 | 최근의 OS는 멀티 태스킹을 지원하지 않는게 없다. 
  6 | 
  7 | 멀티 태스킹은 두 가지 이상의 작업을 동시에 하는 것을 말한다. 
  8 | 
  9 | 예를 들어, 컴퓨터로 음악을 들으며, 웹서핑을 하는 것이다.
 10 | 
 11 | 
 12 | 
 13 | 실제로 동시에 처리될 수 있는 프로세스의 개수는 CPU 코어의 개수와 동일한데, 이보다 많은 개수의 프로세스가 존재하기 때문에 모두 함께 동시에 처리될 수는 없다. 
 14 | 
 15 | 각 코어들은 아주 짧은 시간 동안 여러 프로세스를 번갈아가며 처리하는 방식을 통해 동시에 동작하는 것처럼 보이게 할 뿐이다.
 16 | 
 17 | 이와 마찬가지로, 멀티 스레딩에 대해 간단히만 알아보자. 
 18 | 
 19 | 멀티 스레딩은 하나의 프로세스 안에서 여러 개의 스레드가 동시에 작업을 수행하는 것을 말한다. 
 20 | 
 21 | - 스레드 : 하나의 작업 단위.
 22 | 
 23 | 
 24 | 
 25 | ### 스레드 구현 방법
 26 | 
 27 | 자바에서 쓰레드를 구현하는 방법은 2가지가 있다. 
 28 | 
 29 | 1. Runnable 인터페이스 구현
 30 | 2. Thread 클래스 상속
 31 | 
 32 | 두 방식 모두 run() 메소드를 오버라이딩 한다.
 33 | 
 34 | 
 35 | 
 36 | [Runnable 인터페이스 구현]
 37 | 
 38 | ```java
 39 | public class MyThread implements Runnable {
 40 |   @Override
 41 |   public void run(){
 42 |     // 수행 코드.
 43 |   }
 44 | }
 45 | ```
 46 | 
 47 | - Runnable 인터페이스를 구현하므로 다른 클래스를 상속받을 수 있다.
 48 | - run() 메소드를 오버라이드 하면 된다.
 49 | - 다만, start() 메소드가 없기 때문에 Runnable 인터페이스를 구현한 클래스의 객체를 만들어 Thread를 생성할 때, 생성자의 매개변수로 넘겨주고 쓰레드 객체의 start() 메소드를 수행한다.
 50 | 
 51 | 
 52 | 
 53 | ```java
 54 | public static void main(String[] args){
 55 |   Runnable runnable = new MyThread();
 56 |   Thread t = new Thread(runnable, "mythread");
 57 | }
 58 | ```
 59 | 
 60 | 
 61 | 
 62 | [Thread 클래스 구현]
 63 | 
 64 | ```java
 65 | public class MyThread extends Thread {
 66 | 
 67 |   public void run(){
 68 |     // 수행 코드.
 69 |   }
 70 | }
 71 | ```
 72 | 
 73 | - Thread 클래스를 상속받으면 다른 클래스를 상속받지 못한다.(다중 상속 불가능 - 자바의 특징)
 74 | - run() 메소드를 직접 구현해야 한다.
 75 | - 또한, Thread 클래스를 상속받으면 스레드 클래스의 메소드를 바로 사용할 수 있지만, Runnable 구현의 경우 Thread 클래스의 static 메소드인 currentThread()를 호출해 현재 스레드에 대한 참조를 얻어와야만 호출이 가능하다.
 76 | 
 77 | 
 78 | 
 79 | ### 스레드의 실행
 80 | 
 81 | >  스레드의 실행은 run() 호출이 아닌 start() 호출로 해야 한다.
 82 | 
 83 | 
 84 | 
 85 | [왜?]
 86 | 
 87 | 위에서 우리가 정의했던 메소드는 run()이다. 하지만, 실제로 스레드에게 작업을 시키려면 start()로 작업해야 한다고 한다. run() 메소드로 작업 지시를 하면 스레드가 일을 할까? 그렇지 않다. 두 메소드 모두 같은 작업을 한다. **하지만 run() 메소드를 사용한다면, 이건 스레드를 사용하는 것이 아니다.**
 88 | 
 89 | 
 90 | 
 91 | Java에는 Call Stack이라는 것이 있다. 이 영역이 실질적인 명령어들을 담고 있는 메모리로, 하나씩 꺼내서 실행시키는 역할을 한다. 
 92 | 
 93 | 만약 동시에 두 가지 작업을 한다면, 두 개 이상의 콜 스택이 필요하게 된다. **스레드를 이용한다는 건, JVM이 다수의 콜 스택을 번갈아가며 일처리를 하고 사용자에게는 동시에 작업을 하는 것처럼 보여주는 것이다.**
 94 | 
 95 | 즉, run() 메소드를 이용한다는 것은 main()의 콜 스택 하나만 이용하는 것으로 스레드 활용이 아니다. (그냥 스레드 객체의 run이라는 메소드를 호출하는 것 뿐이게 된다.)
 96 | 
 97 | start() 메소드를 호출하면 JVM은 알아서 스레드를 위한 콜 스택을 새롭게 만들어주고 context switching을 통해 스레드답게 동작하도록 해준다.
 98 | 
 99 | 결국, 우리는 새로운 콜 스택을 만들어 작업을 해야 스레드 일처리가 되는 것이기 때문에 start() 메소드를 써야 하는 것이다.
100 | 
101 | 
102 | 
103 | **start()는 스레드가 작업을 실행하는 데 필요한 콜 스택을 생성한 다음 run()을 호출해서 그 스택 안에 run()을 저장할 수 있도록 해준다.**
104 | 
105 | 
106 | 
107 | ### 스레드의 실행 제어
108 | 
109 | 스레드는 다음과 같이 5가지의 상태를 가지고 있다.
110 | 
111 | 1. NEW : 스레드가 생성되고 아직 start()가 호출되지 않은 상태
112 | 2. RUNNABLE : 실행 중 또는 실행 가능 상태
113 | 3. BLOCKED : 동기화 블록에 의해 일시정지된 상태(lock이 풀릴 때까지 기다림)
114 | 4. WAITING, TIME_WAITING : 실행 가능하지 않은 일시정지 상태
115 | 5. TERMINATED : 스레드 작업이 종료된 상태
116 | 
117 | 
118 | 
119 | 스레드를 사용하는 것이 효율적이라 하지만, 어렵다. 
120 | 
121 | 이유는 위와 같이 다양한 상태를 가지고 있으며, 이를 잘 사용하기 위해선 동기화와 스케줄링이 필요하기 때문이다. 
122 | 
123 | - 스케줄링과 관련된 메소드 : sleep(), join(), yield(), interrupt()
124 | - start() 이후에 join()을 해주면 main 스레드가 모두 종료될 때까지 기다려주는 일도 해준다.
125 | 
126 | 
127 | 
128 | 이와 관련된 내용들은 깊은 내용이며, 운영체제와 연관성이 높다고 판단되어 운영체제 쪽에서 다룰 예정이다.
129 | 


--------------------------------------------------------------------------------
/Java/[Java] Java의 String.md:
--------------------------------------------------------------------------------
 1 | ## Java의 String에 관해서
 2 | 
 3 | Java에서 String은 굉장히 자주 사용되며, 두 가지 생성 방식이 있다.
 4 | 
 5 | 1. new 연산자를 이용한 방식
 6 | 2. 리터럴을 이용한 방식
 7 | 
 8 | 이 두 가지 방식에는 큰 차이점이 존재한다.
 9 | 
10 | new를 통해 String 객체를 생성하면 **Heap** 영역에 존재하게 된다.
11 | 
12 | 리터럴을 이용할 경우, **String Constant Pool**이라는 영역에 존재하게 된다.
13 | 
14 | 
15 | 
16 | ```java
17 | public class StringMemory{
18 |   public static void main(String[] args){
19 |     String literal = "loper";
20 |     String object = new String("loper");
21 |     
22 |     literal == object; // false
23 |     literal.equals(object); // true
24 |   }
25 | }
26 | ```
27 | 
28 | - `==` 연산의 결과는 false이다. == 연산자는 객체의 주소값을 비교하기 때문에 일반 객체처럼 Heap 영역에 생성된 String 객체와 리터럴을 이용해 String Constant Pool에 저장된 String 객체의 주소값은 다를 수 밖에 없다.
29 | - `equals()` 메소드의 수행 결과는 true이다. 이는 문자열 내용을 비교하기 때문에 같은 문자열에 대해서 true를 반환하는 것이 맞다.
30 | 
31 | 
32 | 
33 | ### 왜 이런 결과가 나올까?
34 | 
35 | 이를 위해서는 동작 방식에 대한 이해가 필요하다. String을 리터럴로 선언할 경우, 내부적으로 String의 `intern()`이라는 메소드가 호출되게 된다.
36 | 
37 | - `intern()` : 주어진 문자열이 **String Constant Pool**에 존재하는지 검색하고 있다면 그 주소값을 반환하고 없다면 **String Constant Pool**에 넣고 새로운 주소값을 반환하게 된다.
38 | 
39 | 
40 | 
41 | ```java
42 | public class StringMemoryInternTest{
43 |   public static void main(Strig[] args){
44 |     String literal = "loper";
45 |     String object = new String("loper");
46 |     String intern = object.intern(); // 명시적으로 호출. 
47 |     
48 |     literal == object; // false
49 |     literal.equals(object); // true
50 |     
51 |     literal == intern; // true
52 |     literal.equals(intern); // true
53 |   }
54 | }
55 | ```
56 | 
57 | 
58 | 
59 | 기존에 `new`를 통해 생성된 **String** 객체와 리터럴로 생성된 **String** 객체를 `==` 연산하였을 경우, **false**를 반환했지만 `new`를 통해 생성된 **String** 객체의 `intern()` 메소드를 호출하여 새로운 String 객체인 intern에 대입할 경우, 리터럴로 생성된 String 객체와 `==` 연산시 **true**를 반환하게 된다.
60 | 
61 | 
62 | 
63 | 위에서 설명했듯이 리터럴로 "**loper**"라는 문자열이 **String Constant Pool**에 저장되었고, `intern()` 메소드를 호출하면서 **String Constant Pool**에 "**loper**"라는 문자열을 검색하게 되고 이미 저장된 "**loper**" 문자열을 발견할테니 동일한 주소값을 반환하게 되므로 **true가** 성립되는 것이다.
64 | 
65 | 
66 | 
67 | `String Constant Pool의 위치 변경`
68 | 
69 | Java 6까지 String Constant Pool의 위치는 Perm 영역이었다. Perm 영역에 위치했던게 Java 7에서 Heap 영역으로 변경되었다. 그 이유는 OOM(Out Of Memory) 때문이다.
70 | 
71 | 
72 | 
73 | Perm 영역은 고정된 사이즈이며 Runtime에 사이즈가 확장되지 않는다. Perm 영역의 사이즈를 늘릴수는 있지만 어쨌거나 Runtime에 사이즈가 변경되는 것은 아니다. 
74 | 
75 | 그래서 Java 6까지는 String의 intern() 메소드를 호출하는 것은 OOM을 발생시킬 수 있고 그 부분을 컨트롤할 수 없었기 때문에 거의 사용하지 않는 것이 맞다.
76 | 
77 | 
78 | 
79 | 그래서 Oracle의 엔지니어들이 Java 7에서 Perm 영역이 아닌 Heap 영역으로 String Constant Pool의 위치를 변경했다. Heap 영역으로 변경함으로써 얻는 이점은 무엇일까?
80 | 
81 | -> `바로 String Constant Pool의 모든 문자열도 GC의 대상이 될 수 있다는 점이다.`
82 | 
83 | 
84 | 
85 | String Constant Pool의 사이즈 또한 지정할 수 있는데, -xx:StringTableSize 옵션으로 설정이 가능하다. 여기에는 1,000,000과 같은 숫자가 아닌 1,000,003과 같은 소수를 사용해야 한다. 이는 hashCode 성능과 관련된 부분이며 [아티클](http://java-performance.info/hashcode-method-performance-tuning/)에 자세한 내용이 나와있다.
86 | 
87 | ++ 2020.09.19 추가
88 | [해당 블로그](https://inor.tistory.com/39)의 내용이 이해가 잘되어서 첨부하며, 추후에 추가하도록 하겠다.
89 | 


--------------------------------------------------------------------------------
/Java/[Java] Reflection.md:
--------------------------------------------------------------------------------
 1 | ## Reflection
 2 | 
 3 | - 자바에서 이미 로딩이 완료된 클래스에서 또는 다른 클래스를 동적으로 로딩하여 구체적인 타입을 알지 못하더라도 생성자, 멤버 필드, 그리고 멤버 메소드를 사용할 수 있는 기법이다. 
 4 | - 객체를 통해서 클래스의 패키지 정보, 접근 지정자, 부모 클래스, 어노테이션 등을 얻을 수 있다. 
 5 | - 즉, 핵심은 컴파일 타임이 아니라 **런타임에 동적**으로 특정 클래스의 정보를 객체화하여 분석 및 추출해낼 수 있는 프로그래밍 기법이다. 
 6 | 
 7 | 
 8 | 
 9 | ### [사용하는 이유는?]
10 | 
11 | - 실행 시간(Runtime)에 다른 클래스를 동적으로 로딩하여 접근할 필요가 있을 때.
12 | - 클래스와 멤버 필드 그리고 메소드 등에 관한 정보를 얻어야할 때.
13 | - 리플렉션 없이도 완성도 높은 코드를 구현할 수 있지만, 사용한다면 조금 더 유연한 코드를 만들 수 있다. 
14 | 
15 | 
16 | 
17 | ### [주의할 점]
18 | 
19 | - 외부에 공개되지 않는 private 멤버도 Field.setAccessibile() 메소드를 통해 true로 지정하면 접근과 조작이 가능하기 때문에 주의해서 사용해야 한다. 
20 | - Reflection에는 동적으로 해석되는 유형이 포함되므로 특정 JVM 최적화를 수행할 수 없다. 따라서 Reflection 작업이 비 Reflection 작업보다 성능이 떨어지며, 성능에 민감한 애플리케이션에서 자주 호출되는 코드엔 사용하지 않아야 한다. 
21 | 


--------------------------------------------------------------------------------
/Java/[Java] String,StringBuilder,StringBuffer 차이.md:
--------------------------------------------------------------------------------
 1 | ## String, StringBuilder, StringBuffer 차이
 2 | 
 3 | 
 4 | 
 5 | **[String]**
 6 | 
 7 | - Immutable하기 때문에 + 등 concat 연산 시 원본을 변경하지 않고 새로운 String 객체를 생성한다. 이로 인해 메모리 공간의 낭비가 발생하고 성능이 떨어진다.
 8 | - JDK 1.5 이후부터는 컴파일 타임에 StringBuilder로 변경한다고 한다.
 9 | - 불변 객체이기 때문에 멀티 쓰레드 환경에서 동기화를 신경쓰지 않아도 된다.
10 | - 문자열 연산이 적고, 조회가 많은 상황에서 쓰기 좋다.
11 | 
12 | 
13 | 
14 | **[StringBuilder, StringBuffer]**
15 | 
16 | - 공통점
17 |   - String과 다르게 Mutable한 객체이다.
18 |   - 따라서 문자열 연산 시 새롭게 객체를 생성하지 않고, 처음에 만든 객체를 이용해 연산하고 크기를 변경시켜 문자열을 변경한다.
19 |   - 따라서 문자열 연산이 자주 발생하는 상황에서 성능적으로 유리하며 쓰기 좋다.
20 | - 차이점
21 |   - StringBuilder : Thread-Safe 하지 않다. 멀티 쓰레드 지원하지 않음.
22 |   - StringBuffer : Thread-Safe 하다. 멀티 쓰레드 지원함.
23 |   - 즉, 동기화 지원의 유무.
24 | 
25 | StringBuilder는 동기화를 고려하지 않는 상황에서 사용.(Thread를 사용하지 않는 상황.) 문자열 연산이 많은 싱글 쓰레드 환경. 
26 | 
27 | StringBuffer는 동기화가 필요한 멀티 쓰레드 환경에서 사용. 문자열 연산이 많은 **멀티 쓰레드 환경**.
28 | 


--------------------------------------------------------------------------------
/Java/[Java] Wrapper Class.md:
--------------------------------------------------------------------------------
 1 | ## Wrapper Class
 2 | 
 3 | 
 4 | 
 5 | 기본 자료형을 객체 타입의 자료형으로 변환이 필요할 때 주로 사용한다. 
 6 | 
 7 | 
 8 | 
 9 | - 사용 용도
10 |   - 객체로 저장해야 할 경우
11 |   - 매개변수로 객체가 요구될 경우(ex. 제네릭, Collection의 타입)
12 |   - 객체 간의 비교가 필요할 경우
13 |   - 제네릭이나 컬렉션에서 사용할 경우, 기본형을 쓸 수 없기 때문에 이를 Wrapping한 형태를 사용해야 한다. 
14 | 
15 | - 특징
16 |   - 산술 연산을 위한 클래스가 아니기 때문에 `Immutable`하다.(불변)
17 |   - 불변 객체이기 때문에 값에 대한 변경은 불가능하고 새로운 값(객체)의 할당이나 참조만 가능하다.
18 |   - Boxing : 기본 자료형 -> Wrapper Class
19 |   - UnBoxing : Wrapper Class -> 기본 자료형
20 |   - JDK 1.5부터 오토 박싱, 오토 언박싱을 지원한다.
21 |   - 언박싱 시 사용되는 메소드는 다음과 같은 형태를 갖는다.
22 |     - intValue : 객체 -> int 값으로 변환. 
23 | 
24 | 
25 | 
26 | 문자를 숫자로 바꾸거나, 숫자를 문자로 바꿀 때 두 가지 방식의 차이점이 존재한다.
27 | 
28 | [Code]
29 | 
30 | ```java
31 | // 문자열 -> 기본형
32 | int number1 = Integer.parseInt("100");
33 | 
34 | // 문자열 -> wrapper class
35 | Integer number2 = Integer.valueOf("100");
36 | ```
37 | 
38 | 
39 | 
40 | 위에서 언급했듯이, JDK 1.5부터 오토 박싱과 오토 언박싱이 지원되기 때문에 반환값이 기본형이든, wrapper class이든 차이가 없어졌다. 그래서 굳이 구별하지 않고 `valueOf()`를 사용해도 된다. 
41 | 
42 | 
43 | 
44 | 단, 성능을 비교하면 valueOf()가 조금 더 느리다고 한다. 
45 | 
46 | 


--------------------------------------------------------------------------------
/Java/[Java] equals() 메소드 동작 원리.md:
--------------------------------------------------------------------------------
 1 | ## equals() 메소드 동작 원리
 2 | 
 3 | `equals()`
 4 | 
 5 | - 비교를 위한 메소드이다. 
 6 | - Java에서는 대상의 내용 자체를 비교한다. 
 7 | - 그렇다면 두 문자열을 비교할 때, 어떤 원리로 비교할까?
 8 | - Ex) a = "Victory", b = "Victory"
 9 | 
10 | 
11 | 
12 | ```java
13 | public boolean equals()(Object anObject){
14 |   if(this == anObject) return true;
15 |   
16 |   if(anObject instanceof String){
17 |     String anotherString = (String) anObject;
18 |     int n = value.length;
19 |     if(n == anohterString.value.length){
20 |       char v1[] = value;
21 |       char v2[] = anotherString.value;
22 |       
23 |       int i = 0;
24 |       while(n-- !=0){
25 |         if(v1[i] != v2[i]) return false;
26 |         
27 |         i++;
28 |       }
29 |       return true;
30 |     }
31 |   }
32 |   return false;
33 | }
34 | ```
35 | 
36 | 
37 | 
38 | - 먼저, 같은 객체인지 비교한다. 같은 객체라면 같은 값을 가지고 있기 때문에 true를 반환하며, 아래 문장은 수행되지 않는다. 
39 | - 다음으로 인자로 들어온 Object가 String 타입인지 확인하고 조건을 만족하면 해당 객체를 String타입으로 형 변환을 한다. 
40 | - 그리고 char[] 배열로 변환한 뒤, 문자를 앞에서부터 하나씩 비교한다. 한 개의 문자라도 다르다면 false를 반환하고 모든 문자가 동일하다면 true를 반환한다. 
41 | - true -> 동일한 내용임을 의미. false -> 다른 내용임을 의미.


--------------------------------------------------------------------------------
/Java/[Java] final 키워드.md:
--------------------------------------------------------------------------------
 1 | ## final 키워드
 2 | 
 3 | 간단한 내용이지만, final 키워드가 클래스, 메소드, 변수 앞에 붙었을 때 각각의 의미에 대해서 정확히 정리하려 한다.
 4 | 
 5 | - final class
 6 |   - 다른 클래스가 상속받지 못한다.
 7 | - final method
 8 |   - 자식 클래스에서 상위 클래스의 final method를 오버라이드 하지 못한다.
 9 | - final variable
10 |   - 변하지 않는 상수 값이 되어 새롭게 값을 할당할 수 없는 변수가 된다.
11 | 
12 | 
13 | 
14 | 


--------------------------------------------------------------------------------
/Java/[Java] int와 short.md:
--------------------------------------------------------------------------------
 1 | ## int와 short
 2 | 
 3 | 두 가지 모두 정수형 타입이다. 그렇다면 어떤 차이가 있는지 알아보자.
 4 | 
 5 | 
 6 | - `char, short 형` : 이와 같은 정수 자료형 타입으로 표현하면 메모리 공간을 효율적으로 사용할수는 있으나 연산의 효율성은 떨어진다. 
 7 |   - size : 2byte(16bits)
 8 | - `int 형` : int형보다 작은 크기의 데이터를 가지고 연산을 진행할 경우, 그 데이터를 일단 int형으로 바꿔서 연산을 진행한다. 따라서 산술 연산시, 자료형을 int형으로 선언해야 중간에 불필요한 변환 과정을 거치지 않게 되어 연산 효율이 좋다. 
 9 |   - size : 4byte(32bits)
10 | 
11 | 


--------------------------------------------------------------------------------
/Java/[Java] non-static 멤버와 static 멤버의 차이.md:
--------------------------------------------------------------------------------
 1 | ## non-static 멤버와 static 멤버의 차이
 2 | 
 3 | - non-static 멤버
 4 |   - 공간적 특성 : 해당 멤버는 객체마다 별도로 존재한다.
 5 |     - 인스턴스 멤버라고 부른다.
 6 |   - 시간적 특성 : 객체 생성 시에 멤버가 생성된다.
 7 |     - 객체가 생성될 때, 멤버가 생성되므로 객체 생성 후에 멤버 사용이 가능.
 8 |     - 객체가 사라지면 해당 멤버도 사라진다.
 9 |   - 공유의 특성 : 공유되지 않는다.
10 |     - 멤버는 객체 내에 각각 독립된 공간을 유지하므로 공유되지 않는다.
11 | - static 멤버
12 |   - 공간적 특성 : 해당 멤버는 클래스 당 하나만 생성된다.
13 |     - 해당 멤버는 객체 내부가 아닌 별도의 공간에 생성된다.
14 |     - 클래스 멤버라고 부른다.
15 |   - 시간적 특성 : 클래스 로딩 시에 멤버가 생성된다.
16 |     - 객체가 생성되기 전에 이미 생성되므로 객체를 생성하지 않고도 사용 가능.
17 |     - 객체가 사라져도 해당 멤버가 사라지지 않는다.
18 |     - 해당 멤버는 프로그램이 종료될 때, 사라진다.
19 |   - 공유의 특성 : 동일한 클래스의 모든 객체들에 의해 공유된다. (하나의 클래스로부터 생성된 여러 객체가 공유한다.)
20 | 
21 | 


--------------------------------------------------------------------------------
/Java/[Java] 객체지향 프로그래밍 개념.md:
--------------------------------------------------------------------------------
 1 | ## 객체지향 프로그래밍
 2 | 
 3 | 객체 지향 프로그래밍은 OOP(Object Oriented Programming)이라고도 한다.
 4 | 
 5 | 프로그래밍에서 필요한 데이터를 추상화시켜 상태와 행위를 가진 객체를 만들고 그 객체들 간의 유기적인 상호작용을 통해 로직을 구성하는 프로그래밍 방법이다.
 6 | 
 7 | 
 8 | 
 9 | **[장점]**
10 | 
11 | - 코드의 재사용성이 높다.
12 |   - 누군가가 만든 클래스를 가져와 사용할 수 있고 상속을 통해 확장할 수도 있다.
13 | - 유지보수가 쉽다.
14 |   - 수정해야 할 부분이 클래스 내부에 멤버 변수 혹은 메소드로 존재하기 때문에 해당 부분만 수정하면 된다.
15 | - 대형 프로젝트에 적합하다.
16 |   - 클래스 단위로 모듈화시켜서 개발할 수 있으므로 업무 분담하기가 쉽다.
17 | 
18 | 
19 | 
20 | **[단점]**
21 | 
22 | - 처리 속도가 상대적으로 느리다.
23 | - 객체가 많으면 용량이 커질 수 있다.
24 | - 설계 시 많은 노력과 시간이 필요하다.
25 | 
26 | 
27 | 
28 | ## 객체 지향 프로그래밍의 특징
29 | 
30 | - 추상화
31 | 
32 | 불필요한 정보는 숨기고 필요한 정보만을 표현함으로써 공통의 속성이나 기능을 묶어 이름을 붙이는 것이다.
33 | 
34 | 
35 | 
36 | - 캡슐화
37 | 
38 | 속성과 기능을 정의하는 멤버 변수와 메소드를 클래스라는 캡슐에 넣는 것이다. 즉, 관련된 기능(메소드)과 속성(변수)을 한 곳에 모으고 분류하기 때문에 재활용이 원활하다.
39 | 
40 | 목적 : 코드를 수정 없이 재활용하는 것
41 | 
42 | 또한, 캡슐화를 통해 정보 은닉이 가능하다.
43 | 
44 | 
45 | 
46 | - 상속
47 | 
48 | 부모 클래스의 속성과 기능을 그대로 이어 받아 사용할 수 있게 하고 기능의 일부분을 변경해야 할 경우, 상속 받은 자식 클래스에서 해당 기능만 다시 수정(정의)하여 사용할 수 있게 하는 것이다.
49 | 
50 | 상속을 통해서 클래스를 작성하면 보다 적은 양의 코드로 새로운 클래스를 작성할 수 있다. 
51 | 
52 | 또한, 코드를 공통적으로 관리하여 코드 추가 및 변경이 용이하다.
53 | 
54 | 
55 | 
56 | - 다형성
57 | 
58 | 하나의 변수명, 함수명 등이 상황에 따라서 다른 의미로 해석될 수 있는 것이다.
59 | 
60 | 즉, 오버라이딩, 오버로딩이 가능하다.
61 | 
62 | 
63 | 
64 | ## 객체 지향 설계 원칙
65 | 
66 | 이와 관련된 내용은 심도 깊으나, 여기서는 간단하게 무엇을 의미하는지만 정리한다. 추후 추가 예정.
67 | 
68 | 1. SRP(Single Responsibility Principle) : 단일 책임 원칙
69 | 
70 | 클래스는 단 하나의 책임을 가져야 하며, 클래스를 변경하는 이유는 단 하나의 이유여야 한다.
71 | 
72 | 2. OCP(Open Closed Principle) : 개방 폐쇄 원칙
73 | 
74 | 확장에는 열려있고, 변경에는 닫혀있어야 한다.
75 | 
76 | 3. LSP(Liskov Substitution Principle) : 리스코프 치환 원칙
77 | 
78 | 상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다. 
79 | 
80 | 4. ISP(Interface Segregation Principle) : 인터페이스 분리 원칙
81 | 
82 | 인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리해야 한다.
83 | 
84 | 5. DIP(Dependency Inversion Principle) : 의존 역전 원칙
85 | 
86 | 고수준 모듈은 저수준 모듈의 구현에 의존해서는 안된다.
87 | 
88 | 
89 | 
90 | 


--------------------------------------------------------------------------------
/Java/[Java] 기본형과 참조형의 차이점.md:
--------------------------------------------------------------------------------
 1 | ## 기본형과 참조형의 차이점은?
 2 | 
 3 | 자바에서는 Primitive Type과 Reference Type이 있다. 이는 기본형과 참조형이라고 하며, 서로 조금은 다른 특징을 가지고 있다.
 4 | 
 5 | 
 6 | 
 7 | - 기본형(Primitive Type)
 8 |   - 변수에 값 자체를 저장하며, stack 영역에 생성된다.
 9 |   - 사용하기 전에 반드시 선언되어야 하며, 초기화를 하지 않으면 자료형에 맞는 기본 값이 들어간다.
10 |   - OS에 따라 자료의 길이가 변하지 않는다.
11 |   - 비객체 타입이며, Null 값을 가질 수 없다.
12 |   - 정수(byte, short, int, long), 실수(double, float), 문자(char), 논리(boolean)
13 | - 참조형(Reference Type)
14 |   - 기본형을 제외하면 참조형이라고 한다. 
15 |   - 메모리 상에서 객체가 존재하는 주소를 저장하며, heap 영역에 저장한다. 
16 |   - 클래스형, 인터페이스형, 배열형이 있다. 
17 | 
18 | 
19 | 
20 | 


--------------------------------------------------------------------------------
/Java/[Java] 변수의 종류와 메모리 구조.md:
--------------------------------------------------------------------------------
 1 | ## 전역, 지역, 클래스 변수를 자바의 메모리 구조와 관련해서 생각해보기
 2 | 
 3 | 
 4 | <img src="https://user-images.githubusercontent.com/33534771/74100794-00363c80-4b76-11ea-9616-2a819e6dcb4b.png" width="35%"/>
 5 | 
 6 | 
 7 | 1. 메소드 영역
 8 | 
 9 | - 클래스에 대한 정보와 함께 클래스 변수(static variable)가 저장되는 영역. (즉, Static 변수가 저장되는 영역)
10 | - JVM은 자바 프로그램에서 특정 클래스가 사용되면 해당 클래스의 클래스 파일(*.class)을 읽어들여, 클래스에 대한 정보를 메소드 영역에 저장한다. 
11 | 
12 | 2. 힙 영역
13 | 
14 | - 모든 인스턴스 변수(멤버 변수)가 저장되는 영역.
15 | - new 키워드를 사용해 인스턴스가 생성되면, 해당 인스턴스의 정보를 힙 영역에 저장한다. 
16 | - 힙 영역은 메모리의 낮은 주소 -> 높은 주소의 방향으로 할당된다.
17 | 
18 | 3. 스택 영역
19 | 
20 | - 메소드가 호출될 때, 메소드의 스택 프레임이 저장되는 영역.
21 | - 메소드 호출 시, 메소드 호출과 관계되는 매개변수와 지역 변수를 스택 영역에 저장한다. 
22 | - 스택 영역은 메소드의 호출과 함께 할당되며, 메소드의 호출이 완료되면 소멸한다.
23 | - 스택 영역에 저장되는 메소드의 호출 정보를 **스택 프레임**이라고 부른다.
24 | - 후입 선출의 구조를 갖고 있으며, 메모리의 높은 주소에서 낮은 주소의 방향으로 할당된다.
25 | 
26 | 
27 | 
28 | ### [선언 위치에 따른 변수의 종류]
29 | 
30 | - 클래스, 지역, 인스턴스 변수가 있으며 선언된 위치에 따라 종류가 결정된다.
31 | 
32 | ```java
33 | public class Test{
34 |   int iv; // 인스턴스 변수.
35 |   static int cv; // 클래스 변수.
36 |   
37 |   void print(){
38 |     int lv; // 지역 변수. 
39 |   }
40 | }
41 | ```
42 | 
43 | - iv, cv는 클래스 내부에 선언되어 있으므로 멤버 변수.
44 | - cv는 static으로 선언되었으니 클래스 변수이고, iv는 인스턴스 변수.
45 | - lv는 메소드 내에 선언되었으므로 지역 변수. 
46 | 
47 | 
48 | 
49 | 1. 인스턴스 변수
50 | 
51 | - 인스턴스가 생성될 때, 생성된다. 따라서 인스턴스 변수를 사용하기 전에 먼저 객체를 생성해야 한다.
52 | - 인스턴스 변수는 **독립적인 저장공간**을 가지므로 인스턴스 별로 다른 값을 가질 수 있다.
53 | - 따라서 각 인스턴스마다 고유의 값을 가져야 할 때는 인스턴스 변수로 선언한다.
54 | - `힙 영역`에 올라간다.
55 | 
56 | 2. 클래스 변수
57 | 
58 | - `static` 키워드가 붙은 변수이다. 
59 | - 클래스 변수는 **해당 클래스의 모든 인스턴스가 공통된 값을 공유**하게 된다.
60 | - 따라서 한 클래스의 모든 인스턴스가 공통적인 값을 가져야할 때, 클래스 변수로 선언한다. 
61 | - 클래스가 로딩될 때, 생성되어(그러므로 메모리에 딱 한번만 올라간다.) 종료될 때까지 유지되는 클래스 변수는 public을 붙이면 같은 프로그램 내에서 어디서든 접근 가능한 전역 변수가 된다.
62 | - 인스턴스 생성 없이 접근할 수 있으므로 **클래스이름.클래스변수** 를 통해 접근할 수 있다. 
63 | - `메소드 영역`에 올라가며, 주로 **공유의 목적**으로 사용한다.
64 | 
65 | 3. 지역 변수
66 | 
67 | - 메소드 내에 선언되며 메소드 내에서만 사용할 수 있는 변수이다.
68 | - 메소드가 실행될 때, 메모리를 할당받으며 메소드가 끝나면 소멸되어 사용할 수 없게 된다.
69 | - `스택 영역`에 올라간다.
70 | 


--------------------------------------------------------------------------------
/Java/[Java] 오버라이딩과 오버로딩.md:
--------------------------------------------------------------------------------
 1 | ## 오버라이딩 vs 오버로딩
 2 | 
 3 | 오버라이딩과 오버로딩은 자주 나오면서도 중요한 개념이다. 하지만, 그만큼 잘 까먹기 때문에 정리하고 넘어가려 한다.
 4 | 
 5 | 
 6 | 
 7 | - **오버라이딩** : 상위 클래스가 가지고 있는 메소드를 하위 클래스에서 재정의해서 사용하는 것을 의미한다.
 8 |   - 상속 시, 상위 클래스의 private 멤버를 제외한 모든 멤버를 상속받는다. 
 9 | - **오버로딩** : 같은 이름의 메소드를 여러 개 가지면서 매개변수의 타입과 개수를 다르게 하여 정의하는 것을 의미한다. 즉, 메소드의 시그니처를 다르게 하여 정의하는 것이다. 
10 | 
11 | 
12 | 
13 | | 구분           | 오버로딩  | 오버라이딩 |
14 | | -------------- | --------- | ---------- |
15 | | 메소드 이름    | 동일      | 동일       |
16 | | 매개변수, 타입 | 다름      | 동일       |
17 | | 반환 타입      | 상관 없음 | 동일       |
18 | |                |           |            |
19 | 
20 | 


--------------------------------------------------------------------------------
/Java/[Java] 인터페이스.md:
--------------------------------------------------------------------------------
  1 | ## 인터페이스란?
  2 | 
  3 | - 인터페이스는 인터페이스를 구현하는 모든 클래스에 대해 특정한 메소드가 반드시 존재하도록 강제한다.
  4 | - 인터페이스의 목적은 구현 객체가 같은 동작을 한다는 것을 보장하는 것이다.
  5 | - 일종의 추상 클래스다. 하지만 추상 클래스보다 추상화 정도가 높아서 추상 메소드 이외의 일반 메소드나 멤버 변수를 구성원으로 가질 수 없다. 오직 추상 메소드와 상수만 멤버로 가질 수 있으며, 그 외의 요소는 허용하지 않는다.
  6 | 
  7 | 
  8 | 
  9 | 추상 클래스를 부분적으로만 완성된 미완성 설계도라고 한다면 인터페이스는 구현된 것이 아무것도 없는 기본 설계도라 할 수 있다. 
 10 | 
 11 | 
 12 | 
 13 | - 제약 사항
 14 |   - 모든 멤버 변수는 public static final 이어야 하며, 생략 가능.
 15 |   - 모든 메소드는 public abstract 이어야 하며, 생략 가능.
 16 |   - JDK 1.8부터 인터페이스에 static 메소드와 디폴트 메소드의 추가를 허용했다.
 17 | 
 18 | 
 19 | 
 20 | ```java
 21 | interface PlayCard {
 22 |   public static final int NUMBER = 4;
 23 |   
 24 |   final int DIAMOND = 3;
 25 |   static int HEART = 2;
 26 |   int CLOVER = 1;
 27 |   // 위의 상수는 모두 public static final이며, 생략된 형태이다.
 28 |   
 29 |   public abstract int getCardNumber();
 30 |   
 31 |   String getCardKind();
 32 |   
 33 |   // public 생략.
 34 |   default void getNewCard() {
 35 |     
 36 |   }
 37 |   
 38 |   // public 생략.
 39 |   static void staticMethod() {
 40 |     
 41 |   }
 42 | }
 43 | ```
 44 | 
 45 | 
 46 | 
 47 | ### [인터페이스의 상속]
 48 | 
 49 | - 인터페이스는 인터페이스로부터만 상속(extends) 받을 수 있다. 클래스와는 달리 다중 상속, 즉 여러 개의 인터페이스로부터 상속 받는 것이 가능하다.
 50 | - 클래스에서 여러 인터페이스를 다중 구현하는 것 또한 가능하다.
 51 | 
 52 | 
 53 | 
 54 | ### [인터페이스의 구현]
 55 | 
 56 | - 추상 클래스와 마찬가지로 자신이 직접 인스턴스를 생성할 수 없다. 따라서 인터페이스가 포함하고 있는 추상 메소드를 구현해 줄 클래스를 작성해야 한다.
 57 | - 상속은 클래스를 확장한다는 의미의 키워드인 extends를 사용하며, 인터페이스는 구현한다는 의미의 키워드인 implements를 사용한다.
 58 | 
 59 | 
 60 | 
 61 | ```java
 62 | interface Movable {
 63 |   void move(int x, int y);
 64 | }
 65 | 
 66 | interface Attackable {
 67 |   void attack(Unit n);
 68 | }
 69 | 
 70 | interface Fightable implements Movable, Attackable {
 71 |   
 72 | }
 73 | 
 74 | abstract class Fighter implements Fightable {
 75 |   public void move(int x, int y){
 76 |     ...
 77 |   }
 78 | }
 79 | ```
 80 | 
 81 | 
 82 | 
 83 | 만약 모든 추상 메소드의 구현을 원하지 않는다면 위의 코드처럼 Fighter 클래스를 abstract 키워드를 붙여 추상 클래스로 선언해야 한다.
 84 | 
 85 | 위에서는 move() 함수만을 구현했다. attack()을 구현하지 않았기 때문에 abstract Fighter인 추상 클래스로 선언을 했다.
 86 | 
 87 | 자바에서는 상속과 구현을 동시에 할 수 있다.
 88 | 
 89 | ```java
 90 | class Fighter extends Unit implements Fightable {
 91 |   public void move(int x, int y) { ... }
 92 |   public void attack(Unit u) { ... }
 93 | }
 94 | ```
 95 | 
 96 | 
 97 | 
 98 | ### [클래스를 이용한 다중 상속의 문제점]
 99 | 
100 | - 다중 상속이 된다고 가정했을 때, 아래의 코드를 확인해보자.
101 | 
102 | ```java
103 | class Animal {
104 |   public void cry(){
105 |     System.out.println("짖기!");
106 |   }
107 | }
108 | 
109 | class Cat extends Animal {
110 |   @Override
111 |   public void cry(){
112 |     System.out.println("냐옹냐옹!");
113 |   }
114 | }
115 | 
116 | class Dog extends Animal{
117 |   @Override
118 |   public void cry(){
119 |     System.out.println("멍멍!");
120 |   }
121 | }
122 | 
123 | class MyPet extends Cat, Dog { ... }
124 | // 1.
125 | 
126 | public class Test {
127 |   public static void main(String[] args){
128 |     MyPet pet = new MyPet();
129 |     pet.cry();
130 |     // 2.
131 |   }
132 | }
133 | ```
134 | 
135 | 
136 | 
137 | 다중 상속을 허용할 경우, 발생할 수 있는 문제는 **메소드 출처의 모호성**이다. 
138 | 
139 | 주석을 달아놓은 2에서 MyPet 클래스의 인스턴스인 pet이 cry() 메소드를 호출하면 이 메소드가 Dog 클래스의 cry() 메소드인지, Cat 클래스의 cry() 메소드인지 구분할 수 없는 모호성이 생긴다.
140 | 
141 | 이와 같은 이유로 자바에서 다중 상속을 지원하지 않는다.
142 | 
143 | 
144 | 
145 | 하지만, 인터페이스를 이용해 다중 구현을 하게되면 위와 같은 메소드 호출의 모호성을 방지할 수 있다.
146 | 
147 | ```java
148 | interface Animal {
149 |   void cry();
150 | }
151 | 
152 | interface Cat extends Animal {
153 |   void cry();
154 | }
155 | 
156 | interface Dog extends Animal {
157 |   void cry();
158 | }
159 | 
160 | class Pet implements Cat, Dog {
161 |   @Override
162 |   public void cry(){
163 |     System.out.println("멍멍~ 냐옹냐옹~")
164 |   }
165 | }
166 | 
167 | public class Test{
168 |   public static void main(String[] args){
169 |     Pet pet = new Pet();
170 |     pet.cry();
171 |   }
172 | }
173 | 
174 | // 결과
175 | 멍멍~ 냐옹냐옹~
176 | ```
177 | 
178 | 
179 | 
180 | Cat, Dog 인터페이스를 동시에 구현한 Pet 클래스에서만 cry() 메소드를 정의하므로, 앞의 예제에서 발생한 메소드 호출의 모호성이 없다. 
181 | 
182 | 
183 | 
184 | ### [인터페이스를 통한 다형성]
185 | 
186 | 자손 클래스의 인스턴스를 조상 타입의 참조 변수로 참조하는 것이 가능하다.
187 | 
188 | 인터페이스도 인터페이스를 구현한 클래스의 조상이라고 할 수 있으므로, 해당 인터페이스 타입의 참조 변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있다.
189 | 
190 | 
191 | 
192 | ### [장점]
193 | 
194 | 1. 대규모 프로젝트 개발 시 일관되고 정형화된 개발을 위한 표준화가 가능하다.
195 | 2. 클래스의 작성과 인터페이스의 구현을 동시에 진행할 수 있으므로, 개발 시간을 단축할 수 있다.
196 | 3. 클래스와 클래스 간의 관계를 인터페이스로 연결하면 클래스마다 독립적인 프로그래밍이 가능하다.


--------------------------------------------------------------------------------
/Java/[Java] 접근 제어 지시자.md:
--------------------------------------------------------------------------------
 1 | ## 접근 제어 지시자
 2 | 
 3 | 자바에서 기본적인 부분이지만, 실제로 사용할 때 의미를 파악하지 않고 남발하는 경우가 많아 정리하려 한다.
 4 | 
 5 | - public : public으로 선언된 멤버는 어떤 클래스에서라도 접근이 가능하다. public 메소드는 private 멤버와 프로그램 사이의 인터페이스 역할을 수행하기도 한다.
 6 | - protected : protected 멤버를 포함하는 클래스가 정의되어 있는 해당 패키지 내 그리고 해당 클래스를 상속 받은 외부 패키지의 자식 클래스에서 접근이 가능하다.
 7 | - private : private으로 선언된 멤버는 해당 멤버를 선언한 클래스에서만 접근이 가능하다. public 메소드를 이용한다면 해당 객체의 private 한 멤버에 접근이 가능하다.
 8 | - Default(package private) : 같은 클래스의 멤버와 해당 클래스가 정의되어 있는 패키지 내에서만 접근이 가능하다.
 9 | 
10 | 
11 | 
12 | ### 참고
13 | 
14 | 1) private의 경우
15 | 
16 | Private 멤버나 메소드를 가지고 있는 클래스를 A라고 하자.
17 | 
18 | 그리고 B라는 클래스가 A를 상속받는다. 이 경우, B 클래스는 private으로 선언된 멤버 혹은 메소드에 접근할 수 없다. 
19 | 
20 | 따라서 상속을 받더라도 private한 멤버에는 접근이 불가능 하다. 
21 | 
22 | 대신, public 메소드 통해 getter를 만들면 private 멤버를 사용할 수 있다.
23 | 
24 | 
25 | 
26 | 2) protected의 경우
27 | 
28 | Protected 멤버나 메소드를 가지고 있는 클래스를 A라고 하자.
29 | 
30 | 마찬가지로 B라는 클래스가 A를 상속받는다. 이 경우, B 클래스는 protected로 선언된 멤버 혹은 메소드에 접근이 가능하다. B 라는 클래스가 다른 패키지에 선언되었을지라도 A 클래스의 멤버에 접근이 가능하다. 
31 | 
32 | 하지만, 다른 패키지의 A 클래스를 상속받지 않은 클래스는 A 클래스의 멤버에 접근할 수 없다. 마치 private 처럼 말이다.
33 | 


--------------------------------------------------------------------------------
/Java/[Java] 직렬화.md:
--------------------------------------------------------------------------------
 1 | ## 직렬화
 2 | 
 3 | 자바에서 직렬화라는 기술이 있다. 이는 안드로이드에서도 종종 사용되는 기술인데, 이에 대해 알아보려 한다.
 4 | 
 5 | 
 6 | 
 7 | - 메모리 내에 존재하는 정보를 보다 쉽게 전송 및 전달하기 위해서 byte 코드 형태로 나열하는 것을 말한다. 이는 간단한 설명이다. 좀 더 자세히 알아보자. 
 8 | 
 9 | 
10 | 
11 | ### 직렬화가 무엇인가?
12 | 
13 | - 자바 직렬화란 자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터를 변환하는 기술과 바이트로 변환된 데이터를 다시 객체로 변환하는 기술(역직렬화)을 아울러서 이야기 한다.
14 | - 시스템적으로 이야기하면, JVM(Java Virtual Machine 이하 JVM)의 메모리에 상주(힙 또는 스택)되어 있는 객체 데이터를 바이트 형태로 변환하는 기술과 직렬화된 바이트 형태의 데이터를 객체로 변환해서 JVM으로 상주시키는 형태를 같이 이야기 한다.
15 | 
16 | 
17 | 
18 | 


--------------------------------------------------------------------------------
/Java/[Java] 추상 클래스.md:
--------------------------------------------------------------------------------
 1 | ## 추상 클래스란?
 2 | 
 3 | - 추상 클래스는 미완성된 클래스이다.
 4 | - 미완성된 클래스는 미완성된 메소드인 추상 메소드를 포함하고 있다.
 5 | - 추상 클래스는 혼자로는 클래스의 역할을 다 못하지만, 새로운 클래스를 작성하는 데 있어 **그 바탕이 되는 부모 클래스로서의 중요한 의미**를 갖는다. 왜냐하면 클래스를 작성함에 있어서 어느정도 작성된 상태에서 시작할 수 있기 때문이다. 
 6 | 
 7 | - 클래스 앞에 abstract 키워드를 붙인다. 
 8 | 
 9 | ```java
10 | abstract class Car {
11 |   abstract void accelrate();
12 | }
13 | ```
14 | 
15 | 
16 | 
17 | - abstract 키워드가 있는 클래스라고 모두 구현해야 하는 것은 아니다. 왜냐하면 단지 공유의 목적으로 abstract class를 만드는 경우도 있기 때문이다. 
18 | 
19 | 
20 | 
21 | ### [추상 클래스의 목적]
22 | 
23 | - 기존의 클래스에서 공통된 부분을 추상화하여 상속하는 클래스에게 구현을 강제화한다. 메소드의 동작은 구현하는 자식 클래스에게 위임한다.
24 | - 공유의 목적을 갖고 있다.
25 | 
26 | 
27 | 
28 | ### [추상 클래스의 특징]
29 | 
30 | - 추상 클래스는 추상 메소드가 아닌 일반 메소드, 멤버도 포함할 수 있다. 하지만 추상 메소드를 하나라도 포함하고 있다면 추상 클래스로 선언해야 한다. 
31 | 
32 | - 추상 클래스는 동작이 정의되어 있지 않은 추상 메소드를 포함하고 있으므로 인스턴스를 생성할 수 없다. 
33 | 
34 | 
35 | 
36 | ```java
37 | abstract class Animal {
38 |   abstract void cry();
39 | }
40 | 
41 | class Cat extends Animal {
42 |   @Override
43 |   void cry(){
44 |     System.out.println("냐옹냐옹 ~~!");
45 |   }
46 | }
47 | 
48 | class Dog extends Animal {
49 |   @Override
50 |   void cry(){
51 |     System.out.println("멍멍 ~~!");
52 |   }
53 | }
54 | 
55 | public class Test{
56 |   public static void main(String[] args){
57 |     // Animal animal = new Animal();
58 |     // 추상 클래스는 자체적으로 인스턴스를 생성할 수 없다. 불완전하기 때문에.
59 |     
60 |     Cat cat = new Cat();
61 |     Dog dog = new Dog();
62 |     
63 |     cat.cry();
64 |     dog.cry();
65 |     
66 |   }
67 | }
68 | ```
69 | 
70 | 
71 | 
72 | 추상 클래스인 Animal은 추상 메소드인 cry()를 가지고 있으며, Animal 클래스를 상속받는 자식 클래스인 Dog, Cat 클래스는 cry() 메소드를 오버라이딩해야만 인스턴스를 생성할 수 있다.
73 | 
74 | 
75 | 
76 | - 추상 메소드
77 |   - 선언부만 작성하고 구현부는 작성하지 않는 메소드이며, 앞에 abstract 키워드를 붙인다.
78 |   - 구현부를 작성하지 않는 이유는 메소드의 내용이 상속받은 클래스에 따라 달라질 수 있기 때문이다.
79 |   - 사용하는 목적은 추상 메소드를 포함한 클래스를 상속받는 자식 클래스가 반드시 추상 메소드를 구현하도록 강제하기 위함이다.
80 |   - 추상 클래스를 상속받은 자식 클래스는 오버라이딩을 통해 조상인 추상 클래스의 추상 메소드를 모두 구현해야 한다.
81 |   - 만약, 자식 클래스에서 추상 메소드를 하나라도 구현하지 않는다면 자식 클래스 역시 추상 클래스로 지정해야 한다.
82 | 
83 | 
84 | 
85 | 
86 | 
87 | 


--------------------------------------------------------------------------------
/Java/[Java] 추상 클래스와 인터페이스의 차이.md:
--------------------------------------------------------------------------------
 1 | ## 추상 클래스와 인터페이스의 차이점
 2 | 
 3 | - 인터페이스
 4 |   - 클래스가 아니며, 클래스와 관련이 없다.
 5 |   - 추상 메소드와 상수만을 멤버로 가진다.
 6 |   - 한 개의 클래스가 여러 인터페이스를 구현할 수 있다. (다중 구현 가능.)
 7 |   - Java 8부터 default 메소드가 추가되었다. 
 8 |     - default 키워드가 붙은 메소드는 구현할 수 있으며(일반 메소드처럼), 자식 클래스에서는 이를 오버라이딩할 수 있다.
 9 |     - 인터페이스가 변경되면 이를 구현하는 모든 클래스들이 해당 메소드를 다시 구현해야하는 번거로운 문제가 있었다. 이런 문제를 해결하기 위하여 인터페이스에 메소드를 구현할 수 있도록 변경되었다.
10 |   - Java 8부터 static 메소드가 추가되었다.
11 |     - 인터페이스에 static 메소드를 선언 가능하게 함으로써, 간단한 기능을 가지는 유틸리티성 인터페이스를 만들 수 있게 되었다. 
12 |   - 목적 : 구현 객체의 같은 동작을 보장하기 위해 사용한다.
13 | - 추상 클래스
14 |   - 클래스이며, 클래스와 관련이 있다. (주로 베이스 클래스로 사용)
15 |   - 추상 메소드 및 일반 메소드와 멤버도 포함할 수 있다.
16 |   - 한 개의 클래스가 여러 개의 클래스를 상속받을 수 없다. (다중 상속 불가능.)
17 |   - 상속을 받아 기능을 확장시키는 데 목적이 있다.
18 |   - 목적 : 기존의 클래스에서 공통된 부분을 추상화하여 상속하는 클래스에게 구현을 강제화한다. 메소드의 동작은 구현하는 자식 클래스로 위임한다. 
19 |   - **공유의 목적**.
20 | 
21 | 


--------------------------------------------------------------------------------
/Java/[Java] 클래스와 인스턴스.md:
--------------------------------------------------------------------------------
 1 | ## 클래스와 인스턴스
 2 | 
 3 | 기본적인 개념이지만, 간단하고 쉽게 이해할 수 있도록 정리하려 한다.
 4 | 
 5 | - 클래스
 6 | 
 7 | 어떤 문제를 해결하기 위한 데이터를 만들기 위해 추상화를 거쳐 집단에 속하는 속성과 행위를 변수와 메소드로 정의한 것이다.
 8 | 
 9 | 
10 | 
11 | - 인스턴스
12 | 
13 | 클래스에서 정의한 것을 토대로 실제 메모리 상에 할당된 것으로 실제 프로그램에서 사용되는 데이터를 말한다.
14 | 
15 | 
16 | 
17 | 인스턴스는 독립된 메모리 공간에 저장된 자신만의 필드를 가질 수 있다. 하지만 해당 클래스의 모든 메소드는 해당 클래스로부터 생성된 모든 인스턴스가 하나의 메소드를 공유하게 되는 특징을 갖고 있다. 


--------------------------------------------------------------------------------
/Java/값 타입과 참조 타입의 차이.md:
--------------------------------------------------------------------------------
 1 | ### 값 타입 vs 참조 타입
 2 | 
 3 | 가장 큰 차이점은 데이터가 저장되는 메모리 상의 위치이다.
 4 | 
 5 | 편의상 값 타입은 원시 타입(Primitive Type)이라고 부르겠다. 참조 타입(Reference Type)
 6 | 
 7 | - 원시 타입 : 크기가 작고 고정적이기 때문에 스택 영역에 저장된다.
 8 | - 참조 타입 : 크기가 크고 가변적이기 때문에 동적으로 관리되는 힙에 저장된다.
 9 | 
10 | 이처럼 저장되는 위치의 차이는 여러 차이점을 만든다. 
11 | 
12 | 
13 | 
14 | 1) 메모리 및 접근 속도
15 | 
16 | - 원시 타입
17 |   - 선언시 스택에 즉시 생성되므로 선언 직후부터 데이터를 저장하는 용도로 사용할 수 있다.
18 | - 참조 타입 
19 |   - 선언에 의해 참조만 생성될 뿐, 데이터를 저장할 수 있는 실제 메모리가 할당된 것은 아니다. 따라서 선언 즉시 사용할 수 없다. **반드시 new 연산자로 메모리를 할당받아 초기화해야 한다.** 
20 |   - '스택' 메모리에는 참조값만 존재하고 실제 값은 '힙' 메모리에 존재한다. **값을 필요로 할 때마다 언박싱 과정을 거쳐여 하므로 원시타입과 비교해서 접근 속도가 느려진다.**
21 | 
22 | > 예외적으로 엄청 큰 숫자를 복사해야 한다면, 참조값만 넘길 수 있는 참조 타입이 좋을 수도 있다.
23 | 
24 | 
25 | 
26 | ![img](https://k.kakaocdn.net/dn/uj0bm/btqvqfnwD5S/tKWdT5AKJDttoyuF5baZZK/img.gif)
27 | 
28 | <center>차지하는 메모리의 양</center>
29 | 
30 | Boolean의 경우에는 128배나 많은 메모리를 사용하게 된다. 
31 | 
32 | 2) 소멸 시점
33 | 
34 | - 원시 타입 : 변수를 선언한 메소드가 종료될 때 혹은 소속된 객체가 사라질 때, 소멸된다.
35 | - 참조 타입 : 더 이상 참조하는 변수가 없을 때 GC에 의해 제거된다.
36 | 
37 | 
38 | 
39 | 3) 복사
40 | 
41 | - 원시 타입 : 복사에 의해 별개의 복사본이 생성되며 복사 후 원본과 복사본은 별개의 변수이다. 완전히 다른 두 개의 변수가 생성되는 것이다.
42 | - 참조 타입 : 참조 타입끼리의 대입은 힙 영역에 존재하는 데이터를 참조하는 참조자가 하나 더 늘어날 뿐이다. 따라서 별도의 메모리가 추가로 할당되지 않는다. 그래서 둘 중 하나를 변경하면 다른 참조자는 같은 값을 참조하기 때문에 같이 변경된다. (해결하기 위해서는 Deep Copy 해야 한다.)
43 | 
44 | 
45 | 
46 | 4) Null 
47 | 
48 | - 원시 타입 : Null 값을 저장할 수 없다.
49 | - 참조 타입 : Null 값을 저장할 수 있다.
50 | 
51 | 
52 | 
53 | **결론**
54 | 
55 | 성능과 메모리에 장점이 있는 원시 타입을 먼저 고려해본다. 만약, Null을 다뤄야 하거나 제네릭 타입에서 사용되어야 한다면 참조 타입을 사용한다.
56 | 
57 | 
58 | 
59 | ### 참고
60 | 
61 | - [값타입, 참조타입 차이]([https://rsd885.tistory.com/entry/%EA%B0%92%ED%83%80%EC%9E%85-%EC%B0%B8%EC%A1%B0%ED%83%80%EC%9E%85-%EC%B0%A8%EC%9D%B4](https://rsd885.tistory.com/entry/값타입-참조타입-차이))
62 | - [Java에서 원시타입 vs 참조타입 어떤 걸 사용해야 할까?](https://siyoon210.tistory.com/139)
63 | 
64 | 


--------------------------------------------------------------------------------
/Kotlin/kotlin_functions.md:
--------------------------------------------------------------------------------
 1 | # 코틀린 함수들
 2 | 
 3 | ### Slice
 4 | 
 5 | - 배열을 어떤 특정 범위만큼 자른다.
 6 | - 자른 뒤, list를 반환한다.
 7 | - Usage
 8 | 
 9 | ```kotlin
10 | val arr = arrayOf(1,2,3,4,5)
11 | println(arr.slice(1..3))
12 | // 결과
13 | [2,3,4]
14 | ```
15 | 
16 | ### sorted
17 | 
18 | - 기본적으로 사용할 수 있는 정렬 함수다.
19 | - Collection에 대해서 사용한다.
20 | 
21 | ### sortedDescending
22 | 
23 | - 내림차순 정렬을 지원한다.
24 | - Collection에 대해서 사용한다.
25 | 
26 | ### sortedWith
27 | 
28 | - Comparator를 인자로 전달받아 사용자 정의 타입에 대해서 사용자가 정렬 기준을 정의할 수 있다.
29 | - compareBy()를 전달할 수 있다.
30 |     - 이때는 compareBy() 함수의 인자로 여러 개의 람다를 전달할 수 있다.
31 | - usage
32 | 
33 | 1) Comparator
34 | 
35 | ```kotlin
36 | private fun solution(strings: Array<String>, n: Int): Array<String> {
37 |         return strings.sortedWith(Comparator { o1, o2 ->
38 |             if (o1[n] == o2[n]) o1.compareTo(o2)
39 |             else o1[n] - o2[n]
40 |         }).toTypedArray()
41 |     }
42 | ```
43 | 
44 | 2) compareBy()
45 | 
46 | ```kotlin
47 | private fun solution2(strings: Array<String>, n: Int): Array<String> {
48 |         val result = strings.sortedWith(compareBy({ it[n] }, { it }))
49 |         println(result)
50 |         return result.toTypedArray()
51 |     }
52 | ```
53 | 
54 | - 첫 번째 인자로 전달받은 람다를 기준으로 정렬한다.
55 | - 첫 번째 람다로 정렬했을 때, 두 문자열이 동일하다면 두 번째 람다를 기준으로 정렬한다.
56 | 
57 | ### joinToString
58 | 
59 | - Collection에 대해서 사용할 수 있다.
60 | - list 내에 포함된 자료들을 사용자가 지정한 구분자와 함께 하나의 문자열로 표현할 수 있는 함수이다.
61 | - prefix, postfix 등 여러 인자를 사용하여 다양하게 활용할 수도 있다.
62 | - usage
63 | 
64 | ```kotlin
65 | val list = listOf("lee", "jung", "park")
66 | println(list) // [lee, jung, park]
67 | println(list.joinToString("")) // leejungpark
68 | println(list.joinToString(" - ")) // lee - jung - park
69 | ```
70 | 
71 | ### subList
72 | 
73 | - fromIndex ~ toIndex까지 list를 잘라서 반환한다.
74 | - fromIndex는 포함하고, toIndex는 포함하지 않는다.


--------------------------------------------------------------------------------
/Kotlin/범위 지정 함수.md:
--------------------------------------------------------------------------------
  1 | ## 범위 지정 함수
  2 | 
  3 | 코틀린에서 제공하는 여러 함수들 중 유용하게 사용할 수 있는 함수들이다.
  4 | 
  5 | **let()**
  6 | 
  7 | let()은 함수를 호출하는 객체를 이어지는 블록의 인자로 넘기고, 블록의 결과값을 반환한다.
  8 | 
  9 | ```kotlin
 10 | fun<T,R> T.let(block: (T) -> R): R
 11 | ```
 12 | 
 13 | - 사용 예
 14 | 
 15 | 함수를 호출한 객체를 인자로 받으므로, 이를 사용하여 다른 메소드를 실행하거나 연산을 수행해야 하는 경우 사용할 수 있다.
 16 | 
 17 | 커스텀 뷰에서 Padding 값을 지정할 때 일반적으로는 아래와 같이 코드를 작성한다.
 18 | 
 19 | ```kotlin
 20 | val padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
 21 | 16f, resources.displayMetrics).toInt()
 22 | 
 23 | setPadding(padding, 0, padding, 0)
 24 | ```
 25 | 
 26 | 위의 코드에서 padding이라는 상수 값은 한 번만 사용되고 더 이상 사용되지 않는다. 이런 경우, 다음과 같이 let()을 사용하면 불필요한 선언을 방지할 수 있다.
 27 | 
 28 | ```kotlin
 29 | TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
 30 | 16f, resources.displayMetrics).toInt().let{ padding->
 31 | 	setPadding(padding, 0, padding, 0)
 32 | }
 33 | ```
 34 | 
 35 | 계산된 값을 padding 이라는 이름의 인자로 받아서 let{..} 블록 안에서 값을 세팅한다.
 36 | 
 37 | 람다식의 인자가 한 개일 경우, 인자 이름을 생략하고 `it` 을 사용하여 코드를 간략하게 할 수 있다.
 38 | 
 39 | 또한, let()을 안전한 호출 ?. 연산자와 함께 사용하면 `if(null !=obj) ...` 를 대체할 수 있다. → 널 값에 대한 유효성 검사를 대신할 수 있다.
 40 | 
 41 | ```kotlin
 42 | var obj: String?
 43 | 
 44 | if(obj != null ) {
 45 | 	println("null이 아니에요~")
 46 | }
 47 | 
 48 | obj?.let {
 49 | 	println("null이 아니에요~")
 50 | }
 51 | ```
 52 | 
 53 | let()을 이용한 코드는 obj가 null이 아닐 경우 작업을 수행하는 코드이다.
 54 | 
 55 | **apply()**
 56 | 
 57 | apply()는 함수를 호출하는 객체를 이어지는 블록의 `리시버` 로 전달하고, 객체 자체를 반환한다.
 58 | 
 59 | - 리시버란? 바로 이어지는 블록 내에서 메소드 및 속성에 바로 접근할 수 있도록 할 객체를 의미한다.(접근 제어자에 따라 접근 가능한 범위에 한함.)
 60 | 
 61 |   fun <T> T.apply(block: T.() -> Unit): T
 62 | 
 63 | - 사용 예
 64 | 
 65 | 특정 객체를 생성하면서 함께 호출해야 하는 초기화 코드가 있는 경우 사용할 수 있다.
 66 | 
 67 | 새로운 LayoutParams 객체를 생성하고 속성을 지정하는 코드를 예로 들어보자. 여러 줄에 걸쳐 새로 선언한 변수 param을 사용하여 속성을 지정하고 있다.
 68 | 
 69 | ```kotlin
 70 | val param = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT)
 71 | param.gravity = Gravity.CENTER_HORIZONTAL
 72 | param.weight = 1f
 73 | param.topMargin = 100
 74 | param.bottomMargin = 100
 75 | ```
 76 | 
 77 | 위의 코드를 `apply()` 함수를 사용하면 이를 다음과 같이 바꿀 수 있다. param을 사용하지 않고 직접 속성을 지정할 수 있다.
 78 | 
 79 | ```kotlin
 80 | val param = LinearLayout.LayoutParams(0, LinearLayout.LayoutParams.WRAP_CONTENT).apply{
 81 | 	gravity = Gravity.CENTER_HORIZONTAL
 82 | 	weight = 1f
 83 | 	topMargin = 100
 84 | 	bottomMargin = 100
 85 | }
 86 | ```
 87 | 
 88 | **run()**
 89 | 
 90 | run() 함수는 인자가 없는 익명 함수처럼 동작하는 형태와 객체에서 호출하는 형태 두 가지가 있다. 객체 없이 run() 함수를 사용하면 인자 없는 익명 함수처럼 사용할 수 있다. 이어지는 블록 내에서 처리할 작업들을 넣어줄 수 있으며, 일반 함수와 마찬가지로 값을 반환하지 않거나(Unit) 특정 값을 반환할 수도 있다.
 91 | 
 92 | 인자가 없는 익명 함수처럼 사용하는 경우
 93 | 
 94 | - 어떤 값을 계산할 필요가 있거나 지역변수의 범위를 제한하기 위해 사용한다.
 95 | 
 96 |   fun <R> run(block: () -> R): R
 97 | 
 98 | 객체에서 run() 함수를 호출할 경우
 99 | 
100 | - 호출하는 객체를 이어지는 블록의 리시버로 전달하고, 블록의 결과값을 반환한다.
101 | 
102 |   fun <T,R> T.run(block: T.() -> R): R
103 | 
104 | - 사용 예
105 | 
106 | 객체에서 이 함수를 호출하는 경우 객체를 리시버로 전달받으므로, 특정 객체의 메소드나 필드를 연속적으로 호출하거나 값을 할당할 때 사용한다.
107 | 
108 | `apply()` 와 적용 예가 유사하지만, apply()는 새로운 객체를 생성함과 동시에 연속된 작업이 필요할 때 사용하고 `run()` 은 이미 생성된 객체에 연속된 작업이 필요할 때 사용한다는 점이 조금 다르다.
109 | 
110 | 다음은 AppCompatActivity의 액션바 속성을 연속하여 변경하는 예이다. `run()` 메소드에서도 **안전한 호출 ?.** 를 사용할 수 있으며, 이를 통해 액션바가 null이 아닐 경우에만 블록 내 명령들이 실행된다.
111 | 
112 | ```kotlin
113 | supportActionBar?.run{
114 | 	setDisplayHomeAsUpEnabled(true)
115 | 	setHomeAsUpIndicatore(R.drawable.ic_clear_white)
116 | }
117 | ```
118 | 
119 | **with()**
120 | 
121 | with() 함수는 인자로 받는 객체를 이어지는 블록의 리시버로 전달하며, 블록의 결과값을 반환한다.
122 | 
123 | ```kotlin
124 | fun <T,R> with(receiver: T, block: T.() -> R): R
125 | ```
126 | 
127 | with() 함수는 사실상 run() 함수와 기능이 거의 동일하며, 리시버로 전달할 객체가 어디에 위치하는지만 다르다.
128 | 
129 | `run()` 함수는 `with()` 함수를 좀 더 편리하게 사용하기 위해 `let()` 함수와 `with()` 함수를 합쳐놓은 형태라고 봐도 무방하다. 즉, run() 함수는 다음과 같이 표현할 수 있다.
130 | 
131 | ```kotlin
132 | supportActionBar?.let{
133 | 	with(it){
134 | 		setDisplayHomeAsUpEnabled(true)
135 | 		setHomeAsUpIndicator(R.drawable.ic_clear_white)
136 | 	}
137 | }
138 | ```
139 | 
140 | 이와 같이 기능은 똑같지만 `run()` 함수가 안전한 호출을 지원하는데 반해, `with()` 함수는 이를 자체적으로 지원하지 않으므로 특별한 경우가 아니라면 `run()` 함수를 더 자주 사용하게 될 것 같다.
141 | 


--------------------------------------------------------------------------------
/Kotlin/코틀린-간단한 개념.md:
--------------------------------------------------------------------------------
  1 | Kotlin의 특징을 정말 간단하고 보기 쉽게 정리하는 공간입니다.
  2 | 
  3 | 람다 표현식을 지원한다.
  4 | 
  5 | 스트림 API를 지원한다.
  6 | 
  7 | 자바와 완벽하게 호환된다.
  8 | 
  9 | # 간결한 문법
 10 | 
 11 | - 세미 콜론을 사용하지 않는다.
 12 | - new를 사용하지 않고 객체를 생성.
 13 | - 타입 추론을 지원한다.
 14 | - `var` : 수정 가능한 **변수**
 15 | - `val` : 수정 불가능한 **값**
 16 | - 반복문은 for-each문만 지원한다.
 17 | 
 18 | # 널 안전성
 19 | 
 20 | - 널 값의 허용 여부를 명확히 검사한다.
 21 | - **컴파일 단계**에서 검사한다.
 22 | 
 23 | ```kotlin
 24 | // 널 값 허용 
 25 | var a: String?=null 
 26 | // 널 값 허용 X 
 27 | var b: String = "b"
 28 | ```
 29 | 
 30 | 
 31 | 
 32 | 
 33 | 
 34 | # 기본 자료형
 35 | 
 36 | **타입 관련**
 37 | 
 38 | - 모든 타입을 **객체**로 표현. (원시 타입과 래퍼 클래스를 구분하지 X) 사실, 원시 타입을 모두 객체로 처리하면 비효율적이다. 코틀린은 코드를 작성하는 시점에 원시 타입과 래퍼를 구분하지 않지만, **컴파일 단계를 거치면서 가장 효율적인 타입으로 변환된다.**
 39 | - 값이나 변수의 타입으로 사용되는 경우 : 원시 타입으로 변환
 40 | - 컬렉션의 타입 인자로 사용되는 경우 : 래퍼로 변환
 41 | 
 42 | ```kotlin
 43 | var a: Int = 2 var b: List<Int> = ...
 44 | 
 45 | // 아래와 같이 변환된다.
 46 | 
 47 | int a = 2; List<Integer> b = ..
 48 | ```
 49 | 
 50 | 
 51 | 
 52 | **문자 관련**
 53 | 
 54 | - 문자에 해당하는 아스키 코드를 char에 숫자 형태로 대입하지 못한다. 컴파일 에러가 발생한다.
 55 | - toChar() 함수를 사용해 다른 자료형의 값을 문자 자료형으로 대입한다.
 56 | 
 57 | ```kotlin
 58 | val code: Int=65 
 59 | // code에 해당하는 문자를 할당한다. 
 60 | val ch: Char = code.toChar()
 61 | ```
 62 | 
 63 | 
 64 | 
 65 | **문자열 관련**
 66 | 
 67 | - 문자열의 특정 문자에 접근할 때 get() 혹은 대괄호([])와 인덱스를 사용해 접근한다.
 68 | - 문자열 템플릿을 사용해 템플릿 문자열 내에 직접 인자를 대입한다.
 69 |   - 인자로 값이나 변수 대신 표현식을 넣을 경우 `중괄호{}`로 구분한다.
 70 | 
 71 | ```kotlin
 72 | val foo: String = "Victory" val ch1: Char = foo.get(0) // V 
 73 | val ch2: Char = foo[1] // i
 74 | 
 75 | val length: Int = 10 
 76 | val lengthText: String = "Length: $length meters" 
 77 | val text = "Length : ${foo.length}"
 78 | ```
 79 | 
 80 | 
 81 | 
 82 | **배열**
 83 | 
 84 | - 타입 인자를 갖는 Array 클래스로 표현한다.
 85 | - arrayOf() : 코틀린 표준 라이브러리에 포함. 입력 받은 인자로 구성된 배열을 생성.
 86 | - 자바의 원시 타입은 코틀린 배열 클래스의 타입 인자로 사용할 수 없다.
 87 | - 자바 원시 타입을 인자로 갖는 배열을 표현하기 위해서는 원시 타입에 대응하는 특수한 클래스를 사용해야 한다.
 88 | 
 89 | ```kotlin
 90 | val words: Array<String> = arrayOf("a","b")
 91 | 
 92 | // 원시 타입의 배열 
 93 | val intArr: IntArray = intArrayOf(1,2,3) 
 94 | // wrapper 타입의 배열 
 95 | val IntArr2: Array<Int> = arrayOf(1,2,3)
 96 | ```
 97 | 
 98 | 
 99 | 
100 | **컬렉션**
101 | 
102 | - JVM을 기반으로 하므로 컬렉션은 자바에서 제공하는 클래스들을 그대로 사용한다.
103 | - 컬렉션 내 자료의 수정 가능 여부에 따라 컬렉션의 종류를 구분한다.
104 | - Collection, List 인터페이스에는 자료를 조회하는 함수만 포함되어 있으므로 자료가 할당되면 수정이 불가능하다.
105 | - MutableCollection, MutableList 인터페이스에는 자료를 수정하는 함수가 포함되어 있다.
106 | - set, map 도 동일한 규칙이 지정된다.
107 | - listOf, setOf, mapOf : 자료의 수정이 불가능하다.(**불변 - immutable**)
108 | 
109 | ```kotlin
110 | // 자료의 수정이 불가능함. immutable하다. 
111 | val immutableList: List<String> = listOf("a","b")
112 | 
113 | // get(0)과 동일. 
114 | val firstItem: String= immutableList[0]
115 | 
116 | // 컴파일 오류 발생. 
117 | immutableList[0] = "c"
118 | 
119 | val immutableMap : Map<String, Int> = mapOf(Pair("A", 65) , Pair("B", 66))
120 | 
121 | // 키 "A"에 해당하는 값 - get("A")과 동일. 
122 | val code: Int = immutableMap["A"]
123 | 
124 | // 불변이므로 컴파일 에러. 
125 | immutableMap["C] = 67
126 | 
127 | val mutableMap : HashMap<String, Int> = hashMapOf(Pair("A",65),Pair("B",66)) // 가변이므로 가능.
128 | mutableMap["C"] = 67
129 | 
130 | // 조금 더 간단하게 Pair 표현 // key to value 형태. 
131 | val map : Map<String, Int> = mapOf("A" to 65, "B" to 66)
132 | ```
133 | 
134 | 
135 | 
136 | **클래스 및 인터페이스**
137 | 
138 | - 디폴트가 public이다.
139 | 
140 | - 선언된 내용이 없으면 몸체만 선언할 수 있다.
141 | 
142 | - new를 사용하지 않고 인스턴스를 생성.
143 | 
144 | - 추상 클래스와 인터페이스는 인스턴스를 생성하는 형태가 자바와 조금 다르다.
145 | 
146 | - 추상 클래스에서는 인스턴스를 생성 시 생성자를 사용하지만, 생성자가 없는 인스턴스 생성 시 인터페이스 이름만 사용한다.
147 | 
148 |   
149 | 
150 |   ```kotlin
151 |   abstract class Foo{ 
152 |     abstract fun bar() 
153 |   }
154 |   // object: 생성자 
155 |   val foo = object: Foo(){
156 |   override fun bar(){
157 |     	// 함수 구현.
158 |     }
159 |   }
160 |   
161 |   interface Bar{ 
162 |     fun baz() 
163 |   } 
164 |   // object: 인터페이스 이름 
165 |   val bar = object: Bar{
166 |       override fun baz(){
167 |     	// 함수 구현.
168 |     }
169 |   }
170 |   ```
171 | 
172 | **프로퍼티**
173 | 
174 | - 자료를 저장할 수 있는 필드와 이에 상응하는 **getter/setter 메소드**를 함께 제공한다.
175 | - 클래스의 멤버로 사용하는 프로퍼티는 초기값을 명시적으로 지정해야 한다. 그렇지 않을 시 컴파일 에러 발생.
176 |   - 단, 생성자에서 프로퍼티의 값을 할당한다면 선언 시 값을 할당하지 않아도 된다.
177 | - 프로퍼티 선언 시점이나 생성자 호출 시점에 값을 할당할 수 없는 경우 `lateinit` 키워드를 사용해 프로퍼티의 값이 나중에 할당될 것임을 명시한다.
178 |   - `lateinit` 키워드는 var 변수에만 사용 가능.
179 |   - 반드시 초기화 해야 한다.
180 |   - 프로퍼티에 초기값을 할당하는 시점에서 해당 프로퍼티의 타입을 추론할 수 있다면 타입 선언 생략 가능.
181 |   - lazy : 사용 시점(참조 시점)에 메모리에 할당. 선언하고 참조하지 않으면 메모리 할당하지 않음.
182 | 
183 | ```kotlin
184 | class Person{ 
185 |   lateinit var gender: String 
186 |   // 선언 시점에 값을 할당하지 않아도 컴파일 에러 발생 X. 
187 | }
188 | ```
189 | 
190 | 
191 | 
192 | 주의할 점이 하나 있다.
193 | 
194 | `lateinit` 키워드를 사용했는데, 초기화 하지 않으면 **Uninitialized PropertyAccessException** 예외가 발생한다. 컴파일 단계에서는 확인이 불가능하므로 `lateinit` 키워드를 사용할 경우 반드시 초기화 여부를 확인하는 것이 좋다.
195 | 
196 | ```kotlin
197 | lateinit var name: String
198 | 
199 | // 초기화가 되었는지 확인할 수 있다.
200 | if(::name.inInitialized){
201 | 	println("초기화O")
202 | }else{
203 | 	println("초기화X")
204 | }
205 | ```


--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
 1 | MIT License
 2 | 
 3 | Copyright (c) 2020 이승우
 4 | 
 5 | Permission is hereby granted, free of charge, to any person obtaining a copy
 6 | of this software and associated documentation files (the "Software"), to deal
 7 | in the Software without restriction, including without limitation the rights
 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 | 
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 | 
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 | 


--------------------------------------------------------------------------------
/Network/3 way handshake.md:
--------------------------------------------------------------------------------
 1 | ## 3 way handshake
 2 | 
 3 | TCP/IP 프로토콜을 이용하여 통신을 진행할 때, 두 종단 간 **정확한** 데이터 전송을 보장하기 위해 연결을 설정하는 과정이다.
 4 | 
 5 | <img src="https://user-images.githubusercontent.com/33534771/75338886-d77ea880-58d2-11ea-84c3-f8b60663f9c6.png" width="60%"/>
 6 | 
 7 | 
 8 | **[연결 과정]**
 9 | 
10 | > SYN : Synchronize Sequence Number
11 | >
12 | > ACK : Acknowledgement
13 | 
14 | 1) 클라이언트는 서버에 접속을 요청하는 SYN(a) 패킷을 보낸다.
15 | 
16 | 2) 서버는 클라이언트의 요청인 SYN(a) 패킷에 대한 요청 수락 응답으로 ACK(a+1) 패킷과 클라이언트도 포트를 열어달라는 SYN(b) 패킷을 보낸다.
17 | 
18 | 3) 클라이언트는 ACK(a+1) 패킷과 SYN(b) 패킷을 받고 이에 대한 응답으로 ACK(b+1) 패킷을 보내며 연결이 성립된다.
19 | 
20 | 
21 | 
22 | **[Q. 왜 2way가 아니라 3way일까?]**
23 | 
24 | **TCP**는 `양방향성 연결`이기 때문에 클라이언트에서 서버에게 자신의 존재를 알리고 패킷을 보낼 수 있는 것처럼 서버에서도 클라이언트에게 자신의 존재를 알리고 패킷을 보낼 수 있다는 신호를 보내야 하기 때문이다.
25 | 
26 | 
27 | 
28 | **[참고]**
29 | 
30 | **처음에 클라이언트에서 SYN 패킷을 보낼 때 Sequence Number에는 랜덤한 숫자가 담겨진다.** 
31 | 
32 | Connection을 맺을 때, 사용하는 포트(port)는 유한 범위 내에서 사용하고 시간이 지남에 따라 재사용한다. 따라서 이전에 사용한 포트 번호를 재사용할 가능성이 있다.
33 | 
34 | Sequence Number가 순차적인 숫자로 전송된다면 서버는 이전의 Connection으로부터 전송되는 패킷으로 인식할 수 있다. 따라서 이러한 문제를 해결하기 위해 난수로 초기 Sequence Number를 설정한다.
35 | 
36 | 
37 | 
38 | ## 4 way handshake
39 | 
40 | TCP/IP 프로토콜을 이용한 통신 과정에서는 위에서 언급했던 것처럼 3 way handshake 과정을 통해 연결을 설정하고 4 way handshake 과정을 통해 연결 설정을 해제한다.
41 | 
42 | <img src="https://user-images.githubusercontent.com/33534771/75338959-ef562c80-58d2-11ea-99eb-1c09ec97e83a.png" width="60%"/>
43 | 
44 | 
45 | 
46 | **[연결 과정]**
47 | 
48 | 1) 클라이언트는 서버에게 연결을 종료하겠다는 FIN 패킷을 보낸다.
49 | 
50 | 2) 서버는 클라이언트의 요청(FIN)에 대한 응답으로 ACK 패킷을 보낸다.
51 | 
52 | ​	2-1) 처리해야 할 자신의 통신이 끝날 때까지 기다린다.
53 | 
54 | 3) 처리해야 할 모든 통신을 끝마쳤다면 연결을 종료하겠다는 FIN 패킷을 보낸다.
55 | 
56 | 4) 클라이언트는 FIN 패킷에 대한 확인 응답으로 ACK 패킷을 보낸다.
57 | 
58 | 5) 클라이언트의 ACK 패킷을 받은 서버는 소켓 연결을 close 한다.
59 | 
60 | 6) 클라이언트는 아직 서버로부터 받지 못한 데이터가 있을 것을 대비해 기다리는 과정을 거친다.(TIME_WAIT)
61 | 
62 | 
63 | 
64 | [에러 발생]
65 | 
66 | 클라이언트에서 FIN 패킷 전송 후 ACK 패킷을 기다리는 FIN_WAIT1과 서버의 ACK 패킷을 받은 후 FIN 패킷을 기다리는 FIN_WAIT2 에러 발생으로 인해 Time out이 되면 스스로 연결을 종료한다.
67 | 
68 | 
69 | 
70 | 그러나, CLOSE_WAIT은 Application이 close()를 적절하게 처리하지 못하면 CLOSE_WAIT 상태로 계속 기다리게 되어 Socket Hang Up 에러가 발생할 수 있다.
71 | 


--------------------------------------------------------------------------------
/Network/Blocking I:O & Non-Blocking I:O.md:
--------------------------------------------------------------------------------
 1 | ## Blocking I/O & Non-Blocking I/O
 2 | 
 3 | 
 4 | 
 5 | ### I/O 작업
 6 | 
 7 | - I/O 작업은 Input/Output의 약자.
 8 | - 주로 파일 입출력을 다룰 때, 흔히 볼 수 있다.
 9 | - Ex) 두 대 이상의 컴퓨터끼리 서로 네트워크를 통해 통신을 한다고 가정할 때, 한 컴퓨터에서 출력(send)을 하고 다른 한 컴퓨터에서 입력(read)을 받는 과정을 통해 통신할 수 있다.
10 | - I/O 작업은 User Level에서 직접 수행할 수 없고, **실제 I/O 작업을 수행하는 것은 Kernel Level에서만 가능하다.**
11 | - User Process, Thread는 커널에게 요청하고 작업 완료 후, 커널이 반환하는 결과를 기다릴 뿐이다.
12 | 
13 | 
14 | 
15 | ### Blocking Model
16 | 
17 | 가장 기본적인 I/O 모델로, 리눅스에서 모든 소켓 통신은 기본 blocking으로 동작한다.
18 | 
19 | I/O 작업이 진행되는 동안 유저 프로세스는 자신의 작업을 중단한 채 대기하는 방식이다.
20 | 
21 | ![img](https://user-images.githubusercontent.com/41428527/51266321-4ade9700-19fe-11e9-9b23-30bca4faccfd.png)
22 | 
23 | 
24 | 
25 | 위의 그림처럼
26 | 
27 | 1) 유저는 커널에게 read 작업을 요청.
28 | 
29 | 2) 데이터가 입력될 때까지 대기.
30 | 
31 | 3) 데이터가 입력되면 유저(커널->유저)에게 결과가 전달되어야만 유저 자신의 작업에 비로소 복귀할 수 있다.
32 | 
33 | 
34 | 
35 | - **말 그대로 block이 되고, 어플리케이션에서 다른 작업을 수행하지 못하고 대기하게 되므로 자원이 낭비된다.**
36 | 
37 | 
38 | 
39 | ### Non-Blocking Model
40 | 
41 | 위와 같은 blocking 방식의 비효율성을 극복하고자 도입된 방식이다.
42 | 
43 | **I/O 작업이 진행되는 동안 유저 프로세스의 작업을 중단시키지 않는 방식이다.**
44 | 
45 | ![img](https://user-images.githubusercontent.com/41428527/51266324-4e721e00-19fe-11e9-900a-809ff39e40c1.png)
46 | 
47 | `How to`
48 | 
49 | 1) 유저가 커널에게 read 작업을 요청.
50 | 
51 | 2) **데이터가 입력되었든 입력되지 않았든 요청하는 그 순간, 바로 결과가 반환된다.**
52 | 
53 | - 이때, 입력 데이터가 없으면 입력 데이터가 없다는 결과 메시지를 반환한다.
54 | 
55 | 3) 입력 데이터가 있을 때까지 1~2번을 반복.(**2번에서 결과 메시지를 받은 유저는 다른 작업 진행이 가능하다.**)
56 | 
57 | 4) 입력 데이터가 있으면 유저(커널->유저)에게 결과가 전달된다.
58 | 
59 | 
60 | 
61 | - **이 경우 I/O의 진행시간과 관계가 없기 때문에(대기X) 어플리케이션에서 작업을 오랜 시간 중지하지 않고도 I/O 작업을 진행할 수 있다.**
62 | - **그러나 반복적으로 시스템 호출이 발생하기 때문에 이 경우 역시 자원이 낭비된다.**
63 | 
64 | 
65 | 
66 | ### 참고
67 | 
68 | - [Blocking I/O & Non-Blocking I/O]([https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Network/%5BNetwork%5D%20Blocking%20Non-Blocking%20IO.md](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer Science/Network/[Network] Blocking Non-Blocking IO.md))
69 | 
70 | - [블로킹(Blocking), 논블로킹(Non-Blocking) - I/O 모델 (1)](https://ju3un.github.io/network-basic-1/)


--------------------------------------------------------------------------------
/Network/Cookie_Session.md:
--------------------------------------------------------------------------------
 1 | ### Cookie & Session
 2 | 
 3 | HTTP는 비상태성(Stateless) 프로토콜로 상태 정보를 유지하지 않는다. 연결을 유지하지 않기 때문에 리소스 낭비가 줄어드는 것은 큰 장점이지만 통신할 때마다 매번 연결 설정을 해야 하며, 이전 요청과 현재 요청이 같은 사용자의 요청인지 알 수 없다는 단점이 존재한다.
 4 | 
 5 | 쿠키와 세션을 통해서 HTTP의 Stateless한 문제점을 해결할 수 있다.
 6 | 
 7 | 
 8 | 
 9 | [저장 위치]
10 | 
11 | - 쿠키 : 클라이언트의 웹 브라우저가 지정하는 메모리 or 하드 디스크
12 | - 세션 : 서버의 메모리
13 | 
14 | 
15 | 
16 | [만료 시점]
17 | 
18 | - 쿠키 : 저장할 때, expires 속성을 정의하여 무효화시키면 삭제될 날짜를 지정할 수 있다.
19 | - 세션 : 클라이언트가 로그아웃하거나 설정 시간 동안 반응이 없으면 무효화되기 때문에 정확한 시점을 알 수 없다.
20 | 
21 | 
22 | 
23 | [리소스]
24 | 
25 | - 쿠키 : 클라이언트에 저장되고 클라이언트의 메모리를 사용하기 때문에 서버 자원을 사용하지 않는다.
26 | - 세션 : 서버에 저장되고, 서버 메모리로 로딩되기 때문에 세션이 생길 때마다 리소스를 차지한다.
27 | 
28 | 
29 | 
30 | [용량 제한]
31 | 
32 | - 쿠키 : 클라이언트도 모르게 접속되는 사이트에 의하여 설정될 수 있기 때문에 쿠키로 인해 문제가 발생하는 걸 막고자 한 도메인당 20개, 하나의 쿠키당 4KB로 제한해 두었다.
33 | - 세션 : 클라이언트가 접속하면 서버에 의해 생성되므로 개수나 용량 제한이 없다.
34 | 
35 | 
36 | 
37 | [보안]
38 | 
39 | - 쿠키 : 클라이언트에 저장하기 때문에 보안에 취약하다.
40 | - 세션 : 서버에 저장하기 때문에 쿠키에 비해서는 보안에 우수하다.
41 | 
42 | 
43 | 
44 | ### Reference
45 | 
46 | - [규글님](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Web/Cookie%20%26%20Session.md)
47 | 


--------------------------------------------------------------------------------
/Network/GetVsPost.md:
--------------------------------------------------------------------------------
 1 | ### GET
 2 | 
 3 | 주로 데이터를 읽거나 검색할 때 사용하는 메소드이다. GET 요청이 성공적으로 이루어진다면 XML이나 JSON과 함께 200(ok) HTTP Status Code를 반환한다. 
 4 | 만약, 에러가 발생하면 주로 404(Not found) 에러나 400(Bad Request) 에러가 발생한다.
 5 | 
 6 | HTTP 명세에 의하면 GET 요청은 오로지 데이터를 읽을 때만 사용되고 수정할 때는 사용하지 않는다. 따라서 이런 이유로 사용하면 안전하다고 간주된다. 즉, 데이터 변형의 위험 없이 사용할 수 있다는 뜻이다. 게다가 GET 요청은 **멱등성**을 가지고 있다. 즉, 같은 요청을 여러번 하더라도 변함없이 항상 같은 응답을 받을 수 있다.
 7 | 
 8 | 그러므로 GET을 데이터를 변경하는 등의 안전하지 않은 연산에 사용하면 안된다.
 9 | 
10 | ### POST
11 | 
12 | 주로 새로운 리소스를 생성(Create)할 때 사용된다. 구체적으로 POST는 하위 리소스들(부모 리소스의 하위 리소스)을 생성하는데 사용된다. 성공적으로 Creation을 완료하면 201(Created) HTTP Status Code를 반환한다. 
13 | 
14 | POST 요청은 안전하지도 않고 멱등성이 있지도 않다. 다시 말해서 같은 POST 요청을 반복해서 했을 때 항상 같은 결과물이 나오는 것을 보장하지 않는다는 것이다. 그러므로 두 개의 같은 POST 요청을 보내면 같은 정보를 담은 두 개의 다른 resource를 반환할 가능성이 높다.
15 | 
16 | ### GET vs POST
17 | 
18 | - GET : 모든 필요한 데이터를 URL에 포함하여 요청한다.
19 | - POST : 추가적인 데이터를 body에 포함할 수 있다.
20 | 
21 | |제목| GET | POST |
22 | |------|---|---|
23 | |History|파라미터들은 URL의 일부분이기 때문에 브라우저 히스토리에 남는다.|파라미터들이 브라우저 히스토리에 저장되지 않는다.|
24 | |Bookmarked|요청 파라미터들이 URL로 인코딩되므로 즐겨찾기가 가능하다.|요청 파라미터들이 request body에 포함되고 request URL에 나타나지 않으므로 즐겨찾기가 불가능하다.|
25 | |button/re-sumit behavior|GET 요청이 다시 실행되더라도 브라우저 캐시에 HTML이 저장되어 있다면 서버에 다시 submit되지 않는다.|브라우저가 보통 사용자에게 데이터가 다시 submit 되어야 한다고 alert을 준다.|
26 | |Encoding type|application/x-www-form-urlencoded|multipart/form-data or application/x-www-form-urlencoded Use multipart encoding for binary data|
27 | |Parameters|전송 가능하지만 URL에 넣을 수 있는 파라미터 데이터가 제한된다. 2K 이하로 사용하는 것이 안전하며 몇몇 서버들은 64K까지 다룬다.|서버에 파일 업로드하는 것을 포함하여 파라미터를 전송할 수 있다.|
28 | |Hacked|script kiddies에 의해 해킹되기 쉽다.|GET에 비해 해킹이 좀 더 어렵다.|
29 | |Restrictions on form data type|오직 ASCII characters만 허용된다.|제한이 없으며, binary data도 허용된다.|
30 | |Security|GET은 POST에 비해 보안에 약하다. 그 이유는 데이터가 URL의 일부로 전송되고 그 때문에 브라우저 히스토리에 저장되며 서버가 plain text로 로그를 남기기 때문이다.|POST는 GET에 비해 보안이 조금 더 안전하다. 그 이유는 파라미터들이 브라우저 히스토리나 서버 로그에 저장되지 않기 때문이다.|
31 | |Restrictions on form data length|form data가 URL에 포함되고 URL 길이가 제한되기 때문에 form data의 길이도 제한된다. 안전한 URL 길이는 2047 characters이나 브라우저나 웹 서버에 따라 달라진다.|제한이 없다.|
32 | |Usability|GET 메소드는 비밀번호와 같은 민감한 정보들을 전송하는데 사용해서는 안된다.|POST 메소드는 비밀번호와 같은 민감한 정보를 전송하는데 사용된다.|
33 | |Visibility|GET 메소드는 모두에게 보여진다. (브라우저 주소창에 그대로 보여지고 그에 따라 전송가능한 정보의 양도 제한된다.)|POST 메소드는 URL에 보여지지 않는다.|
34 | |Cached|GET 은 idempotent하기 때문에 캐시가 된다.(멱등성 : 같은 요청을 여러 번 보내도 항상 같은 응답이 나온다.)|POST는 idempotent하지 않기 때문에 캐시가 되지 않는다. (같은 요청을 여러 번 보내도 다른 응답이 올 수 있다.)|
35 | 
36 | ### Ref
37 | - https://im-developer.tistory.com/166
38 | 


--------------------------------------------------------------------------------
/Network/HTTP, HTTPS.md:
--------------------------------------------------------------------------------
 1 | ## HTTP, HTTPS
 2 | 
 3 | **[HTTP]**
 4 | 
 5 | - 웹 서버와 클라이언트 간의 문서를 교환하기 위한 통신 규약
 6 | - 웹에서만 사용하는 프로토콜로 TCP/IP 기반으로 서버와 클라이언트 간의 요청과 응답을 전송한다.
 7 | 
 8 | 
 9 | 
10 | **[HTTP의 특징]**
11 | 
12 | - TCP 기반의 통신 방식
13 | - 비연결 지향
14 |   - 브라우저를 통해 사용자의 요청으로 서버와 접속하여 요청에 대한 응답의 데이터를 전송후, 연결을 종료한다.
15 |   - 간단하기 때문에 자원이 적게드는 장점이 있다.
16 |   - 하지만, 연결이 지속적이지 않기 때문에 사용자와 연결 종료후 추가적인 요청시 어떤 사용자의 요청인지 모른다는 점이 존재한다.
17 |   - 즉, 여러 사용자가 요청할 시 각각의 사용자 요청을 구분할 수 없어서 제대로 된 응답 데이터를 전송할 수 없다는 단점이 있다.
18 |   - 해결 방법으로는 쿠키, 세션, 히든 폼 필드 등이 있다.
19 | - 단방향성
20 |   - 사용자의 요청 한개에 대해 한개의 응답을 하는 방식이기 때문에 서버가 먼저 응답하지 않는다.
21 | 
22 | 
23 | 
24 | **HTTP의 문제점**
25 | 
26 | - HTTP는 평문 통신이기 때문에 도청이 가능하다.
27 | - 통신 상대를 확인하지 않기 때문에 위장이 가능하다.
28 | - 완전성을 증명할 수 없기 때문에 변조가 가능하다.
29 | 
30 | 
31 | 
32 | 이러한 문제점을 해결하기 위해 HTTPS가 등장했다.
33 | 
34 | 
35 | 
36 | **[HTTPS]**
37 | 
38 | - HTTP 통신하는 소켓 부분을 인터넷 상에서 정보를 암호화하는 SSL(Secure Socket Layer)라는 프로토콜로 대체한 것이다. 
39 | - HTTP는 TCP와 통신했지만, HTTPS에서 HTTP는 SSL과 통신하고 SSL이 TCP와 통신하게 된다.
40 | - 즉, 하나의 레이어를 더 둔 것이다.
41 | - HTTPS의 SSL에서는 **대칭키 암호화 방식과 공개키 암호화 방식을 모두 사용**한다.
42 | 
43 | 
44 | 
45 | ### SSL
46 | 
47 | SSL 프로토콜은 Netscape 사에서 웹 서버와 브라우저 사이의 보안을 위해 만들어졌다. CA(Certificate Authority)라 불리는 서드 파티로부터 서버와 클라이언트의 인증을 하는데 사용된다. 
48 | 
49 | 
50 | 
51 | **애플리케이션 서버를 운영하는 기업은 CA를 통해 인증서를 만든다.**
52 | 
53 | 1. 애플리케이션 서버를 운영하는 기업은 HTTPS 적용을 위해 공개키와 개인키를 만든다.
54 | 2. 신뢰할 수 있는 CA 기업을 선택하고 인증서 생성을 요청한다.
55 | 3. CA는 서버의 공개키, 암호화 방법 등의 정보를 담은 인증서를 만들고 해당 CA의 개인키로 암호화하여 서버에 제공한다.
56 | 4. 클라이언트가 SSL로 암호화된 페이지(https://)를 요청시 서버는 인증서를 전송한다.
57 | 
58 | 
59 | 
60 | **클라이언트와 서버의 통신 흐름 과정**
61 | 
62 | 1. 클라이언트가 SSL로 암호화된 페이지를 요청한다.
63 | 2. 서버는 클라이언트에게 인증서를 전송한다.
64 | 3. 클라이언트는 인증서가 신용이 있는  CA로부터 서명된 것인지 판단한다. 
65 |    브라우저는 CA 리스트와 해당 CA의 공개키를 가지고 있다. 공개키를 활용하여 인증서가 복호화가 가능하다면 접속한 사이트가 CA에 의해 검토되었다는 것을 의미한다. 따라서 서버가 신용이 있다고 판단한다. 공개키가 데이터를 제공한 사람의 신원을 보장해주는 것으로 이러한 것을 **전자 서명** 이라고 한다.
66 | 4. 클라이언트는 CA의 공개키를 이용해 인증서를 복호화하고 서버의 공개키를 획득한다.
67 | 5. 클라이언트는 서버의 공개키를 사용해 랜덤 대칭 암호화키, 데이터 등을 암호화하여 서버로 전송한다.
68 | 6. 서버는 자신의 개인키를 이용해 복호화하고 랜덤 대칭 암호화키, 데이터 등을 획득한다.
69 | 7. 서버는 랜덤 대칭 암호화키로 클라이언트 요청에 대한 응답을 암호화하여 전송한다.
70 | 8. 클라이언트는 랜덤 대칭 암호화키를 이용해 복호화하고 데이터를 이용한다.
71 | 
72 | <img src="https://user-images.githubusercontent.com/33534771/75338777-a1d9bf80-58d2-11ea-9754-809110475c89.png" width="50%"/>
73 | 
74 | 
75 | **인증서에 포함된 내용**
76 | 
77 | - 서버측 공개키(public key)
78 | - 공개키 암호화 방법
79 | - 인증서를 사용한 웹서버의 URL
80 | - 인증서를 발행한 기관 이름
81 | 
82 | 
83 | 
84 | 모든 웹페이지에서 HTTPS를 사용하지 않는다. 이유는 평문 통신에 비해서 암호화 통신은 CPU나 메모리 등 리소스를 많이 필요로 하기 때문이다. 통신할 때마다 암호화를 하면 리소스를 소비하기 때문에 서버 한 대당 처리할 수 있는 Request 수가 줄어들게 된다.
85 | 
86 | 따라서 민감한 정보를 다룰 때만 HTTPS에 의한 암호화 통신을 사용해야 한다.
87 | 


--------------------------------------------------------------------------------
/Network/HTTP동작과정과 HTTP Method, 상태코드.md:
--------------------------------------------------------------------------------
 1 | # HTTP란?
 2 | > HyperText Transfer Protocal의 약자로써 **인터넷 통신을 위해 사용되는 프로토콜**이다.
 3 | 
 4 | # HTTP 동작
 5 | 
 6 | Client가 브라우저를 통해 URI을 통해 특정 요청(Request)을 보내면, Server는 해당 요청(Request)을 받아 처리를 하여 Client에게 응답(Response)을 하는 형태
 7 | 
 8 | ![hppt동작 과정](https://user-images.githubusercontent.com/37958836/119261737-ab57f180-bc13-11eb-85d4-cae4e392c5a3.png)
 9 | 
10 | # HTTP 특징
11 | - TCP/IP을 이용한 응용 프로토콜이다.
12 | - 연결 상태를 유지하지 않는 비연결성 프로토콜이다.
13 | - 요청과 응답 방식으로 동작한다.
14 | - 서버와 클라이언트에 의해 HTTP 메세지가 해석된다.
15 | 
16 | # HTTP Method
17 | | Method  | 설명                                                                                                    |
18 | | ------- | ------------------------------------------------------------------------------------------------------- |
19 | | GET     | URI가 가진 정보를 검색하기 위해 요청하는 메소드                                                         |
20 | | HEAD    | GET메소드와 방식은 동일하지만, `응답에 BODY가 없고 응답 코드와 HEAD만 응답하는데 사용`되는 메소드       |
21 | | POST    | 요청된 자원을 생성하기 위한 메소드                                                                      |
22 | | PUT     | 요청된 자원을 수정할때 사용하고, `PATHCH와는 다르게 자원 전체를 갱신하는데 사용`되는 메소드             |
23 | | PATCH   | PUT메소드와 유사하게 요청된 자원을 수정할때 사용되지만, `자원의 일부를 수정`하는 의미로 사용되는 메소드 |
24 | | DELETE  | 요청된 자원을 삭제하기 위한 메소드                                                                      |
25 | | CONNECT | 동적으로 터널 모드를 교환하고 프락시 기능을 요청할때 사용하는 메소드                                    |
26 | | TRACE   | 원격 서버에 루프백 메세지를 호출하기 위해 테스트용도로 사용하는 메소드                                  |
27 | | OPTIONS | 웹 서버에서 지원하는 메소드의 종류들을 확인할 경우 사용하는 메소드                                      |
28 | 
29 | # HTTP Status Code
30 | 
31 | ### 정보전송 임시응답 (1xx)
32 | - 서버가 요청을 클라이언트에서 성공적으로 수신을 했고 서버에서 처리중인 정보를 보낸디.
33 | 
34 |     | Status Code | 설명               |
35 |     | ----------- | ------------------ |
36 |     | 100         | Continue           |
37 |     | 101         | Swiching protocols |
38 | 
39 | ### 성공 (2xx)
40 | - 서버가 요청을 `성공`적으로 받았음을 알려준다.
41 | 
42 |     | Status Code | 설명                          |
43 |     | ----------- | ----------------------------- |
44 |     | 200         | Ok!                           |
45 |     | 201         | Created                       |
46 |     | 202         | Accepted                      |
47 |     | 203         | Non-authoritative Information |
48 |     | 204         | No Cotent                     |
49 | 
50 | ### 리다이렉션 (3xx)
51 | - 캐싱된 파일을 새로고침 하여 확인하면 3xx대 코드을 받을 수 있다.
52 | 
53 |     | Status Code | 설명              |
54 |     | ----------- | ----------------- |
55 |     | 301         | Moved permanently |
56 |     | 302         | Not temporarily   |
57 |     | 303         | Not modified      |
58 | 
59 | ### 클라이언트 요청 오류 (4xx)
60 | - 클라이언에서 서버에 잘못된 요청을 보내 서버가 요청을 해결 할 수 없을때 발생하는 코드이며, `클라이언트측에서 발생하는 코드`이다.
61 | 
62 |     | Status Code | 설명                          |
63 |     | ----------- | ----------------------------- |
64 |     | 400         | Bad Request                   |
65 |     | 401         | Unauthorized                  |
66 |     | 402         | Payment required              |
67 |     | 403         | Forbidden                     |
68 |     | 404         | Not found                     |
69 |     | 405         | Method not allowed            |
70 |     | 407         | Proxy authentication required |
71 |     | 408         | Request timeout               |
72 |     | 410         | Gone                          |
73 |     | 412         | Precondition failed           |
74 |     | 414         | Request-URI too long          |
75 | 
76 | ### 서버에러 (5xx)
77 | - 클라이언트의 요청을 받고 서버에서 처리하지 못할때 발생하는 코드이며, `서버측에서 발생하는 코드`이다.
78 | 
79 |     | Status Code | 설명                       |
80 |     | ----------- | -------------------------- |
81 |     | 500         | Internal server error      |
82 |     | 501         | Not implemented            |
83 |     | 503         | Service unnailable         |
84 |     | 504         | Gateway timeout            |
85 |     | 505         | HTTP version not supported |


--------------------------------------------------------------------------------
/Network/OSI 7 계층.md:
--------------------------------------------------------------------------------
 1 | ## OSI 7 계층
 2 | 
 3 | <img src="https://user-images.githubusercontent.com/33534771/74589801-e603cf00-504b-11ea-862c-765c57d3169b.png" width="60%"/>
 4 | 
 5 | **OSI 7 계층을 나누는 이유는 무엇일까?**
 6 | 
 7 | 중요한 목적은 표준과 학습 도구라 할 수 있다. 표준화를 통해 이질적인 포트 문제나 프로토콜 등으로 인한 문제를 해결하여 비용을 절감했다. 또한, 계층별의 기능과 통신 과정을 단계별로 나누어서 쉽게 알 수 있고, 특정한 곳에 이상이 생기면 그 단계만 수정할 수 있기 때문에 편리하다.
 8 | 
 9 | 
10 | 
11 | **1) 물리(Physical)**
12 | 
13 | > 리피터, 케이블, 허브 등
14 | 
15 | 주로 전기적, 기계적, 기능적인 특성을 이용해서 통신 케이블로 데이터를 전송하는 역할을 한다.
16 | 
17 | 
18 | 
19 | **2) 데이터 링크(Data Link)**
20 | 
21 | > 브릿지, 스위치 등
22 | 
23 | 물리 계층을 통해 송, 수신되는 정보의 오류와 흐름을 관리하여 안전한 정보의 전달을 수행할 수 있도록 도와주는 역할을 한다.
24 | 
25 | MAC 주소를 이용해 통신한다. 
26 | 
27 | Frame에 MAC 주소를 부여하고 에러검출, 재전송, 흐름 제어를 진행한다.
28 | 
29 | 
30 | 
31 | **3) 네트워크(Network)**
32 | 
33 | > 라우터, IP
34 | 
35 | 여러 개의 노드를 거칠 때마다 경로를 찾아주는 역할을 하며, 다양한 길이의 데이터를 목적지까지 가장 안전하고 빠르게 전달하는 기능을 담당한다. (전송 계층이 요구하는 서비스 품질을 제공하기 위한 기능적, 절차적 수단을 제공한다.)
36 | 
37 | 라우터를 통해 이동할 경로를 선택하여 IP  주소를 지정하고, 해당 경로에 따라 패킷을 전달해준다. 
38 | 
39 | 라우팅, 흐름 제어, 오류 제어, 세그먼테이션 등을 수행한다.
40 | 
41 | 
42 | 
43 | **4) 전송 계층(Transport)**
44 | 
45 | > TCP, UDP
46 | 
47 | TCP, UDP 프로토콜을 통해 통신을 활성화 한다. 포트를 열어두고, 프로그램들이 전송을 할 수 있도록 제공해준다. 이를 통해 양 끝 단의 사용자들이 데이터를 주고 받을 수 있다.
48 | 
49 | - TCP : 신뢰성, 연결 지향적
50 | - UDP : 비신뢰성, 비연결성, 실시간
51 | 
52 | 
53 | 
54 | **5)세션(Session)**
55 | 
56 | > API, Socket
57 | 
58 | 양 끝 단의 응용 프로세스가 통신을 관리하기 위한 방법을 제공한다. 
59 | 
60 | 데이터가 통신하기 위한 논리적 연결을 담당한다.
61 | 
62 | TCP/IP 세션을 만들고 없애는 책임을 지니고 있다.
63 | 
64 | 
65 | 
66 | **6) 표현(Presentation)**
67 | 
68 | > JPEG, MPEG 등
69 | 
70 | 데이터 표현에 대한 독립성을 제공하고 암호화하는 역할을 담당한다.
71 | 
72 | 코드 간의 번역을 담당하여 사용자 시스템에서 데이터의 형식상 차이를 다루는 부담을 응용 계층으로부터 덜어준다. 
73 | 
74 | 파일 인코딩, 명령어를 포장, 압축, 암호화한다.
75 | 
76 | 
77 | 
78 | **7) 응용(Application)**
79 | 
80 | > HTTP, FTP, DNS 등
81 | 
82 | 최종 목적지로 응용 프로세스와 직접 관계하여 일반적인 응용 서비스를 수행한다.
83 | 
84 | 사용자 인터페이스, 전자우편, 데이터베이스 관리 등의 서비스를 제공한다.
85 | 


--------------------------------------------------------------------------------
/Network/REST & RESTful.md:
--------------------------------------------------------------------------------
 1 | ## REST & RESTful이란?
 2 | 
 3 | REST란 Representational State Transfer의 약자로 웹의 장점을 최대한 활용할 수 있는 Client와 Server 간 통신 방식 중 하나이다.
 4 | 
 5 | 
 6 | 
 7 | 설계 기본 규칙으로 HTTP URI를 통해 자원을 명시하고 HTTP method(GET, POST, PUT, DELETE)를 통해 자원을 처리하도록 설계된 아키텍처이다.
 8 | 
 9 | 
10 | 
11 | RESTful은 REST라는 아키텍처를 구현하는 웹 서비스를 나타내는 것으로 REST 원리를 따르는 시스템을 RESTful이라는 용어로 지칭한다.
12 | 
13 | 


--------------------------------------------------------------------------------
/Network/UDP.md:
--------------------------------------------------------------------------------
 1 | ## UDP
 2 | 
 3 | - User Datagram Protocol의 약자이다.
 4 | - 데이터를 데이터 그램 단위로 처리하는 프로토콜.
 5 |   - 데이터 그램 : 독립적인 관계를 지니는 패킷
 6 | - 비연결형 프로토콜로 사전에 연결 설정 없이 데이터를 전달한다.
 7 | - 사전에 연결 설정을 하지 않은 데이터 그램 방식을 통해 데이터를 전달하기 때문에 하나의 메시지에서 분할된 각각의 패킷은 서로 다른 경로로 전송될 수 있다. 
 8 | - 송신측에서 전송한 패킷의 순서와 수신측에 도착한 패킷의 순서가 다를 수 있다. 그러나 서로 다른 경로로 패킷을 처리함에도 불구하고 순서를 부여하거나 재조립하지 않는다.
 9 | - 흐름 제어, 혼잡 제어, 오류 제어를 하지 않으므로 손상된 세그먼트에 대한 재전송을 하지 않는다.
10 | - 이로 인해 속도가 빠르며 네트워크 부하가 적다는 장점이 있지만, 신뢰성 있는 데이터 전송을 보장하지 못한다.
11 | - UDP는 RTP(Real Time Protocol), Multicast, DNS 등에서 사용된다
12 | 
13 | 
14 | 
15 | DNS 같은 경우 누군가 DNS 서비스를 요청할 때마다 TCP처럼 Session을 맺고 통신한다면 속도도 느리고, 서버 리소스도 엄청나게 소모될 것이다.
16 | 
17 | 그런가 하면 NMS(Network Management Server)가 5분에 한번씩 장비 상태를 점검하기 위해 정보를 읽어오는데 수백, 수천대의 장비와 Session을 맺어야 한다면 이것도 마찬가지로 문제가 생긴다.
18 | 
19 | 그렇기 때문에 UDP를 사용한다.
20 | 
21 | 
22 | 
23 | 재전송을 하면 안되는 서비스가 있다.
24 | 
25 | 대표적으로 RTP이다.
26 | 
27 | 전화를 하고 있다 다고 가정해보자.
28 | 
29 | "여","보","세","요"라는 4개의 데이터를 전송했는데, "세"를 못받았다고 다시 보내달라고 하면 "여보요세"가 될 것이다.
30 | 
31 | 이럴 때는 그냥 "여보X요"로 전달하는게 나은 상황이다.
32 | 
33 | 
34 | 
35 | 또한, Multicast 서비스가 UDP를 사용한다.
36 | 
37 | 1:N으로 통신하는 방식에서 한 사람이 데이터를 받지 못했다고 재전송을 요청한다고 가정해보자. 제대로 받은 사람들도 해당 데이터를 다시 받아서 처리해야 한다는 문제점이 발생할 수 있기 때문에 UDP를 사용한다.
38 | 


--------------------------------------------------------------------------------
/Network/공개키 & 대칭키.md:
--------------------------------------------------------------------------------
 1 | ## 대칭키 & 공개키
 2 | 
 3 | **[대칭키 암호화]**
 4 | 
 5 | <img src="https://user-images.githubusercontent.com/33534771/75338515-2bd55880-58d2-11ea-9fcf-1fe65c72b69d.png" width="60%"/>
 6 | 
 7 | - 암호화에 사용되는 키와 복호화에 사용되는 키가 동일한 암호화 기법이다.
 8 | - 대칭키 암호 방식으로 암호화한 정보를 누군가에게 보낼 때, 암호키도 함께 보내야 한다. 암호키 자체는 암호화가 되지 않은 평문으로 분실하거나 타인에게 노출되면 보안에 매우 취약할 수 있다.
 9 | - **키 전달 및 관리에 어려움이 있지만, 대칭키 암호화 방식은 암호화 연산 속도가 빠르기 때문에 효율적인 암호 시스템을 구축할 수 있다는 장점이 있다.**
10 | - 블록 암호화, 스트림 암호화가 있다.
11 | 
12 | 
13 | 
14 | **[공개키 암호화]**
15 | 
16 | - 대칭키 암호화 방식의 키 전달의 취약점을 해결하기 위해 나온 방식이다. 암호화에 사용하는 키와 복호화에 사용하는 키를 분리했다. 따라서 **비대칭키 암호화**라고도 부른다.
17 | - 자신이 가지고 있는 고유한 암호키(개인키 혹은 비밀키)로만 복호화할 수 있는 암호키(공개키)를 대중에게 공개한다.
18 | 
19 | - `공개키 암호화 방식의 진행과정`
20 |   1. B 사용자는 자신의 공개키를 공개한다. 이 공개키는 암호화에 사용되는 키이며, 누구든지 열람이 가능하다. (복호화에 사용되는 키는 B 자신만 가지고 있다. 잃어버리면 안된다.)
21 |   2. A 사용자는 B 사용자의 공개키로 데이터를 암호화한다.
22 |   3. 암호화된 문서를 B 사용자에게 전송한다.
23 |   4. B 사용자는 자신만의 개인키(복호화키)를 이용하여 전송받은 암호화 문서를 복호화하여 데이터를 열람한다.
24 | 
25 | - 대칭키 암호화 방식의 키 전달 문제를 해결했지만 암호화, 복호화를 위해 복잡한 수학 연산을 수행하기 때문에 대칭키 방식에 비해 속도가 느리고 복잡하다는 단점이 있다. 
26 | 
27 | 
28 | 
29 | 대칭키 암호화의 장점과 공개키 암호화의 장점을 채택하여 용량이 큰 정보는 대칭키로 암호화하고, 암호화에 사용된 대칭키는 공개키로 암호화하여 대상에게 전달하는 하이브리드 암호화 방법이 일반적으로 사용되고 있다.
30 | 
31 | 
32 | 
33 | **공개키 기반 구조**
34 | 
35 | 특정 사람의 개인키와 공개키는 어떻게 생성할 것이며, 어떻게 배포할 것이고 어떻게 관리해야 하는가에 대한 이슈가 존재한다. 또한, 어떤 공개키가 특정한 사람의 공개키라는 것을 어떻게 보장할 수 있는지에 대한 이슈도 존재한다.
36 | 
37 | 이를 해결하기 위해 디지털 인증서를 도입했고 이를 활용하는 소프트웨어, 하드웨어, 정책, 제도, 사용자 등을 총칭해서 공개키 기반 구조라고 한다.
38 | 
39 | <img src="https://user-images.githubusercontent.com/33534771/75338621-5e7f5100-58d2-11ea-8722-be41d86e0a42.png" width="60%"/>
40 | 
41 | 
42 | 
43 | ### 참고
44 | 
45 | - [공개 키 암호방식이란?](https://blog.voidmainvoid.net/317)
46 | - [규글님의 레포지토리](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Network/%EB%8C%80%EC%B9%AD%ED%82%A4%20%26%20%EA%B3%B5%EA%B0%9C%ED%82%A4.md)
47 | 
48 | 
49 | 


--------------------------------------------------------------------------------
/Network/로드 밸런싱.md:
--------------------------------------------------------------------------------
 1 | ## 로드 밸런싱
 2 | 
 3 | >  둘 이상의 CPU or 저장 장치와 같은 컴퓨터 자원들에게 작업을 나누는 것
 4 | 
 5 | 
 6 | 
 7 | 요즘 시대에는 웹사이트에 접속하는 인원이 급격하게 늘어나게 되었다.
 8 | 
 9 | 따라서 이 사람들에 대해 모든 트래픽을 감당하기엔 1대의 서버로는 부족하다.
10 | 
11 | 대응 방안으로 하드웨어의 성능을 올리거나(**Scale-up**) 여러대의 서버가 나눠서 일하도록 만드는 것(**Scale-out**)이 있다.
12 | 
13 | 하드웨어 향상 비용이 더욱 비싸기도 하고, 서버가 여러 대 존재하면 무중단 서비스를 제공하는 환경 구성이 용이하므로 `Scale-out`이 효과적이다. 
14 | 
15 | 이때, 여러 서버에게 균등하게 트래픽을 분산시켜주는 것이 바로 **로드 밸런싱**이다.
16 | 
17 | 
18 | 
19 | > Scale-up : Server가 더 빠르게 동작하기 위해 하드웨어의 성능을 올리는 방법.
20 | >
21 | > Scale-out : 하나의 Server보다는 여러 대의 Server가 나눠서 일을 하는 방법.
22 | 
23 | 
24 | 
25 | ### 로드 밸런서가 서버를 선택하는 방식
26 | 
27 | - 라운드 로빈 : CPU 스케줄링의 라운드 로빈 방식 활용
28 | - Least Connections : 연결 갯수가 가장 적은 서버 선택(트래픽으로 인해 세션이 길어지는 경우 권장)
29 | - Source : 사용자 IP를 해싱하여 분배(특정 사용자가 항상 같은 서버로 연결되는 것을 보장)
30 | 
31 | 
32 | 
33 | ### 로드 밸런서 장애 대비
34 | 
35 | 서버를 분배하는 로드 밸런서에 문제가 생길 수 있기 때문에 로드 밸런서를 이중화하여 대비한다.
36 | 
37 | - Active 상태
38 | - Passive 상태
39 | 
40 | 
41 | 
42 | ### 참고 - 조금 더 깊게 보면 좋은 내용들
43 | 
44 | [로드 밸런서(Load Balancer)란?](https://nesoy.github.io/articles/2018-06/Load-Balancer)
45 | 
46 | 


--------------------------------------------------------------------------------
/Network/주소창에 naver.com을 치면 일어나는 일.md:
--------------------------------------------------------------------------------
 1 | ### 주소창에 naver.com을 치면 일어나는 일
 2 | 
 3 | 면접 질문에서도 종종 나오는 방식이다. 이해하기 전에 IP 주소와 도메인에 대한 사전 지식이 필요하다.
 4 | 
 5 | 
 6 | 
 7 | #### IP 주소
 8 | 
 9 | - IP 주소란 많은 컴퓨터들이 인터넷 상에서 서로를 인식하기 위해 지정받은 식별용 번호라고 생각하면 된다.
10 | - 현재는 IPv4 버전(32비트)로 구성되어 있으며, 한번씩은 들어봤을 법한 127.0.0.1 같은 주소를 말한다.
11 | - 시간이 갈수록 IPv4 주소의 부족으로 IPv6가 생겼는데, 128비트로 구성되어 있기 때문에 IP 주소가 부족하지 않다는 특징이 있다.
12 | 
13 | 
14 | 
15 | #### 도메인 네임(Domain Name)
16 | 
17 | - IP 주소는 12자리의 숫자로 되어 있기 때문에 사람이 외우기 힘들다는 단점이 있다.
18 | - 그렇기 때문에 12자리의 IP 주소를 문자로 표현한 주소를 **도메인 네임**이라고 한다.
19 | - 다시 말해서, 도메인 네임은 'naver.com'처럼 몇 개의 의미있는 문자들과 .의 조합으로 구성된다.
20 | - 도메인 네임은 사람의 편의성을 위해 만든 주소이므로 실제로는 컴퓨터가 이해할 수 있는 IP 주소로 변환하는 작업이 필요하다.
21 | - 이때, 사용할 수 있도록 미리 도메인 네임과 함께 해당하는 IP 주소값을 한 쌍으로 저장하고 있는 데이터베이스를 **DNS(Domain Name System)** 이라고 부른다.
22 | - **도메인 네임으로 입력하면 DNS를 이용해 컴퓨터는 IP 주소를 받아 찾아갈 수 있다.**
23 | 
24 | 
25 | 
26 | #### 작동 방식
27 | 
28 | <img src="https://t1.daumcdn.net/cfile/tistory/99F099375C124B2D02" alt="img" style="zoom:67%;" />
29 | 
30 | 1. 사용자가 브라우저에 도메인 네임(www.naver.com)을 입력한다.
31 | 2. 사용자가 입력한 URL 주소 중에서 도메인 네임(Domain Name) 부분을 DNS 서버에서 검색하고, DNS 서버에서 해당 도메인 네임에 해당하는 IP 주소를 찾아 사용자가 입력한 URL 정보와 함께 전달한다.
32 | 3. 페이지 URL 정보와 전달받은 IP 주소는 HTTP 프로토콜을 사용하여 HTTP 요청 메시지를 생성하고, 이렇게 생성된 HTTP 요청 메시지는 TCP 프로토콜을 사용하여 인터넷을 거쳐 해당 IP 주소의 컴퓨터로 전송된다.
33 | 4. 이렇게 도착한 HTTP 요청 메시지는 HTTP 프로토콜을 사용하여 웹 페이지 URL 정보로 변환되어 웹 페이지 URL 정보에 해당하는 데이터를 검색한다.
34 | 5. 검색된 웹 페이지 데이터는 또 다시 HTTP 프로토콜을 사용하여 HTTP 응답 메시지를 생성하고 TCP 프로토콜을 사용하여 인터넷을 거쳐 원래 컴퓨터로 전송된다.
35 | 6. 도착한 HTTP 응답 메시지는 HTTP 프로토콜을 사용하여 웹 페이지 데이터로 변환되어 웹 브라우저에 의해 출력되어 사용자가 볼 수 있게 된다.
36 | 
37 | 
38 | 
39 | 이렇게 말하면 어느 정도 설명할 수 있지만, 뭔가 부족하다. 조금 더 알아보자.
40 | 
41 | 
42 | 
43 | #### DHCP & ARP
44 | 
45 | 대부분의 가정집에서는 `DHCP`로 인터넷 접속을 하고 있다. DHCP는 Dynamic Host Configuration Protocol의 약자로, 호스트의 IP 주소 및 TCP / IP 설정을 클라이언트에 자동으로 제공하는 프로토콜이다. 사용자의 PC는 DHCP 서버에서 **사용자 자신의 IP 주소, 가장 가까운 라우터의 IP 주소, 가장 가까운 DNS 서버의 IP 주소**를 받는다. 이후, ARP 프로토콜을 이용하여 IP 주소를 기반으로 가장 가까운 라우터의 MAC 주소를 알아낸다.
46 | 
47 | 
48 | 
49 | ![img](https://t1.daumcdn.net/cfile/tistory/267BCC405870914920)
50 | 
51 | > DHCP 서버의 동작 개념도 - 클라이언트가 인터넷 접속을 시도하면 IP와 기본 정보를 제공해준다. 
52 | 
53 | 
54 | 
55 | #### IP 정보 수신
56 | 
57 | 위의 과정을 통해 외부와 통신할 준비를 마쳤으므로, DNS Query를 DNS 서버에 전송한다. DNS 서버는 이에 대한 결과로 웹 서버의 IP 주소를 사용자 PC에 돌려준다. DNS 서버가 도메인에 대한 IP 주소를 송신하는 과정은 약간 복잡하다.
58 | 
59 | 
60 | 
61 | > 과정 (www.naver.com 이라고 가정하자.)
62 | 
63 | 사용자의 PC는 가장 먼저 지정된 DNS 서버(우리나라의 경우, 통신사별로 지정된 DNS 서버가 있다.)에 DNS Query를 송신한다. 그 후 지정된 DNS 서버는 **Root 네임서버**에 www.naver.com을 질의하고, Root 네임서버는 .com 네임서버의 ip 주소를 알려준다. 
64 | 
65 | 
66 | 
67 | 그 후 **.com 네임서버**에 www.naver.com을 질의하면 naver.com 네임서버의 ip 주소를 받고 그곳에 질의를 또 송신하면 www.naver.com의 IP 주소를 수신하게 된다.
68 | 
69 | 
70 | 
71 | 이와 같이 여러번 왔다갔다 하는 이유는, 도메인의 계층화 구조에 따라 DNS 서버도 계층화 되어있기 때문이다. 이렇게 계층화되어 있으므로 도메인의 가장 최상단, 즉 가장 뒷쪽(.com, .kr 등등)을 담당하는 DNS 서버는 전세계에 13개 뿐이다.
72 | 
73 | 
74 | 
75 | 
76 | 
77 | #### 웹 서버 접속
78 | 
79 | 이제 웹 서버의 IP 주소까지 알았다. Http Request를 위헤 TCP Socket을 개방하고 연결한다. 이 과정에서 3-way hand shaking 과정이 일어난다. TCP 연결에 성공하면, Http Request가 TCP Socket을 통해 보내진다. 이에 대한 응답으로 웹 페이지의 정보가 사용자의 PC로 들어온다.
80 | 
81 | 
82 | 
83 | 
84 | 
85 | 
86 | 
87 | 
88 | 
89 | ### 참고
90 | 
91 | - [[Network\] 주소창에 www.naver.com을 치면 일어나는 일](https://sophia2730.tistory.com/entry/DNS-주소창에-wwwnavercom을-치면-일어나는-일)
92 | - [IT 기술면접 준비자료 당신이 브라우저로 웹사이트에 접속할 때 일어나는 일들 (부제: DNS 이야기)](https://preamtree.tistory.com/35)
93 | - [브라우저로 웹 사이트에 접속할 때 과정]([https://godsenal.github.io/2018/07/17/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EB%A1%9C-%EC%9B%B9-%EC%82%AC%EC%9D%B4%ED%8A%B8%EC%97%90-%EC%A0%91%EC%86%8D%ED%95%A0-%EB%95%8C-%EA%B3%BC%EC%A0%95/](https://godsenal.github.io/2018/07/17/브라우저로-웹-사이트에-접속할-때-과정/))
94 | 
95 | 
96 | 
97 | 


--------------------------------------------------------------------------------
/Operating System/CPU 스케줄링.md:
--------------------------------------------------------------------------------
  1 | ### CPU 스케줄링
  2 | 
  3 | CPU가 하나의 프로세스 작업이 끝나면 다음 프로세스 작업을 수행해야 한다. 이때 어떤 프로세스를 다음에 처리할 지 선택하는 알고리즘을 CPU Scheduling 알고리즘이라고 한다. 따라서 상황에 맞게 CPU를 어떤 프로세스에 배정하여 효율적으로 처리하는가가 관건이다.
  4 | 
  5 | 
  6 | 
  7 | ### Preemptive vs Non-Preemptive
  8 | 
  9 | 1) Preemptive(선점)
 10 | 
 11 | - 프로세스가 CPU를 점유하고 있는 동안 I/O나 인터럽트가 발생하지 않았음에도 다른 프로세스가 해당 CPU를 강제로 점유할 수 있다. 
 12 | - 즉, 프로세스가 정상적으로 수행중인 동안 다른 프로세스가 CPU를 강제로 점유하여 실행할 수 있다.
 13 | 
 14 | 
 15 | 
 16 | 2) Non-Preemptive(비선점)
 17 | 
 18 | - 한 프로세스가 CPU를 점유했다면 I/O나 인터럽트 발생 또는 프로세스가 종료될 때까지 다른 프로세스가 CPU를 점유하지 못하는 것이다. 
 19 | 
 20 | 
 21 | 
 22 | 
 23 | 
 24 | ### 선점형 스케줄링
 25 | 
 26 | 1) SRT(Shortest Remaining Time) 스케줄링
 27 | 
 28 | - 짧은 시간 순서대로 프로세스를 수행한다.
 29 | - 현재 CPU에서 실행 중인 프로세스의 남은 CPU 버스트 시간보다 더 짧은 CPU 버스트 시간을 가지는 프로세스가 도착하면 CPU가 선점된다.
 30 | 
 31 | 2) Round Robin 스케줄링
 32 | 
 33 | - 시분할 시스템의 성질을 활용한 방법
 34 | - 일정 시간을 정하여 하나의 프로세스가 이 시간동안 수행하고 다시 대기 상태로 돌아간다.
 35 | - 그리고 다음 프로세스 역시 같은 시간동안 수행한 후, 대기한다. 이러한 작업을 모든 프로세스가 돌아가면서 진행하며, 마지막 프로세스가 끝나면 다시 처음 프로세스로 돌아와서 작업을 반복한다.
 36 | - 일정 시간을 Time Quantum(Time Slice)라고 부른다. 일반적으로 10 ~ 100msec 사이의 범위를 갖는다.
 37 | - 한 프로세스가 종료되기 전에 time quantum이 끝나면 다른 프로세스에게 CPU를 넘겨주기 때문에 선점형 스케줄링의 대표적인 예시다.
 38 | 
 39 | 3) Multi-level Queue 스케줄링
 40 | 
 41 | - 프로세스를 그룹으로 나누어, 각 그룹에 따라 Ready Queue(준비 큐)를 여러 개 두며, 각 큐마다 다른 규칙을 지정할 수도 있다.(ex. 우선순위, CPU 시간 등)
 42 | - 즉, 준비 큐를 여러 개로 분할해 관리하는 스케줄링 방법이다.
 43 | - 프로세스들이 CPU를 기다리기 위해 한 줄로 서는 게 아니라 여러 줄로 선다.
 44 | 
 45 | ![img](https://user-images.githubusercontent.com/34755287/53879673-5e979880-4052-11e9-9f9b-e8bfec7c9be6.png)
 46 | 
 47 | 4) Multi-level feedback Queue 스케줄링
 48 | 
 49 | - 기본 개념은 Multi-level Queue와 동일하나, 프로세스가 하나의 큐에서 다른 큐로 이동 가능하다는 점이 다르다.
 50 | 
 51 | ![img](https://user-images.githubusercontent.com/34755287/53879675-5f302f00-4052-11e9-86a2-c02ee03bac64.png)
 52 | 
 53 | - 위 그림에서 모든 프로세스는 가장 위의 큐에서 CPU의 점유를 대기한다. 이 상태로 진행하다가 이 큐에서 기다리는 시간이 너무 오래 걸린다면 **아래의 큐로 프로세스를 옮긴다.** 이와 같은 방식으로 대기 시간을 조정할 수 있다. 
 54 | - 만약, 우선순위 순으로 큐를 사용하는 상황에서 우선순위가 낮은 아래의 큐에 있는 프로세스에서 starvation 상태가 발생하면 이를 우선순위가 높은 위의 큐로 옮길 수도 있다.
 55 | - 대부분의 상용 운영체제는 여러 개의 큐를 사용하고 각 큐마다 다른 스케줄링 방식을 사용한다. 프로세스의 성격에 맞는 스케줄링 방식을 사용하여 최대한 효율을 높일 수 있는 방법을 선택한다.
 56 | 
 57 | 
 58 | 
 59 | ### 비선점형 스케줄링
 60 | 
 61 | 1) FCFS(First Come First Server)
 62 | 
 63 | - 준비 큐에 먼저 도착한 프로세스가 먼저 CPU를 점유하는 방식이다.
 64 | - CPU를 할당받으면 CPU 버스트가 완료될 때까지 CPU를 반환하지 않으며, 할당되었던 CPU가 반환될 때만 스케줄링이 이루어진다.
 65 | 
 66 | <img src="https://user-images.githubusercontent.com/33534771/89703489-500b8a00-d986-11ea-9b6c-27cca4ea1016.png" width="300" height="300"/>
 67 | 
 68 | ![img](https://user-images.githubusercontent.com/34755287/53879661-5d666b80-4052-11e9-8453-bad918a563ef.png)
 69 | 
 70 | 표는 3개의 프로세스와 각 프로세스가 CPU를 사용한 시간(Burst Time)을 나타낸다.
 71 | 
 72 | 이를 간트 차트로 표현하면 그림과 같다. (도착 시간은 모두 0초라고 가정한다.)
 73 | 
 74 | 평균 대기 시간은 아래와 같다.
 75 | 
 76 | - Average Waiting Time = 0 + 24 + 27 / 3 = 17msec
 77 | 
 78 | 만약, 프로세스가 들어온 순서가 P3, P2, P1이라면 간트 차트는 아래와 같이 바뀐다.
 79 | 
 80 | ![img](https://user-images.githubusercontent.com/34755287/53879665-5d666b80-4052-11e9-8ad5-8639b73b13ac.png)
 81 | 
 82 | - Average Waiting Time = 3 + 6 + 0 / 3 = 3msec
 83 | 
 84 | 두 경우에서 모든 프로세스가 끝난 시간은 30msec로 같지만, 평균 대기 시간으로 봤을 때는 위의 예제는 17msec이고 아래는 3msec로 차이가 난다. **즉, 들어온 순서로 수행한다고 해서 반드시 효율적인 것은 아니다.**
 85 | 
 86 | 위의 예제처럼 `P1, P2, P3` 순서로 들어온 경우를 **Convoy Effect** 라고 한다. 
 87 | 
 88 | 이는 CPU 시간을 오래 사용하는 프로세스가 먼저 수행되는 동안 나머지 프로세스들은 그만큼 오래 기다리는 것을 뜻한다. P1이 수행되는 동안 P2, P3는 오래 기다리게 된다. 
 89 | 
 90 | 단점
 91 | 
 92 | - Convoy Effect 발생 : 소요 시간이 긴 프로세스가 짧은 프로세스보다 먼저 도착해서 뒤에 프로세스들이 오래 기다려야 하는 현상
 93 | 
 94 | 
 95 | 
 96 | 2) SJF(Shortest-Job-First)
 97 | 
 98 | - 다른 프로세스가 먼저 도착했더라도 CPU 버스트가 짧은 프로세스에게 CPU를 먼저 할당하는 방식이다.
 99 | - 선점, 비선점 모두 가능하다.
100 | 
101 | <img src="https://user-images.githubusercontent.com/33534771/89703540-b7293e80-d986-11ea-9b11-0dabd8e5488f.png" width="300" height="300"/>
102 | 
103 | ![img](https://user-images.githubusercontent.com/34755287/53879666-5d666b80-4052-11e9-93c2-86b725588403.png)
104 | 
105 | 위의 간트 차트는 SJF를 사용했다. 평균 대기 시간은 아래와 같다.
106 | 
107 | - Average Waiting Time(AWT) = 3 + 9 + 16 + 0 / 4 = 7msec
108 | 
109 | 이번에는 위의 표를 FCSF를 사용해 간트 차트로 나타내고 평균 대기 시간을 구해보자.
110 | 
111 | ![img](https://user-images.githubusercontent.com/34755287/53879667-5d666b80-4052-11e9-8cd4-066aefcf3047.png)
112 | 
113 | - Average Waiting Time(AWT) = 0 + 6 + 14 + 21 / 4 = 10.25msec
114 | 
115 | SJF가 평균 대기 시간이 더 짧다. 수학적으로 증명되었으며, 어떠한 예제를 보더라도 SJF의 AWT가 짧다는 것을 알 수 있을 것이다. 
116 | 
117 | 
118 | 
119 | SJF가 가장 효율적인 CPU 스케줄링 방법 같지만, 매우 **비현실적**이다. 왜냐하면 컴퓨터 환경에서는 프로세스의 CPU 점유 시간(Burst time)을 알 수 없다. 한 프로세스가 실행 중에는 많은 변수가 존재하기 때문에 CPU 점유 시간을 알려면 실제로 수행하여 측정하는 수밖에 없다. 실제 측정한 시간으로 예측하여 SJF를 사용할 수도 있지만, 이는 오버헤드가 매우 큰 작업으로 잘 사용되지 않는다.
120 | 
121 | 
122 | 
123 | 3) Priority
124 | 
125 | - 우선순위가 높은 프로세스가 먼저 선택되는 스케줄링 알고리즘이다.
126 | - 우선순위는 정수값으로 나타내며, 작은 값이 우선순위가 높다.(Unix/Linux 기준)
127 | 
128 | - 선점, 비선점 모두 가능하다.
129 | 
130 | <img src="https://user-images.githubusercontent.com/33534771/89703556-e344bf80-d986-11ea-87f1-74994cc47510.png" width="300" height="300"/>
131 | 
132 | ![img](https://user-images.githubusercontent.com/34755287/53879671-5e979880-4052-11e9-84d3-524270cdc920.png)
133 | 
134 | 우선순위가 낮은 순서대로 수행한 모습을 간트 차트로 나타냈다.
135 | 
136 | - Average Waiting Time(AWT) : 0 + 6 + 16 + 18 + 1 / 5 = 8.2msec
137 | 
138 | 우선순위를 정하는 방법은 크게 내부적인 요소와 외부적인 요소로 나뉜다.
139 | 
140 | - Internal : time limit, memory requirement, I/O to CPU burst(I/O 작업은 길고, CPU 작업은 짧은 프로세스 우선) 등
141 | - External : amout of funds being paid, political factors 등
142 | 
143 | 
144 | 
145 | - 단점 : Starvation(기아) 현상
146 | 
147 | CPU의 점유를 오랜 시간 동안 하지 못하는 현상을 의미한다. Priority 스케줄링 방식에서 우선순위가 매우 낮은 프로세스가 ready queue에서 대기하고 있다고 가정해보자.
148 | 
149 | 이 프로세스는 아무리 오래 기다려도 CPU를 점유하지 못할 가능성이 매우 크다. 실제 컴퓨터 환경에서는 새로운 프로세스가 자주 ready queue에 들어온다. 이러한 프로세스가 모두 우선순위가 높은 상태라면 이미 기다리고 있던 우선순위가 낮은 프로세스는 하염없이 기다리고만 있는 상태로 남아있을 수 있다. 
150 | 
151 | 
152 | 
153 | 이를 해결하는 방법 중 하나는 **aging**이 있다. ready queue에서 기다리는 동안 일정 시간이 지나면 우선 순위를 일정량 높여주는 것이다. 그러면 우선순위가 매우 낮은 프로세스라 하더라도, 기다리는 시간이 길어질수록 우선순위도 계속 높아지므로 수행될 가능성이 커진다.
154 | 
155 | 
156 | 
157 | 
158 | 
159 | 
160 | 
161 | ### Reference
162 | 
163 | - [운영체제(OS) 6. CPU 스케줄링](https://velog.io/@codemcd/%EC%9A%B4%EC%98%81%EC%B2%B4%EC%A0%9COS-6.-CPU-%EC%8A%A4%EC%BC%80%EC%A4%84%EB%A7%81)
164 | 


--------------------------------------------------------------------------------
/Operating System/Context Switching.md:
--------------------------------------------------------------------------------
 1 | **Q. Context Switching이란?**
 2 | 
 3 | - CPU는 한번에 하나의 프로세스만 처리할 수 있다.
 4 | - 여러 프로세스를 처리해야 하는 상황에서 현재 진행중인 Task(프로세스, 스레드)의 상태를 PCB에 저장하고 다음에 진행할 Task의 상태값을 읽어 적용하는 과정을 말한다. (**다른 프로세스에게 CPU를 할당해 작업을 수행하는 과정을 말한다.**)
 5 | - 과정
 6 |   - Task의 대부분 정보는 Register에 저장되고 PCB로 관리된다.
 7 |   - 현재 실행하고 있는 Task의 PCB 정보를 저장한다.
 8 |   - 다음 실행할 Task의 PCB 정보를 읽어 Register에 적재하고 CPU가 이전에 진행했던 과정을 연속적으로 수행할 수 있다.
 9 | - Context Switching은 많은 비용이 소모된다.
10 |   - Cache 초기화
11 |   - Memory mapping 초기화
12 |   - 커널은 항상 실행되어야 한다.
13 | - Context Switching의 비용은 프로세스가 스레드보다 더 많이 든다.
14 | - 이유 : 스레드는 Stack 영역을 제외한 모든 메모리를 공유하기 때문에 Context Switching 발생시 Stack 영역만 변경을 진행하면 되기 때문이다.


--------------------------------------------------------------------------------
/Operating System/IPC(Inter Process Communication).md:
--------------------------------------------------------------------------------
 1 | ### IPC(Inter Process Communication)
 2 | 
 3 | ![img](https://camo.githubusercontent.com/39947826ff6c0138a468fd6a5d7cb5ee70737397/68747470733a2f2f74312e6461756d63646e2e6e65742f6366696c652f746973746f72792f393944423843343935433443353730343137)
 4 | 
 5 | - 프로세스는 독립적으로 실행된다. 이는 다른 프로세스에게 영향을 받지 않는다는 뜻이기도 하다. (스레드는 프로세스 안에서 자원을 공유하므로 영향을 받는다.)
 6 | 
 7 | - 이처럼 독립적인 공간을 가진 프로세스간 통신에 사용되는 기법이 IPC 통신이다.
 8 | - 프로세스는 커널이 제공하는 IPC 설비를 이용해 프로세스간 통신을 할 수 있게 된다.
 9 | 
10 | 
11 | 
12 | 
13 | ### Reference
14 | 
15 | - [규글님 - IPC](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Operation%20System/IPC(Inter%20Process%20Communication).md)
16 | 


--------------------------------------------------------------------------------
/Operating System/PageReplacement.md:
--------------------------------------------------------------------------------
  1 | ### 페이지 교체 알고리즘
  2 | 
  3 | 
  4 | 
  5 | - 가상 메모리는 `요구 페이징 기법`을 통해 필요한 페이지만 메모리에 적재하고 사용하지 않는 부분은 그대로 둔다.
  6 | - 하지만, 필요한 페이지만 올리더라도 메모리는 결국 가득 차게 되고, 올라와있던 페이지가 사용이 다 된 후에도 자리만 차지하고 있을 수 있다.
  7 | - 메모리가 가득차면, 추가로 페이지를 가져오기 위해서 안쓰는 페이지는 out하고 해당 공간에 현재 필요한 페이지를 in 시켜야 한다. 이때, 어떤 페이지를 out 시킬지 정해야 한다. 
  8 | - 수정이 되지 않는 페이지를 선택해야 좋다. 만약, 수정되면 메인 메모리에서 내보낼 때, 하드디스크에서 또 수정해야 하므로 시간이 오래걸린다.
  9 | - 이러한 상황에서 적절한 페이지 교체를 위해 페이지 교체 알고리즘이 존재한다.
 10 | 
 11 | 
 12 | 
 13 | ### 가상 메모리
 14 | 
 15 | - 운영체제는 모든 프로그램에게 같은 크기의 메모리를 할당하지 않고 몇몇 프로그램에게 집중적으로 메모리를 할당한 후, 시간이 흐르면 이들에게서 메모리를 회수하여 다른 프로그램들에게 다시 집중적으로 할당하는 방식을 사용한다.
 16 | - CPU를 할당받아 당장 수행해야 할 부분만 메모리에 올려놓고 그렇지 않은 부분은 디스크의 스왑 영역에 내려놓았다가 다시 필요해지만 메모리에 올라가 있는 부분과 교체하는 방식을 사용한다. 이를 통해 프로그램이 자기 자신만 메모리를 사용하는 것과 같은 효과를 낸다.
 17 | - 가상 메모리는 프로세스마다 각각 0번지부터 시작하는 자기 자신만의 주소 공간을 가지게 되며, 이들 공간 중 일부는 물리적 메모리에 적재되고 일부는 디스크의 스왑 영역에 적재된다. -> **요구 페이징 기법**
 18 | 
 19 | 
 20 | 
 21 | **[요구 페이징]**
 22 | 
 23 | - 가상 메모리는 요구 페이징 기법을 통해 필요한 페이지만 메모리에 적재하고 사용하지 않는 부분은 그대로 둔다.
 24 | - 특정 페이지에 대해 CPU의 요청이 들어온 후에야 해당 페이지를 메모리에 적재하며, 한번도 접근되지 않은 페이지는 물리적 메모리에 적재되지 않는다.
 25 | - 이를 통해 메모리 사용량이 감소하고 프로세스 전체를 메모리에 올리는데 들었던 입출력 오버헤드가 감소하며 응답시간이 단축된다.
 26 | - 유효, 무효 비트를 두어 각 페이지가 메모리에 존재하는지 표시한다.
 27 |   - 유효 : 페이지가 메모리에 적재됨.
 28 |   - 무효 : 페이지가 현재 메모리에 없는 경우이거나 그 페이지가 속한 주소 영역을 프로세스가 사용하지 않는 경우
 29 | - CPU가 참조하려는 페이지가 현재 메모리에 올라와 있지 않아 **무효**로 세팅되어 있는 경우를 `'페이지 부재'`가 일어났다고 한다.
 30 | 
 31 | 
 32 | 
 33 | **[페이지 교체]**
 34 | 
 35 | - 페이지 부재가 발생하면 요청된 페이지를 디스크에서 메모리로 읽어와야 한다. 이때 물리적 메모리에 빈 프레임이 존재하지 않을 수 있다.
 36 | - 이 경우, 메모리에 올라와있는 페이지 중 하나를 디스크로 쫓아내고 메모리에 빈 공간을 확보하는 작업이 필요하다. 이를 페이지 교체라고 한다.
 37 | - 페이지 교체를 할 때, 어떤 프레임에 있는 페이지를 쫓아낼 것인지 결정하는 알고리즘을 페이지 교체 알고리즘이라 하며, 목표는 페이지 부재율을 최소화하는 것이다. 
 38 | 
 39 | <u>*페이지 부재 발생 -> 새로운 페이지를 할당해야 한다. -> 현재 할당된 페이지(메모리에 올라와있는 페이지) 중 어떤 것을 교체할지 결정하는 방법*</u>
 40 | 
 41 | 
 42 | 
 43 | ### 페이지 교체 알고리즘
 44 | 
 45 | 1) FIFO(First in First out) 알고리즘
 46 | 
 47 | - 페이지 교체시 메모리에 먼저 올라온 페이지를 먼저 내보내는 알고리즘
 48 | - 가장 간단한 방법으로, 특히 초기화 코드에서 적절한 방법이다. 
 49 | - 단점
 50 |   - 페이지의 향후 참조 가능성을 고려하지 않고, 물리적 메모리에 들어온 순서대로 내쫓을 대상을 선정하기 때문에 비효율적인 상황이 발생할 수 있다.
 51 |   - 빌레이디의 모순 현상이 발생할 수 있다. (페이지 프레임 수가 많으면(메모리 증가) 페이지 부재수가 줄어드는 것이 일반적이지만, 페이지 프레임 수를 증가시켰음에도 페이지 부재가 더 많이 일어나는 현상을 의미한다.)
 52 | 
 53 | ![img](https://camo.githubusercontent.com/250c0a33495ccda3dcaaa1c2b4d79ec22bf07da3/68747470733a2f2f696d67312e6461756d63646e2e6e65742f7468756d622f523132383078302f3f73636f64653d6d746973746f727926666e616d653d68747470732533412532462532466b2e6b616b616f63646e2e6e6574253246646e253246565143474b253246627471754a7571526b79532532464c62334e6777486b427665303859685a704c6b713331253246696d672e706e67)
 54 | 
 55 | 
 56 | 
 57 | 2) 최적 페이지 교체 알고리즘(Optimal Page Replacement)
 58 | 
 59 | - 앞으로 가장 오랫동안 사용하지 않은 페이지를 교체하는 방법
 60 | - 미래에 어떤 페이지가 어떠한 순서로 참조될지 미리 알고있다는 전제하에 알고리즘을 운영하므로 현실적으로 구현이 어렵다.
 61 | - 페이지 부재율이 가장 낮은 효율적인 알고리즘이다.
 62 | 
 63 | ![img](https://t1.daumcdn.net/cfile/tistory/265B26335916A03F39)
 64 | 
 65 | 
 66 | 
 67 | 3) LRU 알고리즘(Least Recently Used)
 68 | 
 69 | - 최근에 사용하지 않은 페이지를 가장 먼저 내보내는 방법
 70 | - 최근에 사용하지 않았으면, 나중에도 사용되지 않을 것이라는 아이디어에서 나왔다.
 71 | - OPT의 경우 미래 예측이지만, LRU의 경우는 과거를 보고 판단하므로 실질적으로 사용이 가능한 알고리즘 (실제로도 최근에 사용하지 않은 페이지는 앞으로도 사용하지 않을 확률이 높다.)
 72 | - OPT보다는 페이지 결함이 더 일어날 수 있지만, **실제로 사용할 수 있는 페이지 교체 알고리즘에서는 가장 좋은 방법 중 하나이다.**
 73 | 
 74 | ![img](https://camo.githubusercontent.com/3da1359d56b8c12c4da96d937554b8375d0cac1f/68747470733a2f2f696d67312e6461756d63646e2e6e65742f7468756d622f523132383078302f3f73636f64653d6d746973746f727926666e616d653d68747470732533412532462532466b2e6b616b616f63646e2e6e6574253246646e2532466e43676333253246627471754757395655726d25324678544b6e564b504f56517553586d4175526568537731253246696d672e706e67)
 75 | 
 76 | 
 77 | 
 78 | 4) LFU 알고리즘(Least Frequently Used) 
 79 | 
 80 | - 페이지의 참조 횟수로 교체할 페이지를 결정하는 방법
 81 | - 즉, 물리적 메모리 내에 존재하는 페이지 중에서 과거에 참조 횟수가 가장 적었던 페이지를 내쫓고 그 자리에 새로 참조될 페이지를 적재한다.
 82 | - 단점
 83 |   - 시간에 따른 페이지 참조의 변화를 반영하지 못하고 LRU보다 구현이 복잡하다.
 84 | 
 85 | - LRU, LFU 알고리즘은 페이지의 최근 참조 시각 및 참조 횟수를 소프트웨어적으로 유지해야 하므로 알고리즘의 운영에 오버헤드가 발생한다.
 86 | 
 87 | 5) 클럭 알고리즘(NRU : Not Recently Used, NUR : Not Used Recently)
 88 | 
 89 | - 하드웨어적인 지원을 받아 LRU와 LFU 알고리즘에서 발생한 시간적인 오버헤드를 줄인 방식이다.
 90 | - LRU를 근사시킨 알고리즘이라고 하며, 오랫동안 사용하지 않은 페이지 중 하나를 교체한다.
 91 | - 최근에 참조되지 않은 페이지를 교체 대상으로 선정하는 측면에서 LRU와 비슷하지만 교체되는 페이지의 참조 시점이 가장 오래됐다는 것을 보장하지 못한다.
 92 | - 참조 비트(Reference Bit)와 변형 비트(Modified Bit, Dirty Bit)를 사용한다.
 93 |   - 참조 비트
 94 |     - 페이지가 참조될 때, 1로 자동 세팅된다. 
 95 |     - 페이지가 참조되지 않았을 때는 0이 되며 페이지는 교체한다.
 96 |   - 변형 비트
 97 |     - 페이지 내용이 변경되었을 때, 1로 지정한다.
 98 |     - 페이지 내용이 변경되지 않았을 때는 0으로 지정한다.
 99 | 
100 | - 이 알고리즘은 하드웨어의 자원으로 동작하기 때문에 LRU에 비해 교체 페이지의 선정이 훨씬 빠르게 결정된다.
101 | - 따라서 대부분의 시스템에서 페이지 교체 알고리즘으로 클럭 알고리즘을 채택한다.
102 | 
103 | 
104 | 
105 | ### Reference
106 | 
107 | - [가상메모리-02-페이지 교체 알고리즘](https://eunhyejung.github.io/os/2018/07/24/operatingsystem-study15.html)
108 | - [규글님 - 페이지 교체 알고리즘](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Operation%20System/Page%20Replacement%20Algorithm.md)
109 | 


--------------------------------------------------------------------------------
/Operating System/교착상태(DeadLock).md:
--------------------------------------------------------------------------------
  1 | ### 교착 상태(DeadLock)
  2 | 
  3 | - 한정된 자원을 여러 곳에서 사용하려고 할 때, 발생하는 문제이다.
  4 | - 즉, 프로세스가 자원을 얻지 못해서 다음 처리를 하지 못하는 상태이다.
  5 | 
  6 | 
  7 | ![img](https://user-images.githubusercontent.com/33534771/87002992-c4230880-c1f5-11ea-8e0e-0bddc09e3f4a.png)
  8 | 
  9 | 프로세스 1과 프로세스2가 모두 자원 1, 자원 2를 얻어야 한다고 가정해보자.
 10 | 
 11 | t1 : 프로세스 1이 자원 1을 얻음 / 프로세스 2가 자원 2를 얻음
 12 | 
 13 | t2 : 프로세스 1은 자원 2를 기다림 / 프로세스 2는 자원 1을 기다림
 14 | 
 15 | 
 16 | 
 17 | 이처럼 현재 서로 원하는 자원이 상대방에게 할당되어 있어서 두 프로세스는 무한정 wait 상태에 빠지게 된다. -> 이러한 상황을 **DeadLock** 이라고 부른다.
 18 | 
 19 | 
 20 | 
 21 | **[주로 발생하는 경우]**
 22 | 
 23 | - 멀티 프로그래밍 환경에서 한정된 자원을 얻기 위해 서로 경쟁하는 상황 발생
 24 | - 한 프로세스가 자원을 요청했을 때, 동시에 그 자원을 사용할 수 없는 상황이 발생할 수 있음. 이때 프로세스는 대기 상태로 들어감
 25 | - 대기 상태로 들어간 프로세스들이 실행 상태로 변경될 수 없을 때, '교착 상태' 발생
 26 | 
 27 | 
 28 | 
 29 | **[교착 상태 발생조건]**
 30 | 
 31 | - 4가지 조건이 동시에 성립할 때, 발생한다
 32 | - 4가지 조건 중 하나라도 성립하지 않는다면 교착 상태를 해결할 수 있다.
 33 | 
 34 | 
 35 | 
 36 | 1) 상호 배제(Mutual Exclusion)
 37 | 
 38 | - 자원은 한 번에 한 프로세스만이 사용할 수 있다.
 39 | 
 40 | 2) 점유 대기(Hold and Wait)
 41 | 
 42 | - 최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 있어야 한다.
 43 | 
 44 | 3) 비선점 (No Preemption)
 45 | 
 46 | - 다른 프로세스에 할당된 자원은 사용이 끝나서 반납할 때까지 강제로 빼앗을 수 없다.
 47 | 
 48 | 4) 순환 대기 (Circular Wait)
 49 | 
 50 | - 프로세스의 집합 {P0, P1, ..., Pn}에서 0은 1이 점유한 자원을 대기하고 1은 2가 점유한 자원을 대기하고 Pn은 P0이 점유한 자원을 요구해야 한다.
 51 | - 이처럼 프로세스의 집합에서 순환 형태로 자원을 대기하고 있어야 한다.
 52 | 
 53 | 
 54 | 
 55 | ### 교착 상태 처리
 56 | 
 57 | 아래와 같은 방법이 존재한다.
 58 | 
 59 | 
 60 | 
 61 | **[교착 상태 예방]**
 62 | 
 63 | - 교착 상태 발생 조건 중 하나를 제거함으로써 해결하는 방법
 64 | - 자원의 낭비가 심하다는 단점이 존재한다.
 65 | 
 66 | 1. 상호 배제 부정
 67 |    여러 프로세스가 공유 자원을 사용하도록 한다.
 68 | 2. 점유 대기 부정
 69 |    프로세스가 실행되기 전 필요한 모든 자원을 할당한다.
 70 | 3. 비선점 부정
 71 |    자원 점유 중인 프로세스가 다른 자원을 요구할 때, 점유 중인 자원을 반납하고 요구한 자원을 사용하기 위해 기다리게 한다.
 72 | 4. 순환 대기 부정
 73 |    자원에 고유한 번호를 할당하고, 번호 순서대로로 자원을 요구하도록 한다.
 74 | 
 75 | 
 76 | 
 77 | **[교착 상태 회피]**
 78 | 
 79 | - 교착 상태가 발생하면 피해나가는 방법
 80 | - 은행원 알고리즘이라고 한다.
 81 | 
 82 | - 다익스트라가 제안한 방법으로 은행에서 모든 고객의 요구가 충족되도록 현금을 할당하는데서 유래된 기법이다. 
 83 | 
 84 | 
 85 | 
 86 | 프로세스가 자원을 요구할 때, 시스템은 자원을 할당한 후에도 안정 상태로 남아있게 되는지를 검사하여 교착 상태를 회피하는 기법이다. 
 87 | 
 88 | 안정 상태에 있으면 자원을 할당하고 그렇지 않으면 다른 프로세스들이 자원을 해제할 때까지 대기한다.
 89 | 
 90 | 
 91 | 
 92 | ![img](https://user-images.githubusercontent.com/33534771/87003104-f6346a80-c1f5-11ea-84f3-d048f1cec0ea.png)
 93 | 
 94 | 
 95 | 
 96 | [교착 상태 탐지]
 97 | 
 98 | - 자원 할당 그래프를 통해 교착 상태를 탐지할 수 있다.
 99 | 
100 | ![img](https://user-images.githubusercontent.com/33534771/87003146-0e0bee80-c1f6-11ea-8d99-d19c46e52324.png)
101 | 
102 | - 프로세스 Pi -> 자원 Rj : 프로세스 P가 자원 R을 요청하는 것으로 현재 이 자원을 기다리는 상태
103 | - 자원 Rj -> 프로세스 Pi : 자원 R이 프로세스 P에 할당된 것을 의미한다.
104 | - 자원을 요청할 때마다 탐지 알고리즘을 실행하므로 오버헤드가 발생한다.
105 | 
106 | 
107 | 
108 | [교착 상태 회복]
109 | 
110 | - 교착 상태를 일으킨 프로세스를 종료하거나 할당된 자원을 해제함으로써 회복하는 것을 의미한다.
111 | 
112 | 1. 프로세스를 종료하는 방법
113 |    - 교착 상태의 프로세스를 모두 중지
114 |    - 교착 상태가 제거될 때까지 한 프로세스씩 중지
115 | 2. 자원을 선점하는 방법
116 |    - 교착 상태의 프로세스가 점유하고 있는 자원을 선점하여 다른 프로세스에게 할당하며, 해당 프로세스를 일시 정지시키는 방법
117 |    - 우선순위가 낮은 프로세스, 수행된 횟수가 적은 프로세스 등을 위주로 프로세스의 자원을 선점한다.
118 | 
119 | 
120 | 
121 | ### 주요 질문
122 | 
123 | - 교착상태가 무엇이고, 발생 조건에 대해 설명해주세요.
124 | - 회피 기법인 은행원 알고리즘이 대해 설명해주세요.
125 | - 기아 상태를 설명하는 '식사하는 철학자 문제'에 대해 설명해주세요.
126 | 
127 | -> 교착 상태 해결책
128 | 
129 | 1. n명이 앉을 수 있는 테이블에서 철학자 n-1명만을 앉게 한다.
130 | 2. 한 철학자가 젓가락 두 개를 모두 집을 수 있는 상황에서만 젓가락을 집도록 허용한다.
131 | 3. 누군가는 왼쪽 젓가락을 먼저 집지 않고 오른쪽 젓가락을 먼저 집도록 허용한다.
132 | 
133 | 
134 | 
135 | ### Reference
136 | - [규글님 DeadLock](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Operation%20System/DeadLock.md)
137 | 


--------------------------------------------------------------------------------
/Operating System/단편화.md:
--------------------------------------------------------------------------------
 1 | ### 단편화
 2 | 
 3 | **[외부 단편화(external fragmentation)]**
 4 | 
 5 | - 프로그램의 크기보다 분할의 크기가 작은 경우, 해당 분할이 비어있음에도 불구하고 프로그램을 적재하지 못하기 때문에 발생하는 메모리 공간을 말한다.
 6 | - 어떤 프로그램에도 배당되지 않은 빈 공간임에도 현재 상태에서 사용될 수 없는 작은 분할이다.
 7 | 
 8 | 
 9 | 
10 | **[내부 단편화(internal fragmentation)]**
11 | 
12 | - 프로그램의 크기보다 분할의 크기가 큰 경우, 해당 분할에 프로그램을 적재하고 남는 메모리 공간을 말한다.
13 | - 즉, 하나의 분할 내부에서 발생하는 사용되지 않는 메모리 조각이다.
14 | - ex) 메모리 자유 분할 공간이 10,000B가 있고 프로세스 A가 9,999B를 사용하게 되면 2B가 남게 된다. 이러한 현상을 내부 단편화라 한다.
15 | 
16 | 
17 | 
18 | **[압축(Compaction)]**
19 | 
20 | - 외부 단편화를 해소하기 위해 프로세스가 사용하는 공간들을 한쪽으로 몰아, 자유 공간을 확보하는 방법론이다.
21 | - 단점 : 작업 효율이 좋지 않다.
22 | 
23 | 
24 | 
25 | **[Swapping]**
26 | 
27 | - 메모리에 올라온 프로세스의 주소 공간 전체를 디스크의 스왑 영역으로 일시적으로 내려놓는 것이다. 메모리 공간을 확보하면 이후에 다른 프로세스의 메모리를 불러 들일 수 있다.
28 | - 주의할 점은 프로세스가 종료되어 주소 공간을 디스크로 내쫓는 것이 아니라 특정한 이유로 수행중인 프로세스의 주소공간을 일시적으로 메모리에서 디스크로 내려놓은 것을 의미한다.
29 |   - 스왑인 : 디스크 -> 메모리
30 |   - 스왑 아웃 : 메모리 -> 디스크
31 | 
32 | 
33 | 
34 | **[연속 할당 방식]**
35 | 
36 | - 각각의 프로세스를 물리적 메모리의 연속적인 공간에 올리는 방식
37 |   1. 고정 분할 방식
38 |      - 물리적 메모리를 주어진 개수만큼의 영구적인 분할로 미리 나누고 각 분할에 하나의 프로세스를 적재하여 실행시키는 방식
39 |      - 단편화 문제 발생
40 |   2. 가변 분할 방식
41 |      - 메모리에 적재되는 프로그램의 크기에 따라 분할의 크기, 개수가 동적으로 변하는 방식
42 |      - 외부 단편화 발생
43 | 
44 | 
45 | 
46 | **[불연속 할당 방식]**
47 | 
48 | - 하나의 프로세스를 물리적 메모리의 여러 영역에 분산하여 적재하는 방식
49 |   1. 페이징 
50 |      - 프로세스를 동일한 크기의 페이지로 나눈다.
51 |      - 내부 단편화 문제
52 |   2. 세그멘테이션
53 |      - 프로세스를 서로 다른 크기의 논리적 블록 단위인 세그멘테이션으로 나눈다.
54 |      - 외부 단편화 문제
55 | 
56 | 


--------------------------------------------------------------------------------
/Operating System/동기와 비동기.md:
--------------------------------------------------------------------------------
 1 | ## 동기와 비동기
 2 | 
 3 | >  동기와 비동기를 비유를 통해 쉽게 설명해보겠다.
 4 | 
 5 | 
 6 | 
 7 | 해야할 일이 빨래, 설거지, 청소 3가지가 있다고 가정하자. 
 8 | 
 9 | - 이 일들을 동기적으로 처리한다면 빨래를 하고 설거지를 한 뒤, 청소를 한다. 
10 | - 비동기적으로 일을 처리한다면 빨래하는 업체에게 빨래를 시킨다. 설거지 대행 업체에 설거지를 시키고, 청소 대행 업체에 청소를 시킨다. 셋 중 어떤 것이 먼저 완료될지는 알 수 없다. 일을 모두 마친 업체는 나에게 알려줄 것이니 나는 다른 작업을 할 수 있다.
11 |   - 이때는 백그라운드 스레드에서 해당 작업을 처리하는 경우의 비동기를 의미한다.
12 | 
13 | 
14 | 
15 | 일반적으로 동기와 비동기의 차이는 메소드를 실행시킴과 동시에 반환 값이 기대되는 경우를 **동기**라고 표현하고 그렇지 않은 경우에 대해서 **비동기**라고 표현한다. "동시에"라는 말은 실행되었을 때 값이 반환되기 전까지는 blocking되어 있다는 것을 의미한다. 비동기의 경우, blocking되지 않고 이벤트 큐에 넣거나 백그라운드 스레드에게 해당 task를 위임하고 바로 다음 코드를 실행하기 때문에 기대되는 값이 바로 반환되지 않는다.
16 | 
17 | 
18 | 
19 | > 비유가 아닌 개념적으로 설명해보자.
20 | 
21 | - 동기(synchronous : 동시에 일어나는)
22 |   - 동시에 일어난다는 뜻이다. 요청과 그 결과가 동시에 일어난다는 약속이다. (blocking)
23 |   - 바로 요청을 하면 시간이 얼마가 걸리던지 요청한 자리에서 결과가 주어져야 한다.
24 |   - 요청과 결과가 한 자리에서 동시에 일어난다.
25 |   - A노드와 B노드 사이의 작업 처리 단위(transaction)를 동시에 맞추겠다.
26 | - 비동기(Asynchronous : 동시에 일어나지 않는)
27 |   - 동시에 일어나지 않는다를 의미한다. 요청과 결과가 동시에 일어나지 않을 것이라는 약속이다. (non-blocking)
28 |   - 요청한 그 자리에서 결과가 주어지지 않는다.
29 |   - 노드 사이의 작업 처리 단위를 동시에 맞추지 않아도 된다.
30 | 
31 | 
32 | 
33 | - 동기 방식은 설계가 매우 간단하고 직관적이지만 결과가 주어질 때까지 아무것도 못하고 대기해야 한다는 단점이 있다. (blocking)
34 | - 비동기 방식은 동기보다 복잡하지만, 결과가 주어지는데 시간이 걸리더라도 그 시간 동안 다른 작업을 할 수 있으므로 자원을 효율적으로 사용할 수 있다는 장점이 있다. (non-blocking)
35 | 
36 | 
37 | 
38 | blocking, non-blocking 글도 참고하기!!
39 | 
40 | ### References
41 | 
42 | - [[OS] 동기와 비동기](https://k39335.tistory.com/34)
43 | - [동기와 비동기의 개념과 차이](https://private.tistory.com/24)
44 | 
45 | 


--------------------------------------------------------------------------------
/Operating System/동기화 문제.md:
--------------------------------------------------------------------------------
  1 | ## 동기화 문제
  2 | 
  3 | - 동기화 : 한정적인 시스템 자원에 여러 스레드가 동시에 접근해서 사용하면 문제가 발생할 수 있다. 이 문제를 방지하기 위해 여러 스레드에게 하나의 자원에 대한 처리 권한을 주거나 순서를 조정하는 기법이다.
  4 | 
  5 | 
  6 | 
  7 | **스레드 동기화**
  8 | 
  9 | 1. 실행 순서의 동기화 : 스레드의 실행 순서를 정의하고, 이 순서를 반드시 따르도록 하는 것.
 10 | 2. 메모리 접근에 대한 동기화
 11 |    - 메모리 접근에 있어서 동시 접근을 막는 것.
 12 |    - 실행의 순서가 중요한 것이 아니라 한 순간에 하나의 스레드만 해당 자원에 접근하도록 하는 것.
 13 | 
 14 | 
 15 | 
 16 | **동기화 기법**
 17 | 
 18 | - 유저 모드의 동기화
 19 |   - 커널의 힘을 빌리지 않는 동기화 기법(커널의 코드가 실행되지 않음.)
 20 |   - 성능상 이점이 있으나 기능상의 제한점이 존재.
 21 |   - 임계 구역 기반의 동기화, 인터락 함수 기반의 동기화.
 22 | - 커널 모드의 동기화
 23 |   - 커널에서 제공하는 동기화 기능을 이용하는 방법.
 24 |   - 커널 모드로의 변경이 필요하고 이는 성능 저하로 이어진다. 그러나 다양한 기능을 활용할 수 있다.
 25 |   - 세마포어, 뮤텍스, 모니터 등등.
 26 | 
 27 | `[유저모드의 동기화]`
 28 | 
 29 | 1. 임계 구역 기반의 동기화.
 30 | 
 31 | - 열쇠를 얻은 프로세스만 임계 구역에 들어갈 수 있다. 즉, 한번에 하나의 스레드만이 접근 가능하다.
 32 | - 임계 구역 진입을 위해 크리티컬 섹션 오브젝트를 얻는다.
 33 | - 다른 스레드가 열쇠를 가지고 있을 시에는 반환할 때까지 블로킹된다. 열쇠가 반환되면 블로킹 상태에서 빠져나와 열쇠를 얻고 임계 구역에 접근한다.
 34 | 
 35 | 
 36 | 
 37 | 2. 인터락 함수 기반의 동기화
 38 | 
 39 | - 함수 내부적으로 한 순간에 하나의 스레드에 의해서만 실행되도록 동기화된다.
 40 | - 임계 구역 기반의 동기화도 내부적으로 인터락 함수를 기반으로 구현된다.
 41 | - 유저 모드 기반으로 동작해서 속도가 빠르다.
 42 | 
 43 | 
 44 | 
 45 | `[커널모드의 동기화]`
 46 | 
 47 | 1. 세마포어(Semaphore)
 48 | 
 49 | - 공유된 자원의 데이터를 여러 프로세스, 스레드가 접근하는 것을 막는 것이다.
 50 | - 동시에 접근할 수 있는 '허용 가능한 갯수'를 가지고 있는 Counter. (공유자원에 접근할 수 있는 스레드 혹은 프로세스의 수를 나타내는 값. -> 공통으로 관리하는 하나의 값)
 51 | - Ex)
 52 |   - 화장실을 예로 들어보자. 세마포어는 1개 이상의 열쇠라고 할 수 있다. 화장실 칸이 4개이고 열쇠가 4개라면, 4명까지는 대기없이 바로 사용할 수 있다. 그 다음부터는 대기를 해야 한다. 이것이 바로 세마포어이다.
 53 | - 세마포어 Counter의 갯수에 따라 다음과 같이 나뉜다.
 54 |   - 1개 : Binary Semaphore(뮤텍스와 같다.)
 55 |   - 2개 이상 : Counting Semaphore
 56 | - 세마포어는 소유할 수 없다.
 57 |   - 세마포어를 소유하지 않은 스레드가 세마포어를 해제할 수 있는 문제가 발생한다.
 58 | 
 59 | 
 60 | 
 61 | 2. 뮤텍스(Mutal Exclusion)
 62 | 
 63 | - 공유된 자원의 데이터를 여러 프로세스, 스레드가 접근하는 것을 막는 것이다.
 64 | - 임계 구역을 가진 스레드들의 Running time이 서로 겹치지 않게 각각 단독으로 실행되게 하는 기술이다.
 65 | - **뮤텍스 객체를 두 스레드가 동시에 사용할 수 없다.**
 66 | - 일종의 Locking 매커니즘으로 공유 자원에 대한 접근을 조율하기 위해 locking과 unlocking을 사용한다.
 67 | - Lock에 대한 소유권이 있으며 Lock을 가지고 있을 경우에만 공유 자원에 접근할 수 있고, Lock을 가진 사람만 반납할 수 있다.
 68 | - 뮤텍스는 무조건 1개의 열쇠만 가질 수 있다. 열쇠를 가진 사람만이 화장실에 갈 수 있고, 다음 사람이 화장실에 가기 위해서는 앞 사람이 열쇠를 반납해야 한다.
 69 | 
 70 | 
 71 | 
 72 | 3. 모니터(Monitor)
 73 | 
 74 | - Mutex(Lock)와 Condition Variables를 가지고 있는 Synchronization 매커니즘이다.
 75 | 
 76 | 
 77 | 
 78 | 뮤텍스와 모니터는 상호 배제를 함으로써 임계 구역에 하나의 쓰레드만 들어갈 수 있다.
 79 | 
 80 | 반면, 세마포어는 하나의 쓰레드만 들어가거나 혹은 여러개의 쓰레드가 들어가게 할 수도 있다.
 81 | 
 82 | 
 83 | 
 84 | #### Q. 임계영역이란?
 85 | 
 86 | - 둘 이상의 스레드가 동시에 접근해서는 안되는 공유 자원을 접근하는 코드의 일부를 말한다.
 87 | - 임계 영역에서 동기화를 진행하지 못하면 치명적인 문제가 발생.
 88 | - 따라서 임계 구역 문제를 해결하기 위해서는 3가지 필수 조건이 있다.
 89 |   1. 상호 배제(Mutual exclusion) : 프로세스 P1이 공유 자원을 접근하는 임계 구역 코드를 수행하고 있으면 다른 프로세스들은 공유 자원을 접근하는 임계 구역 코드를 수행할 수 없다. 즉, 한 순간에 하나의 스레드만이 실행될 수 있다.
 90 |   2. 진행(Progress) : 임계 구역에서 실행중인 프로세스가 없고 별도의 동작이 없는 프로세스들만 임계 구역 진입 후보로서 참여될 수 있다.
 91 |   3. 한정된 대기(Bounded Waiting) : P1이 임계 구역에 진입 신청 후부터 받아들여질때까지, 다른 프로세스들이 임계 구역에 진입하는 횟수는 제한이 있어야 한다.
 92 | 
 93 | 
 94 | 
 95 | **Q. 뮤텍스와 모니터의 차이는?**
 96 | 
 97 | - 뮤텍스는 다른 프로세스나 스레드 간에 동기화를 위해 사용한다.
 98 | - 모니터는 하나의 프로세스내에서 다른 스레드 간에 동기화할 때 사용한다.
 99 | - 뮤텍스는 운영체제 커널에 의해 제공된다.
100 |   - 무겁고 느리다.
101 | - 모니터는 프레임워크나 라이브러리 그 자체에서 제공된다.
102 |   - 가볍고 빠르다.
103 | 
104 | 
105 | 
106 | **Q. 세마포어와 모니터의 차이는?**
107 | 
108 | - 자바에서는 모니터를 모든 객체에게 기본적으로 제공하지만 C에서는 사용할 수 없음.
109 | - 세마포어는 카운터라는 변수값으로 프로그래머가 상호 배제나 정렬의 목적으로 사용시 매번 값을 따로 지정해줘야 하는 등 조금 번거롭다.
110 | - 반면, 모니터는 이러한 일들이 캡슐화되어 있어서 개발자는 카운터 값을 0 또는 1으로 주어야 하는 고민을 할 필요가 없이 synchronized, wait(), notify() 등의 키워드를 이용해 좀 더 편하게 동기화할 수 있다.
111 | 
112 | **Q. 세마포어와 뮤텍스의 차이는?**
113 | 
114 | - 세마포어는 뮤텍스가 될 수 있지만, 뮤텍스는 세마포어가 될 수 없다.
115 | - 세마포어는 소유할 수 없으며, 뮤텍스는 소유할 수 있고 소유주가 그 책임을 진다.
116 | - 뮤텍스의 경우 뮤텍스를 소유하고 있는 스레드가 이 뮤텍스를 해제할 수 있다. 하지만 세마포어는 소유하지 않고 있는 다른 스레드가 세마포어를 해제할 수 있다.
117 | - 뮤텍스는 동기화 대상이 1개일 때 사용하고 세마포어는 동기화 대상이 여러 개일때 사용한다.
118 | 
119 | 
120 | 
121 | **[Toilet Problem]**
122 | 
123 | 동시성 프로그래밍의 가장 큰 숙제는 '공유자원 관리'이다. 공유 자원을 안전하게 관리하기 위해서는 상호배제를 달성하는 기법이 필요하며, 뮤텍스와 세마포어가 이를 위해 고안된 기법이다. 이 둘은 서로 다른 방식으로 상호배제를 달성한다.
124 | 
125 | 이 둘은 화장실 문제에 적용하여 풀어낼 것이다.
126 | 
127 | 1) 뮤텍스
128 | 
129 | 뮤텍스는 화장실이 하나뿐인 식당과 비슷하다. 화장실에 가기 위해서 카운터에서 열쇠를 받아가야 한다.
130 | 
131 | 내가 화장실을 가려고 하는데 카운터에 키가 있으면 화장실에 사람이 없다는 의미이고 나는 열쇠를 가지고 화장실에 갈 수 있다.
132 | 
133 | ![img](https://cdn-images-1.medium.com/max/1600/1*6JKj81oYsxQlDhjAlMXQjg.png)
134 | 
135 | 
136 | 
137 | 화장실에 가고 싶은 다른 사람이 있다. 이 사람은 급하지만 열쇠가 없기 때문에 화장실에 갈 수 없고 기다려야 한다. 내가 용무를 끝내 나올 때까지 카운터에서 기다려야 한다. 또 다른 사람도 화장실에 가고 싶어 카운터에서 대기한다.
138 | 
139 | ![img](https://cdn-images-1.medium.com/max/1600/1*CgUE8ByDUKnVkkrEbMPwCQ.png)
140 | 
141 | 나는 화장실에서 나와 카운터에 키를 올려놓는다. 이제 기다리던 사람들 중 맨 앞에 있던 사람은 키를 받을 수 있고 화장실에 갈 수 있다.
142 | 
143 | ![img](https://cdn-images-1.medium.com/max/1600/1*dIIfI3ezb3Gt2YH1uWhauQ.png)
144 | 
145 | 이게 뮤텍스가 동작하는 방식이다. 
146 | 
147 | 화장실을 이용하는 사람 : 프로세스 혹은 스레드
148 | 
149 | 화장실 : 공유 자원
150 | 
151 | 화장실 키 : 공유 자원에 접근하기 위해 필요한 어떤 오브젝트.
152 | 
153 | ![img](https://cdn-images-1.medium.com/max/1600/1*CdLr52i_BZjnEf3uWZyRVQ.png)
154 | 
155 | 즉, 뮤텍스는 Key에 해당하는 어떤 오브젝트가 있으며 이 오브젝트를 소유한 프로세스나 스레드만이 공유 자원에 접근할 수 있다.
156 | 
157 | 
158 | 
159 | 2) 세마포어
160 | 
161 | 화장실을 좀 더 쉽게 이용할 수 있는 레스토랑으로 생각하면 된다. 레스토랑의 화장실은 여러 개의 칸이 있다. 그리고 화장실 입구에는 현재 화장실의 빈칸 갯수를 보여주는 전광판이 있다.
162 | 
163 | ![img](https://cdn-images-1.medium.com/max/1600/1*ZJXrQu8rFhSQxW6LVAI-GA.png)
164 | 
165 | 나는 화장실에 가고 싶고, 입구에서 빈 칸의 갯수를 확인하고 1개 이상이라면 빈칸의 갯수를 하나 뺀 다음 화장실에 입장해야 한다. 그리고 나올 때, 빈칸의 갯수를 복구하기 위해 하나를 더해준다.
166 | 
167 | ![img](https://cdn-images-1.medium.com/max/1600/1*lFNABipdkdtxFvW9UZmCaw.png)
168 | 
169 | 모든 칸에 사람이 들어갔을 경우, 빈칸의 갯수는 0이되며 이때 화장실에 들어가고자 하는 사람이 있다면 빈칸의 갯수가 1로 바뀔때까지 기다려야 한다.
170 | 
171 | ![img](https://cdn-images-1.medium.com/max/1600/1*wP9yqG6QBuS7A8i_kKTyRA.png)
172 | 
173 | 이용을 마친 사람들은 나오면서 빈칸의 갯수를 1씩 더한다. 그리고 기다리던 사람은 이 숫자에서 다시 1을 뺀 다음 화장실로 입장한다.
174 | 
175 | ![img](https://cdn-images-1.medium.com/max/1600/1*36aMopAPHO3e80YYADmY6w.png)
176 | 
177 | 세마포어는 공통으로 관리하는 하나의 값을 이용해 상호배제를 달성한다.
178 | 
179 | 화장실을 이용하는 사람 : 프로세스 혹은 스레드
180 | 
181 | 화장실 : 공유 자원
182 | 
183 | 화장실 빈칸의 갯수 : 현재 공유 자원에 접근할 수 있는 스레드, 프로세스의 갯수를 나타냄.
184 | 
185 | 
186 | 
187 | `[요약]`
188 | 
189 | 뮤텍스 : 한 스레드, 프로세스에 의해 소유될 수 있는 Key를 기반으로 한 상호배제 기법
190 | 
191 | 세마포어 : 현재 공유자원에 접근할 수 있는 스레드, 프로세스의 수를 나타내는 값을 두어 상호배제를 달성하는 기법
192 | 
193 | **뮤텍스와 세마포어의 목적은 특정 동기화 대상이 이미 특정 스레드나 프로세스에 의해 사용중일 경우, 다른 스레드가 해당 동기화 대상에 접근하는 것을 제한하는 것으로 동일하지만, 관리하는 동기화 대상이 몇개인가에 따라 차이가 생긴다.**
194 | 
195 | 
196 | 
197 | 두 기법 모두 완벽하지는 않다. 이 기법들을 사용하더라도 데이터 무결성을 보장할 수 없으며 데드락이 발생할 수도 있다. 하지만 상호배제를 위한 기본적인 기법이며 여기에 좀 더 복잡한 매커니즘을 적용해 꽤나 우아하게 동작하는 프로그램을 짤 수 있다고 한다.
198 | 
199 | 
200 | 
201 | > 참고
202 | >
203 | > - [뮤텍스(Mutex)와 세마포어(Semaphore)의 차이](https://worthpreading.tistory.com/90)
204 | 


--------------------------------------------------------------------------------
/Operating System/스케줄러의 종류.md:
--------------------------------------------------------------------------------
  1 | ### 스케줄러(Scheduler)
  2 | 
  3 | - 스케줄링 알고리즘을 알기 전에 스케줄러에 대해 알아보자
  4 | - 프로세스들은 자신이 종료될 때까지 수많은 큐들을 돌아다닌다. OS는 이 큐 안에 있는 프로세스 중 하나를 선택해야 하며, 이러한 일을 `스케줄러(Scheduler)`가 담당한다.
  5 | - 작업 큐(Job Queue) : 현재 시스템 내의 모든 프로세스의 집합
  6 | - 준비 큐(Ready Queue) : 현재 메모리 내에 있으면서 CPU를 할당받고 실행되기 위해 기다리는 프로세스의 집합
  7 | - 장치 큐(Device Queue) : 각각의 장치마다 서비스를 기다리며 줄 서 있는 프로세스의 집합
  8 | 
  9 | 
 10 | 
 11 | 
 12 | 
 13 | **[장기 스케줄러(Long-term Scheduler)]**
 14 | 
 15 | <!-- 메모리는 한정되어 있는데 많은 프로세스들이 한꺼번에 메모리에 올라올 경우, 대용량 메모리(일반적으로 디스크)에 임시로 저장된다. 이 Pool에 저장되어 있는 프로세스 중 어떤 프로세스에 메모리를 할당하여 Ready Queue로 보낼지 결정하는 역할을 한다.
 16 | - 메모리와 디스크 사이의 스케줄링을 담당한다.
 17 | - 프로세스에 Memory(및 각종 리소스)를 할당한다.(admit)
 18 | - degree of Multiprogramming 제어(메모리에 여러 프로그램이 올라가는 것. 즉, 몇 개의 프로그램이 올라갈 것인지를 제어)
 19 | - 즉, 디스크와 같은 저장 장치에 작업들을 저장해 놓고 필요할 때 Jab Queue에서 꺼내 Ready Queue에 적재(메모리로 적재)한다.
 20 | - 프로세스의 상태 : 시작 상태(New) -> 준비 상태(Ready) -->
 21 | 
 22 | - 메모리는 한정되어 있는데 많은 프로세스들이 메모리에 한꺼번에 올라올 경우, 대용량 메모리(디스크)에 임시로 저장한다. 이 Pool(디스크) 내의 저장되어 있는 프로세스 중 어떤 순서로 프로세스를 메모리에 적재할지 결정한다.
 23 | 
 24 | - **메모리와 디스크 사이의 스케줄링**을 담당한다. 따라서 상대적으로 호출되는 빈도가 적다.
 25 | - 즉, 디스크와 같은 저장 장치에 작업들을 저장해 놓고 필요할 때 실행할 작업을 Job Queue에서 꺼내 Ready Queue를 통해서 메인 메모리에 적재한다.
 26 | - degree of Multiprogramming 제어(메모리에 여러 프로그램이 올라가는 것. 즉, 몇 개의 프로그램이 올라갈 것인지를 제어)
 27 | - 프로세스의 상태
 28 |   - 시작 상태(New) -> 준비 상태(Ready)
 29 |   - Running(or Ready) -> Terminated
 30 | 
 31 | 
 32 | 
 33 | 
 34 | **[단기 스케줄러(Short-term Scheduler)]**
 35 | 
 36 | <!--
 37 | - CPU와 메모리 사이의 스케줄링을 담당한다.
 38 | - Ready Queue에 존재하는 프로세스 중 어떤 프로세스를 running 시킬지 결정한다.
 39 | - 프로세스에 CPU를 할당한다.
 40 | - 프로세스의 상태 : ready -> running -> waiting -> ready -->
 41 | 
 42 | - **CPU와 메모리 사이의 스케줄링**을 담당한다. 따라서 장기 스케줄러에 비해 매우 많이 호출된다.
 43 | - 우선, CPU에게 필요한 데이터를 확보해주고 메모리에 있는 프로세스 중 하나를 선택해서 CPU를 할당한다.
 44 | - 즉, Ready Queue에 존재하는 프로세스 중 어떤 프로세스를 running 시킬지 결정한다.
 45 | - Ready Queue에 있는 프로세스 중 **먼저 도착한 프로세스에게 CPU를 할당**한다.(=디스페처)
 46 | - 프로세스의 상태 : ready -> running -> waiting -> ready
 47 | 
 48 | 
 49 | 
 50 | **[중기 스케줄러(Medium-term Scheduler)]**
 51 | 
 52 | <!--
 53 | - 여유 공간 마련을 위해 프로세스를 통째로 메모리에서 디스크로 쫓아낸다.(Swapping)
 54 | - 프로세스에게서 Memory를 deallocate
 55 | - degree of Multiprogramming 제어
 56 | - 현 시스템에서 메모리에 너무 많은 프로그램이 동시에 올라가는 것을 조절하는 스케줄러
 57 | - 프로세스의 상태 : ready -> suspended
 58 | -->
 59 | 
 60 | - 시분할 시스템에서 추가로 사용하며, 메모리에 대한 가중을 완화시켜주기 위해 중기 스케줄러 도입.
 61 | - CPU를 차지하기 위한 경쟁이 심해질 때, 우선순위가 낮은 프로세스들을 잠시 제거한 뒤, 나중에 경쟁이 완화되었을 때 다시 디스크에서 메모리로 불러와 중단되었던 지점부터 실행시킨다. (Swapping)
 62 | - 즉, 프로세스들이 서로 CPU를 차지하려고 경쟁이 심해지면 Swapping 기법을 활용하여 메모리를 관리함으로써 너무 많은 프로그램이 동시에 올라가는 것을 조절한다.
 63 | - 프로세스의 상태 : ready -> suspended
 64 | 
 65 | 
 66 | 
 67 | swap out : 메모리에서 디스크로 잠시 나가는 상태
 68 | swap in : 디스크에서 메모리로 다시 들어오는 상태
 69 | 
 70 | 
 71 | 
 72 | **[Process state - suspended]**
 73 | 
 74 | Suspended(stopped) : 외부적인 이유로 프로세스의 수행이 정지된 상태로 메모리에서 내려간 상태를 의미한다. 프로세스 전부 디스크로 Swap out 된다. 
 75 | 
 76 | Blocked 상태는 다른 I/O 작업을 기다리는 상태이기 때문에 스스로 ready state 로 돌아갈 수 있지만, 이 상태는 외부적인 이유로 suspending 되었기 때문에 스스로 돌아갈 수 없다. 
 77 | 
 78 | 
 79 | 
 80 | ### About 중기 스케줄러
 81 | 
 82 | 중기 스케줄러에 대해 더 알아보자.
 83 | 
 84 | 시분할 시스템 운영체제에서는 `중기 스케줄러`를 추가로 도입한다.
 85 | 
 86 | Unix나 Window에서는 장기 스케줄러가 거의 사용되지 않는다고 한다. 왜냐하면 일단 작업이 큐에 들어오면 닥치는대로 메모리에 올린다. 물론 OS 자체적인 제한을 두거나 사용자 스스로 제한을 할 수 있도록 하기도 한다.
 87 | 
 88 | 
 89 | 
 90 | 이를 시분할 시스템에서 어느정도 시스템적으로 완하하기 위해 중기 스케줄러를 도입한 것 같다. 중기 스케줄러를 사용해 **메모리에서 CPU를 쓰기 위해 경쟁하고 있는 프로세스들을 몇 개 제거**한다. 그리고 추후에 **다시 메모리로 불러와서 중단되었던 지점부터 다시 실행을 재게**하게 하는 것이다. -> 스와핑(Swapping) 기법
 91 | 
 92 | 
 93 | <img width="682" alt="scheduler2" src="https://user-images.githubusercontent.com/33534771/87003398-82df2880-c1f6-11ea-99da-9deafad24475.png">
 94 | 
 95 | <img width="402" alt="scheduler" src="https://user-images.githubusercontent.com/33534771/87003325-604d0f80-c1f6-11ea-9849-589fc4976821.png">
 96 | 
 97 | 
 98 | 정리하면 중기 스케줄러에 의해 프로세스들이 CPU를 차지하려고 경쟁이 심해지면, `Swap out` 되어 메모리를 떠났다가 다시 `Swap in` 되어 메모리로 돌아온다는 것이다.
 99 | 
100 | <img width="682" alt="scheduler2" src="https://user-images.githubusercontent.com/33534771/87003398-82df2880-c1f6-11ea-99da-9deafad24475.png">
101 | 
102 | 
103 | - 작업(Job)이 도착하면 입력 큐(또는 준비 큐)에서 장기 스케줄러에 의해 메모리에 적재된다.
104 | - 단기 스케줄러에 의해 선택되어 CPU를 할당받게 된다.
105 | - Memory Scheduler는 중기 스케줄러의 역할을 하며, 프로세스들이 메모리에서 디스크로 Swap in, Swap out 되는 것을 볼 수 있다.
106 | 
107 | 
108 | 
109 | #### [정리] 장기 스케줄러 vs 단기 스케줄러
110 | 
111 | 
112 | `장기 스케줄러와 단기 스케줄러의 가장 큰 차이점은 실행 빈도이다.`
113 | 
114 | 프로세스는 빠르게 실행되고 이러한 프로세스들을 처리하기 위해 즉, 프로세스들 간의 우선순위를 정하기 위해 단기 스케줄러가 동작한다. 여기서 스케줄링의 시간이 지연되면 안되기 때문에 단기 스케줄러는 상당히 빨라야 하고 호출 빈도수가 많다.
115 | 
116 | 
117 | 
118 | 그에 반해 시스템에 새로운 작업이 생성되어 들어오는 것은 분 단위로 프로세스의 함수가 실행되는 시간에 비해 무지 길다. 추가로 시스템에서 이탈하는 프로세스도 관리하지만, 장기 스케줄러는 단기 스케줄러보다 호출 빈도수가 매우 적다. 그리고 장기 스케줄링은 스케줄링 시간이 꽤 걸리더라도 신중하게 프로세스를 선택한다. 
119 | 
120 | 만약, 장기 스케줄링이 I/O 프로세스나 CPU 중심 프로세스 중 한쪽으로 편중해서 프로세스를 받아온다면 ready Queue, device Queue 한쪽에 프로세스가 집중되어 버리게 되어 단기 스케줄러의 균형도 붕괴된다.
121 | 
122 | 
123 | ++ 전체적인 흐름 추가하기(규글)
124 | 
125 | ### Reference
126 | 
127 | - [OS - 스케줄러의 종류](http://blog.naver.com/PostView.nhn?blogId=4717010&logNo=60208674547)
128 | - [[OS] 스케줄러란?](https://k39335.tistory.com/32)
129 | - [[운영체제] 스케줄러](https://kim6394.tistory.com/177)
130 | 
131 | 


--------------------------------------------------------------------------------
/Operating System/시스템 콜(System Call).md:
--------------------------------------------------------------------------------
 1 | ### 시스템 콜(System Call)
 2 | 
 3 | 먼저, 커널 모드와 사용자 모드에 대해서 알아보자.
 4 | 
 5 | 1) 커널 모드
 6 | 
 7 | 프로그램 카운터가 운영체제가 존재하는 부분을 가리키고 있다면, 현재 운영체제의 코드를 수행 중이며 CPU가 커널 모드에서 수행 중이라고 한다.
 8 | 
 9 | 2) 사용자 모드
10 | 
11 | 프로그램 카운터가 사용자 프로그램이 존재하는 메모리 위치를 가리킬 경우, 사용자 프로그램을 수행 중이며 CPU가 사용자 모드에서 수행 중이라고 한다.
12 | 
13 | - 일반 명령 : 메모리에서 자료를 읽어와서 CPU에서 계산하고 결과를 메모리에 쓰는 일련의 명령들. 모든 프로그램이 수행할 수 있음. (사용자 모드)
14 | - 특권 명령 : 보안이 필요한 명령으로 입출력 장치, 타이머 등 각종 장치를 접근하는 명령.(커널 모드)
15 | - CPU 내에 모드 비트를 두어 두 명령을 수행한다.
16 | 
17 | - 사용자 프로그램이 디스크의 파일을 접근하거나, 화면에 결과를 출력하는 등의 작업이 필요한 경우가 있다. 하지만, 이러한 작업은 특권 명령의 수행을 필요로 한다. 
18 | - 이와 같은 경우, 사용자 프로그램은 스스로 특권 명령을 수행할 수 없으므로 운영체제에게 특권 명령의 대행을 요청한다. 이러한 서비스 요청은 시스템 콜이라고 부른다. (즉, 특권 명령의 대행을 요청하여 사용자 프로그램이 커널 영역의 기능을 수행하게 해준다.)
19 | 
20 | 
21 | 
22 | **디스크에서 자료를 읽어오는 시스템 콜이라고 가정!**
23 | 
24 | 1. 사용자 프로그램이 시스템 콜을 하게 되면 운영체제는 자신의 커널 영역에 정의된 시스템 콜 처리 코드를 수행한다.
25 | 2. CPU가 컨트롤 레지스터를 세팅해 디스크 컨트롤러에게 데이터를 읽어오라고 명령한다.
26 | 3. 디스크 컨트롤러는 디스크로부터 데이터를 읽어와서 자신의 로컬 버퍼에 저장한다.
27 | 4. 작업이 완료되면 디스크 컨트롤러가 CPU에게 인터럽트를 발생시켜 입출력 작업이 완료되었음을 통지한다.
28 | 
29 | 
30 | 
31 | 통상적으로 시스템 콜은 여러 종류의 기능으로 나뉘어져 있다. 각 시스템 콜에는 번호가 할당되고 시스템 콜 인터페이스는 이러한 번호에 따라 인덱스되는 테이블을 유지한다. 아래 그림은 open() 시스템 콜을 호출했을 때, 운영체제에서 어떻게 처리되는지를 보여준다.
32 | 
33 | ![img](https://t1.daumcdn.net/cfile/tistory/25333241535CCEE810)
34 | 
35 | 
36 | 
37 | 필요한 기능이나 시스템 환경에 따라 시스템 콜이 발생할 때, 좀 더 많은 정보가 필요할 수도 있다. 그러한 정보가 담긴 매개변수를 운영체제에 전달하기 위해서는 대략 3가지 정도의 방법이 있다.
38 | 
39 | 1) 매개변수를 CPU 레지스터 내에 전달한다. 이 경우에 매개변수의 갯수가 CPU 내의 레지스터 갯수보다 많을 수 있다.
40 | 
41 | 2) 위와 같은 경우에 매개변수를 메모리에 저장하고 **메모리의 주소가 레지스터에 전달**된다. (아래 그림 참고)
42 | 
43 | 3) 매개변수는 프로그램에 의해 **스택으로 전달**될 수도 있다.
44 | 
45 | 
46 | 
47 | ![img](https://t1.daumcdn.net/cfile/tistory/27118142535CCF060A)
48 | 
49 | 
50 | 
51 | 2,3번은 전달되는 **매개변수의 갯수나 길이에 제한이 없기 때문에** 몇몇 운영체제에서 선호하는 방식이다.
52 | 
53 | 
54 | 
55 | ### 시스템 콜의 유형
56 | 
57 | 5가지의 범주로 나눌 수 있다.
58 | 
59 | 1. 프로세스 제어 : 프로세스 특권 모드를 사용해 직접적으로 프로세스 제어가 가능
60 | 2. 파일 조작 : 파일을 생성하거나 삭제, 관리 등
61 | 3. 장치 관리 : 장치 요구 및 장치 해제, 읽기, 쓰기, 재배치 등
62 | 4. 정보 유지 : 시간과 날짜의 설정과 획득, 시스템 자료의 설정과 획득
63 | 5. 통신 : 통신 연결의 생성 및 제거, 메시지의 송수신, 상태 정보 전달 등
64 | 
65 | 
66 | 
67 | ### 참고
68 | 
69 | - [운영체제 04 : 시스템 콜](https://luckyyowu.tistory.com/133)
70 | - [시스템 인터럽트, 시스템 콜](https://luckyyowu.tistory.com/2)


--------------------------------------------------------------------------------
/Operating System/인터럽트(Interrupt).md:
--------------------------------------------------------------------------------
 1 | ### 인터럽트(Interrupt)
 2 | 
 3 | - 하드웨어 장치가 CPU에게 어떤 사실을 알려주거나 CPU의 서비스를 요청해야 할 경우, CPU 내에 있는 인터럽트 라인을 세팅하여 인터럽트를 발생시킨다. (프로그램이 명령을 수행하기 위해서는 CPU를 할당받아야 함)
 4 | - CPU는 매번 프로그램 카운터가 가리고 있는 곳의 명령을 수행한 뒤, 다음 명령을 수행하기 직전에 인터럽트 라인이 세팅되었는지 체크한다.
 5 | - 이를 통해 인터럽트가 발생했으면 CPU는 현재 수행 중이던 프로세스를 멈추고 운영 체제의 인터럽트 처리 루틴으로 이동하여 인터럽트 처리를 수행한다. 
 6 | 
 7 | 
 8 | 
 9 | #### 인터럽트의 종류
10 | 
11 | 1. 하드웨어 인터럽트(일반적인 인터럽트)
12 |    - 하드웨어 컨트롤러가 CPU의 서비스를 요청하기 위해 발생시키는 인터럽트
13 | 
14 | <img src="https://k.kakaocdn.net/dn/bwovTQ/btqvBp24GS1/AxuTAkEaZaQwobodqeEfQk/img.png" alt="img" style="zoom:50%;" />
15 | 
16 | <center>하드웨어 인터럽트 발생 과정</center>
17 | 
18 | 2. 소프트웨어 인터럽트(Trap:트랩)
19 | 
20 | 1) 예외 상황(Exception) 
21 | 
22 | - 프로그램이 허용되지 않은 연산을 수행하려고 할 때, 자동적으로 발생한다. 운영체제는 예외 상황이 발생했을 때, CPU의 제어권을 획득해 이 상황에 대한 조치를 취한다.
23 | - ex) 0으로 나누는 연산, 자신의 주소 공간을 넘어서는 메모리 참조 등
24 | - 예외 상황에 대한 처리 루틴을 자신의 코드 영역에 가지고 있음
25 | 
26 | 2) 시스템 콜(System Call) 
27 | 
28 | - 사용자 프로세스가 운영체제의 서비스를 요청하기 위해 커널의 함수를 호출하는 것이다. 
29 | - 사용자 프로세스가 직접 특권 명령을 수행할 수 없으므로 특권 명령을 수행하려 할 때, 시스템 콜을 사용한다. 
30 | 
31 | <img src="https://k.kakaocdn.net/dn/QnqLh/btqvABC7Ea2/sflPVirxNdWXOiQkc8CQz1/img.png" alt="img" style="zoom:50%;" />
32 | 
33 | <center>소프트웨어 인터럽트 발생 과정</center>
34 | 
35 | 시스템 콜이나 예외 상황은 모두 사용자 프로세스로부터 CPU의 제어권이 운영 체제에게 이양되어 처리되는데 이 과정에 인터럽트 라인을 세팅하여 인터럽트를 발생시킨 후 제어권이 넘어가게 되므로 이들도 넓은 의미에서는 인터럽트의 범주에 포함시킨다. **단지 인터럽트를 발생시키는 주체가 하드웨어 장치가 아닌 소프트웨어이므로 이들을 소프트웨어 인터럽트라고 부른다.**
36 | 
37 | 
38 | 
39 | 
40 | 
41 | #### 인터럽트 발생 처리 과정
42 | 
43 | A 프로그램이 CPU를 할당받고 명령을 수행하고 있는데 인터럽트가 발생하면 A는 현재 수행중인 명령의 위치를 저장해놓는다. 그 후, 운영 체제 내부 코드인 인터럽트 처리 루틴으로 넘어가서 인터럽트 처리를 하고 다시 돌아와 A의 이전 작업 지점부터 수행을 계속 이어나가게 된다.
44 | 
45 | 
46 | 
47 | `그렇다면, 인터럽트가 발생했을 때 수행중이던 프로세스의 정보는 어디에 저장될까?`
48 | 
49 | -> 진행 중이던 A 프로세스의 정보는 프로세스 제어 블록(PCB: Process Control Block)에 저장한다. 그리고 인터럽트 처리를 모두 마치면 프로그램 A의 PCB에 저장된 주소를 복원시켜 원래 수행하던 일을 재개하게 된다. 
50 | 
51 | 
52 | 
53 | - 인터럽트 벡터(Interrupt Vector)
54 |   - 여러가지 인터럽트에 대해 해당 인터럽트 발생시 처리해야 할 루틴의 주소를 보관하고 있는 테이블.
55 |   - 일종의 함수를 가리키는 포인터
56 | 
57 | - 인터럽트 핸들러(Interrupt Handler)
58 |   - 실제 인터럽트를 처리하기 위한 루틴으로 인터럽트 서비스 루틴이라고도 한다.
59 |   - 운영체제 코드 부분에는 각종 인터럽트 별로 처리해야 할 내용이 이미 프로그램되어 있으며, 이 부분을 인터럽트 서비스 루틴 또는 인터럽트 핸들러라고 한다.
60 | 
61 | 예를 들어, 입출력 관련 인터럽트가 발생한 경우, CPU는 인터럽트 라인을 통해 발생한 인터럽트를 확인한다. 인터럽트 벡터를 통해 해당 인터럽트 발생시 처리해야 할 루틴의 메모리 주소를 알아낸다. 주소를 통해 실제 수행되어야 할 코드가 담겨있는 루틴을 찾아가 상황에 맞는 처리를 진행한다.
62 | 
63 | 
64 | 
65 | ### 참고
66 | 
67 | - [#3 인터럽트의 원리 - 운영체제와 정보기술의 원리](https://real-dongsoo7.tistory.com/m/93?category=784608)
68 | - [규글님 Github](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Operation%20System/Interrupt.md)
69 | 


--------------------------------------------------------------------------------
/Operating System/프로세스와 스레드.md:
--------------------------------------------------------------------------------
  1 | ## 프로세스 vs 스레드
  2 | 
  3 | 프로그램이란? 어떤 작업을 위해 실행할 수 있는 파일을 의미한다.
  4 | 
  5 | 
  6 | 
  7 | #### 프로세스(Process)
  8 | 
  9 | - 실행 중인 프로그램으로 디스크로부터 메모리에 적재되어 CPU의 할당을 받은 작업의 단위다.
 10 | - 운영체제로부터 시스템 자원을 할당받는다.
 11 | 
 12 | - 할당받는 시스템 자원
 13 |   - CPU 시간
 14 |   - 운영되기 위한 주소 공간
 15 |   - Code, Data, Stack, Heap의 구조로 되어있는 독립된 메모리 영역.
 16 | 
 17 | <img src="https://user-images.githubusercontent.com/33534771/77537773-fe37fb00-6ee1-11ea-8def-4dd11523b5e7.png" />
 18 | 
 19 | - 기본적으로 프로세스마다 최소 1개의 스레드를 갖는다.(메인 스레드)
 20 | - 프로세스는 각각 별도의 메모리 영역(주소 공간)을 할당받는다.  [Code, Data, Stack, Heap]
 21 | - 한 프로세스는 다른 프로세스의 변수나 자료구조에 접근할 수 없으며, 접근을 위해서는 IPC 통신이 필요하다.
 22 |   - Ex) 파이프, 파일, 소켓 등을 이용한 통신 방법 이용.
 23 | 
 24 | 
 25 | 
 26 | #### 프로세스 제어 블록(Process Control Block, PCB)
 27 | 
 28 | - 특정 프로세스에 대한 중요한 정보를 저장하고 있는 **커널 내의 자료구조**이다.
 29 | - OS는 프로세스를 관리하기 위해 프로세스의 생성과 동시에 고유한 PCB를 생성한다. 
 30 | - 프로세스는 CPU를 할당받아 작업을 처리하다가 프로세스 전환이 발생하면 진행하던 작업을 저장하고 CPU를 반환해야 한다. 이때 작업의 진행 상황을 모두 PCB에 저장한다. 그리고 다시 CPU를 할당받게 되면 PCB에 저장되었던 내용을 불러와 종료되었던 시점부터 다시 작업을 수행한다.
 31 | 
 32 | - PCB에 저장되는 정보
 33 |   - 프로세스 식별자(Process ID, PID) : 프로세스 식별 번호
 34 |   - 프로세스 상태 : new, ready, running, waiting, terminated 등의 상태를 저장
 35 |   - 프로그램 카운터(Program Counter, PC) : 프로세스가 다음에 실행할 명령어의 주소를 가리킨다.
 36 |   - CPU 레지스터
 37 |   - CPU 스케줄링 정보 : 프로세스의 우선순위, 스케줄 큐에 대한 포인터 등
 38 |   - 메모리 관리 정보 : 페이지 테이블 또는 세그먼트 테이블 등과 같은 정보를 포함한다.
 39 |   - 입출력 상태 정보 : 프로세스에 할당된 입출력 장치들과 열린 파일 목록
 40 |   - 어카운팅 정보 : 사용된 CPU 시간, 시간 제한, 계정 번호 등
 41 | 
 42 | 
 43 | 
 44 | #### 스레드(Thread)
 45 | 
 46 | - 프로세스의 실행 단위라고 할 수 있으며, 한 프로세스 내에서 동작되는 여러 실행 흐름으로 프로세스 내의 주소 공간이나 자원을 공유할 수 있다.
 47 | 
 48 | <img src="https://user-images.githubusercontent.com/33534771/77537866-232c6e00-6ee2-11ea-91dc-12dacf688276.png" />
 49 | 
 50 | - 스레드는 프로세스 내의 Code, Data, Heap 영역은 다른 스레드와 공유하고 Stack 영역을 따로 할당받는다.
 51 | - 여러 스레드는 한 프로세스 내의 Code, Data, Heap 영역을 공유하지만, 프로세스 간에는 메모리에 접근할 수 없다.
 52 | - 스레드는 별도의 레지스터와 스택을 갖고 있으며, 다른 영역을 공유한다. 따라서 한 스레드가 프로세스의 자원을 변경하면, 다른 스레드도 그 변경 결과를 즉시 확인할 수 있다.
 53 | 
 54 | 
 55 | 
 56 | `[요약]`
 57 | 
 58 | `프로세스` : 자신만의 고유 공간과 자원을 할당받아 사용하는 작업의 단위.
 59 | 
 60 | `스레드` : 프로세스 내에서 실행되는 흐름의 단위로, 다른 스레드와 프로세스의 자원과 공간을 공유하면서 사용.
 61 | 
 62 | 
 63 | 
 64 | ## 멀티 프로세스 vs 멀티 스레드
 65 | 
 66 | #### 멀티 프로세스(Multi Process)
 67 | 
 68 | - 하나의 응용프로그램을 여러 개의 프로세스로 구성하여 각 프로세스가 하나의 작업을 처리하도록 하는 것.
 69 | - 장점
 70 |   - 여러 개의 자식 프로세스 중 하나에 문제가 발생하면 그 자식 프로세스만 죽는 것 이상으로 다른 영향이 확산되지 않는다. (안전성)
 71 | - 단점
 72 |   1. Context Switching에서의 오버헤드
 73 |      - 프로세스는 각 독립된 메모리 영역을 할당받았기 때문에 공유하는 메모리가 없다. 따라서 캐시 메모리 초기화 등의 무거운 작업이 진행되고 많은 시간이 소모되는 등의 오버헤드가 발생할 문제가 있다.
 74 |   2. 프로세스 간 통신 기법 IPC
 75 |      - 프로세스는 각 독립된 메모리 영역을 할당받았기 때문에 프로세스들 사이에서 변수나 자료구조를 공유할 수 없다. 따라서 IPC라는 방법을 사용해야 하며, 이는 어렵고 복잡한 통신 방법이다.
 76 | 
 77 | 
 78 | 
 79 | #### 멀티 스레드(Multi Thread)
 80 | 
 81 | - 하나의 응용 프로그램을 여러 개의 스레드로 구성하고 각 스레드가 하나의 작업을 처리하도록 하는 것.
 82 | - 윈도우, 리눅스 등 많은 OS들이 멀티 프로세싱을 지원하고 있지만, 멀티 스레딩을 기본으로 하고 있다.
 83 | - 웹 서버는 대표적인 멀티 스레드 응용 프로그램이다.
 84 | - 장점
 85 |   - 메모리 공간과 시스템 자원 소모가 줄어들게 된다.
 86 |   - 스레드 간 통신시, 전역 변수의 공간 또는 동적으로 할당된 공간인 Heap 영역을 이용해 데이터를 주고 받으므로 통신 방법이 간단하다.
 87 |   - Context switching 시, 캐시 메모리를 비울 필요가 없기 때문에 비용이 적고 더 빠르다.
 88 |   - 따라서 시스템의 처리량이 향상되고 자원 소모가 줄어들며, 자연스럽게 프로그램의 응답 시간이 단축된다.
 89 | 
 90 | - 단점
 91 |   - 서로 다른 스레드가 Data, Heap 영역 등을 공유하기 때문에 어떤 스레드가 다른 스레드에서 사용중인 변수나 자료구조에 접근하여 엉뚱한 값을 읽어오거나 수정할 수 있다. 즉, 자원 공유의 문제가 발생한다.(동기화)
 92 |   - 하나의 스레드에 문제가 생기면 전체 프로세스가 영향을 받는다.
 93 |   - 주의 깊은 설계가 필요하며, 디버깅이 까다롭다
 94 | 
 95 | 
 96 | 
 97 | ### 멀티 스레드 vs 멀티 프로세스
 98 | 
 99 | 멀티 스레드는 멀티 프로세스보다 적은 메모리 공간을 차지하고 Context Switching이 빠르다는 장점이 있지만, 오류로 인해 하나의 스레드가 종료되면 전체 스레드가 종료될 수 있다는 점과 동기화 문제를 가지고 있다. 
100 | 
101 | 반면, 멀티 프로세싱 방식은 하나의 프로세스가 죽더라도 다른 프로세스에는 영향을 끼치지 않고 정상적으로 수행된다는 장점이 있지만, 멀티 스레드보다 많은 메모리 공간과 CPU 시간을 차지한다는 단점이 존재한다. 
102 | 
103 | 이 두 가지는 동시에 여러 작업을 수행한다는 점에서 같지만 적용해야 하는 시스템에 따라 적합/부적합이 구분된다. 따라서 대상 시스템의 특징에 따라 적합한 동작 방식을 선택하고 적용해야 한다
104 | 
105 | 
106 | 
107 | **[자주 나오는 질문]**
108 | 
109 | **Q. 스택을 스레드마다 독립적으로 할당하는 이유는 뭘까?**
110 | 
111 | 스택은 함수 호출시 전달되는 인자, 복귀 주소값 및 함수 내에서 선언하는 변수 등을 저장하기 위해 사용되는 메모리 공간.
112 | 
113 | 스택 메모리 공간이 독립적이라는 것은 독립적인 함수 호출이 가능함을 의미하고 이는 독립적인 실행 흐름이 추가된다는 것이다. 따라서 스레드의 정의에 따라 독립적인 실행 흐름을 추가하기 위한 최소 조건으로 독립된 스택을 할당하는 것이다.
114 | 
115 | 
116 | 
117 | **Q. PC 레지스터를 스레드마다 독립적으로 할당하는 이유는 뭘까?**
118 | 
119 | PC 값은 스레드가 명령어의 어디까지 수행했는지를 나타내게 된다. 스레드는 CPU를 할당받았다가 스케줄러에 의해 다시 선점당한다. 그렇기 때문에 명령어가 연속적으로 수행되지 못하고 어느 부분까지 수행했는지 기억할 필요가 있다. 따라서 PC 레지스터를 독립적으로 할당한다.
120 | 
121 | 
122 | 
123 | `[요약]`
124 | 
125 | **Q. 멀티 프로세스 대신 멀티 스레드를 사용하는 이유는?**
126 | 
127 | <img src="https://user-images.githubusercontent.com/33534771/77537949-41926980-6ee2-11ea-90eb-569dc64faed5.png" />
128 | 
129 | - 프로그램을 여러 개 키는 것보다 하나의 프로그램 안에서 여러 작업을 해결하는 것이 더욱 효율적이기 때문이다.
130 | - **프로세스를 생성하여 자원을 할당하는 시스템 콜이 줄어들어 자원을 효율적으로 관리할 수 있다.**
131 | - Context Switching시, 캐시 메모리를 비울 필요가 없기 때문에 비용이 적고 더 빠르다.-> 스레드는 Stack 영역만 초기화하면 되기 때문이다.
132 | - 스레드는 프로세스 내의 메모리를 공유하기 때문에 데이터 전달이 간단하므로 IPC에 비해 비용이 적고 더 빠르다. -> 스레드는 프로세스의 Stack 영역을 제외한 모든 메모리를 공유하기 때문이다.
133 | 
134 | 
135 | 
136 | +Alpha
137 | 
138 | **Q. Context Switching이란?**
139 | 
140 | - CPU는 한번에 하나의 프로세스만 처리할 수 있다.
141 | - 여러 프로세스를 처리해야 하는 상황에서 현재 진행중인 Task(프로세스, 스레드)의 상태를 PCB에 저장하고 다음에 진행할 Task의 상태값을 읽어 적용하는 과정을 말한다. (**다른 프로세스에게 CPU를 할당해 작업을 수행하는 과정을 말한다.**)
142 | - 과정
143 |   - Task의 대부분 정보는 Register에 저장되고 PCB로 관리된다.
144 |   - 현재 실행하고 있는 Task의 PCB 정보를 저장한다.
145 |   - 다음 실행할 Task의 PCB 정보를 읽어 Register에 적재하고 CPU가 이전에 진행했던 과정을 연속적으로 수행할 수 있다.
146 | - Context Switching은 많은 비용이 소모된다.
147 |   - Cache 초기화
148 |   - Memory mapping 초기화
149 |   - 커널은 항상 실행되어야 한다.
150 | - Context Switching의 비용은 프로세스가 스레드보다 더 많이 든다.
151 | - 이유 : 스레드는 Stack 영역을 제외한 모든 메모리를 공유하기 때문에 Context Switching 발생시 Stack 영역만 변경을 진행하면 되기 때문이다.
152 | 
153 | 
154 | 
155 | 
156 | 
157 | ### Thread-safe
158 | 
159 | - 멀티스레드 환경에서 여러 스레드가 동시에 하나의 객체 및 변수(공유 자원)에 접근할 때, 의도한 대로 동작하는 것을 말한다.
160 | - 이러한 상황을 "Thread-safe 하다"라고 표현한다.
161 | - Thread-safe 하게 구현하기
162 |   - 이를 위해서는 공유 자원에 접근하는 임계영역(critical section)을 동기화 기법으로 제어해줘야 한다. 이를 '상호배제'라고 한다.
163 |   - 동기화 기법으로는 뮤텍스나 세마포어가 존재하며, 다른 페이지에서 확인할 수 있다.
164 | 
165 | 
166 | 
167 | - Reentrant
168 |   - `재진입성`이라는 의미로, 어떤 함수가 Reentrant하다는 것은 여러 스레드가 동시에 접근해도 언제나 같은 실행 결과를 보장한다는 의미이다.
169 |   - 이를 만족하기 위해서 해당 서브루틴에서는 공유자원을 사용하지 않으면 된다.
170 |     - 예를 들어, 정적(전역) 변수를 사용하거나 반환하면 안되고 호출 시 제공된 매개변수만으로 동작해야 한다.
171 |   - 따라서, Reentrant하다면 Thread-safe하지만 그 역은 성립하지 않는다.
172 | 


--------------------------------------------------------------------------------
/운영체제와 정보기술의 원리/운영체제란.md:
--------------------------------------------------------------------------------
  1 | ## 운영체제의 개요
  2 | 
  3 | [운영체제와 정보 기술의 원리](http://www.yes24.com/Product/Goods/2824944)라는 책을 읽고 정리한 내용입니다.
  4 | 
  5 | 1장을 정리했습니다. 내용은 전반적으로 얕게 설명되어 있는 장입니다. 
  6 | 
  7 | 
  8 | 
  9 | ### 운영체제란?
 10 | 
 11 | 운영체제(Operating System 이하 OS)란 컴퓨터 하드웨어 바로 윗단에 설치되는 소프트웨어를 말한다. 컴퓨터를 구성하는 요소 중 운영체제의 위상은 아래와 같다.
 12 | 
 13 | ![img](https://k.kakaocdn.net/dn/bjhadS/btqvnG48wLg/CBJNdOaJaDAZlt0rK5jMR1/img.png)
 14 | 
 15 | OS 자체도 하나의 소프트웨어로서 전원이 켜짐과 동시에 메모리에 올라간다. 하지만, OS처럼 규모가 큰 프로그램이 모두 메모리에 올라간다면 한정된 메모리 공간의 낭비가 발생한다. 따라서  운영 체제 중 항상 필요한 부분만을 전원이 켜짐과 동시에 메모리에 올려놓고 그렇지 않은 부분은 필요할 때, 메모리로 올려서 사용하게 된다.
 16 | 
 17 | - 메모리에 상주하는 운영체제의 부분 -> 커널(Kernel) [좁은 의미의 운영체제]
 18 | - 커널은 운영체제 코드 중에서 핵심적인 부분.
 19 | 
 20 | 
 21 | 
 22 | ### 운영체제의 기능
 23 | 
 24 | 운영체제는 컴퓨터 하드웨어와 사용자 사이에 존재하며, 사용자가 직접 운영하기 힘든 하드웨어에 대해서 운영체제가 관리하기도 하고 사용자에게는 편리한 인터페이스를 제공하는 역할도 한다. 우리가 흔히 아는 Windows Sereis, Mac OS 같은 것들이 예시가 된다.
 25 | 
 26 | 
 27 | 
 28 | 간단하게 정리하면 아래와 같다.
 29 | 
 30 | - 컴퓨터 시스템 내의 자원을 효율적으로 관리하는 것
 31 | - 컴퓨터 시스템을 편리하게 사용할 수 있는 환경을 제공하는 것
 32 | - 사용자 및 프로그램들 간에 자원이 형평성 있게 분배되도록 하는 균형자 역할도 제공한다.
 33 | - 사용자와 운영 체제 자신을 보호하는 역할을 담당.
 34 | 
 35 | 
 36 | 
 37 | ### 운영체제의 분류
 38 | 
 39 | 동시 작업을 지원하는지 여부에 따라 단일 작업용 운영체제와 다중 작업용 운영체제로 나누어 볼 수 있다.
 40 | 
 41 | 1) 단일 작업용 운영체제
 42 | 
 43 | - 한 번에 하나의 프로그램만 수행시킬 수 있는 운영체제
 44 | - MS 윈도즈가 나오기 전 DOS 환경에서는 하나의 프로그램이 수행되는 동안 다른 프로그램을 수행시킬 수 있는 명령어 입력 라인이 뜨지 않아 한번에 하나의 작업만 할 수 있었다.
 45 | 
 46 | 
 47 | 
 48 | 최근에는 대부분의 운영체제가 다중 작업을 지원한다.
 49 | 
 50 | MS 윈도즈나 유닉스 환경에서는 하나의 프로그램의 수행이 끝나기 전에 다른 프로그램을 수행시키는 것이 가능하다.
 51 | 
 52 | 주의할 점으로는 다중 작업용 운영체제에서는 여러 프로그램이 CPU와 메모리를 공유하게 된다. 하지만 일반적으로 CPU는 하나밖에 없으며, 다중 작업용 운영체제라도 CPU에서는 매순간 하나의 프로그램만이 수행되는 것이다.
 53 | 
 54 | 이는 CPU의 처리 속도가 워낙 빨라 수 ms 이내의 짧은 시간 규모로 여러 프로그램이 CPU에서 번걸아 수행되기 때문에 여러 프로그램이 동시에 수행되는 것처럼 보인다.
 55 | 
 56 | 
 57 | 
 58 | **[다중 작업용 운영체제의 분류]**
 59 | 
 60 | - 시분할 시스템 : CPU의 작업 시간을 여러 프로그램들이 조금씩 나누어 쓰는 시스템
 61 | - 다중 프로그래밍 시스템 : 메모리 공간을 분할해 여러 프로그램들을 동시에 메모리에 올려놓고 처리하는 시스템
 62 | - 다중처리기 시스템 : 하나의 컴퓨터 안에 CPU가 여러 개 설치된 시스템.
 63 | 
 64 | 
 65 | 
 66 | **[다중 사용자의 동시 지원 여부]**
 67 | 
 68 | - 단일 사용자용 운영체제 : 한 번에 한명의 사용자만이 사용하도록 허용하는 운영체제
 69 | - 다중 사용자용 운영체제 : 여러 사용자가 동시에 접속해 사용할 수 있게 하는 운영체제
 70 |   - Ex) 이메일 서버,웹 서버, MS 윈도즈 등등
 71 | 
 72 | 
 73 | 
 74 | **[작업을 처리하는 방식에 따른 분류]**
 75 | 
 76 | - **일괄 처리** : 작업 요청의 일정량을 모아서 한꺼번에 처리하는 방식. 따라서 모든 작업이 완전히 종료된 후에 결과를 얻을 수 있다.
 77 |   - 응답 시간이 길다는 단점이 존재.
 78 | - **시분할 방식** : 여러 작업을 수행할 때 컴퓨터의 처리 능력을 일정한 시간 단위로 분할해 사용하는 방식
 79 |   - 일괄 처리 방식에 비해 짧은 응답 시간을 갖는다. 
 80 |   - 평균적으로 사람이 길다고 느끼는 시간 전에 요청에 대한 응답을 얻으므로 사용자 측에서는 컴퓨터를 혼자 독점적으로 사용하는 것처럼 생각할 수 있다.
 81 |   - 이와 같이 사용자의 요청에 대한 결과를 곧바로 얻을 수 있는 시스템을 대화형 시스템이라 부르며, 시분할 방식이 대표적인 예이다.
 82 | - 실시간 처리 : 정해진 시간 안에 어떠한 일이 반드시 종료됨이 보장되어야 하는 시스템
 83 |   - 시간 제약의 중요성에 따라 아래와 같이 두 가지로 나뉜다.
 84 |     1. 경성 실시간 시스템 : 주어진 시간을 지키지 못할 경우, 매우 위험한 결과를 초래할 가능성이 있는 로켓, 원자로 제어 시스템 등을 말한다.
 85 |     2. 연성 실시간 시스템 : 멀티미디어 스트리밍 시스템과 같이 데이터가 시간을 맞추어 전달되어야 올바른 기능을 수행할 수 있는 시스템. (위험한 결과를 초래하지는 않는다.)
 86 | 
 87 | 
 88 | 
 89 | ### 운영체제의 자원 관리 기능
 90 | 
 91 | 운영 체제의 가장 핵심적인 기능은 자원을 효율적으로 관리하는 것이다. 
 92 | 
 93 | **[자원]**
 94 | 
 95 | - 하드 웨어 자원 : CPU, 메모리 및 주변 장치, 입출력 장치 등.
 96 | - 소프트웨어 자원
 97 | 
 98 | 
 99 | 
100 | **[운영체제의 기능 요약]**
101 | 
102 | - CPU 스케줄링 : 어떤 프로그램에게 CPU를 줄 것인가?
103 | - 메모리 관리 : 한정된 메모리를 어떻게 나누어 사용할 것인가?
104 | - 파일 관리 : 디스크에 파일을 어떻게 보관할 것인가?
105 | - 입출력 관리 : 각기 다른 입출력 장치와 컴퓨터 간에 어떻게 정보를 주고 받을 것인가?
106 | - 프로세스 관리
107 |   - 프로세스의 생성과 삭제
108 |   - 자원 할당 및 반환
109 |   - 프로세스 간 협력
110 | - 그 외
111 |   - 보호 시스템
112 |   - 네트워킹
113 |   - 명령어 해석기
114 | 
115 | 
116 | 
117 | **[CPU 관리]**
118 | 
119 | - CPU가 하나밖에 없지만 프로세스는 여러개가 동시에 실행된다. 그러므로 매 시점 어떠한 프로세스에게 CPU를 할당해 작업을 처리할 것인지 결정해야 한다. 이러한 일을 **CPU 스케줄링**이라 한다. 
120 | - 목표 : CPU를 가장 효율적으로 사용하면서도 특정 프로세스가 불이익을 당하지 않도록 하는 것이다.
121 | 
122 | 
123 | 
124 | 1) 선입 선출(FCFS : First Come First Served)
125 | 
126 | - CPU를 사용하기 위해 먼저 도착한 프로세스를 먼저 처리하는 방식
127 | - 일상 생활에서 줄서기와 유사하다.
128 | - CPU를 필요로 하는 프로세스가 여럿 있을 때 먼저 CPU를 요청한 프로세스가 원하는 작업을 완료할 때까지 다른 프로세스들이 CPU를 사용하지 못하게 된다. 따라서 장시간 CPU를 사용해야 하는 프로세스가 먼저 도착해 CPU를 사용하면 이후에 도착한 짧은 시간 CPU를 사용해야 하는 프로세스는 앞서 도착한 프로세스의 작업이 끝날 때까지 하염없이 기다리게 되어 비효율적인 결과를 초래할 가능성이 있다. (단점)
129 | 
130 | 
131 | 
132 | 2) 라운드 로빈 기법
133 | 
134 | - FCFS의 단점을 보완하고자 등장.
135 | - CPU를 한 번 할당받아 사용할 수 있는 시간을 일정한 고정된 시간으로 제한한다.
136 | - 그래서 긴 작업을 요하는 프로세스가 CPU를 할당받더라도 정해진 시간이 지나면 CPU를 내어놓고 CPU의 서비스를 기다리는 줄의 제일 뒤에 가서 기다려야 한다.
137 | - 따라서 적어도 긴 작업을 수행하는 프로세스 때문에 짧은 작업을 가진 프로세스들이 무작정 오래 기다려야 하는 상황을 막을 수 있다.
138 | - 일반적으로 1회 할당 시간은 수 밀리 세컨드(ms) 정도의 단위를 사용한다.
139 | 
140 | 
141 | 
142 | 3) 우선 순위 스케줄링
143 | 
144 | - 수행 대기 중인 프로세스들에게 우선 순위를 부여하고 우선순위가 높은 프로세스에게 CPU를 먼저 할당하게 된다.
145 | - 또한, 지나치게 오래 기다리는 프로세스가 발생하지 않도록 기다린 시간이 늘어날수록 우선순위를 점차 높여주는 방안도 우선순위 스케줄링에 활용될 수 있다.
146 | 
147 | 
148 | 
149 | **[메모리 관리]**
150 | 
151 | 메모리는 CPU가 직접 접근할 수 있는 컴퓨터 내부의 기억 장치이다.
152 | 
153 | 프로그램이 CPU에서 수행되려면 해당 부분이 메모리에 올라가 있어야 한다. 한정된 메모리 공간에 여러 프로그램을 수용하려면 메모리에 대한 효율적인 메커니즘이 필요하다.
154 | 
155 | - 운영 체제는 각 프로세스가 자신의 메모리 영역만을 접근할 수 있도록 관리해야 한다.
156 | 
157 | 
158 | 
159 | 1) 물리적 메모리
160 | 
161 | - 고정 분할 방식
162 |   - 물리적 메모리를 몇 개의 영구적인 분할로 나눈다.
163 |   - 각각의 분할에는 하나의 프로그램이 적재된다.
164 |   - 분할의 크기보다 큰 프로그램은 적재가 불가능하며, 동시에 메모리에 적재되는 프로그램의 수는 분할 개수로 한정된다.
165 |   - 분할의 크기가 고정적이기 때문에 분할의 크기보다 작은 프로그램이 적재되는 경우 남는 영역이 발생하며 이를 **내부 조각**이라고 한다.
166 |   - `내부 조각` : 분할 영역에 올라온 프로그램에 의해서도 사용되지 않고, 다른 프로세스에게도 할당될 수 없으므로 비효율적으로 낭비되는 공간.
167 | 
168 | - 가변 분할 방식
169 |   - 매 시점 프로그램의 크기에 맞게 메모리를 분할해서 사용하는 방식.
170 |   - 물리적 메모리 크기보다 더 큰 프로그램의 실행은 여전히 불가능하다.
171 |   - 분할의 크기, 개수가 동적으로 변하므로 기술적 관리 기법이 필요하다.
172 |   - **외부 조각**이 발생할 수 있다.
173 |   - `외부 조각` : 프로그램에게 할당되지 않은 메모리 영역이지만 그 크기가 작아 프로그램을 올리지 못하는 메모리 영역.
174 | 
175 | - 가상 메모리 방식
176 |   - 물리적 메모리보다 더 큰 프로그램이 실행되는 것을 지원한다.
177 |   - 자신만의 가상 메모리를 갖고 물리적 메모리 주소와 가상 메모리의 주소를 매핑하는 기술을 이용해 주소를 변환시킨 후 프로그램을 물리적 메모리에 올린다.
178 |   - 필요한 부분만을 메모리에 올리고 나머지는 스왑 영역(swap area)에 저장하여 사용한다.(스왑 영역 : 보조기억 장치)
179 |   - 프로그램을 구성하는 주소 공간은 페이지라는 동일한 크기의 작은 단위로 나뉘어 물리적 메모리와 스왑 영역에 일부분씩 저장한다.
180 |   - 동일한 단위로 메모리를 나누는 기법 -> 페이징
181 | 
182 | 
183 | 
184 | 
185 | 
186 | 주변 장치 및 입출력 장치
187 | 
188 | - CPU나 메모리와 달리 인터럽트라는 매커니즘을 통해 관리한다.
189 | - 인터럽트 : CPU의 서비스가 필요한 경우에 신호를 발생시켜 서비스를 요청하게 되는데, 이때 발생시키는 신호를 의미한다.
190 | - 인터럽트 발생시 직전 작업 상태를 저장해두고 인터럽트를 처리한다. 인터럽트 처리가 완료된 이후에는 인터럽트가 발생하기 직전 상태를 복구시켜 중단되었던 작업을 재개한다. (저장해둔 직접 작업을 불러와 이어서 수행한다.)
191 | - 인터럽트 처리 루틴 : 인터럽트가 발생했을 때, 해주어야 할 작업을 정의한 프로그램 코드.
192 | - 컨트롤러를 통해 주변 및 외부 장치를 관리한다.
193 | - 컨트롤러는 해당 장치에 대한 업무를 처리하고 이를 메인 CPU에 인터럽트를 발생시켜 보고하는 역할을 한다.
194 | - Ex) 키보드에 사용자가 입력을 하면 키보드 컨트롤러가 인터럽트를 발생시켜 CPU에게 그 사실을 알려준다. CPU는 현재 수행중이던 작업의 상태를 저장하고 인터럽트 요청을 처리하기 위해 운영 체제 내에 정의된 키보드 인터럽트 처리 루틴을 찾는다. 키보드 인터럽트 처리루틴을 실행하고 완료하게 된다. 인터럽트 처리가 끝나면 인터럽트가 발생하기 직전 상태를 복구시켜 중단되었던 작업을 재개한다.


--------------------------------------------------------------------------------
/운영체제와 정보기술의 원리/인터럽트의 원리.md:
--------------------------------------------------------------------------------
 1 | ## 인터럽트의 원리
 2 | 
 3 | #### 인터럽트란?
 4 | 
 5 | - CPU가 어떤 프로그램을 실행하고 있을 때, 입출력 하드웨어 혹은 소프트웨어에 의해 예외상황이 발생하여 처리가 필요한 경우, CPU에게 이를 알려주는 것을 말한다.
 6 | - 예를 들어, A라는 프로그램이 CPU를 할당받고 명령을 수행하고 있는데, 인터럽트가 발생하면 A는 현재 수행 중인 명령의 위치를 저장해 놓는다. 그 후, 운영 체제 내부의 코드인 인터럽트 처리 루틴으로 가서 인터럽트를 처리한 후, 다시 돌아와 A의 이전 작업 지점부터 수행을 계속 이어나간다.
 7 | - **그렇다면 인터럽트가 발생했을 때, 수행 중이던 프로세스의 정보는 어디에 저장이 되는 것일까??**
 8 | - 운영 체제는 현재 실행 중인 모든 프로그램을 관리하기 위한 자료구조는 커널에 존재한다. 이 자료 구조를 프로세스 제어 블록 PCB(Process Control Block)라 부른다.
 9 | - PCB에는 인터럽트가 발생했을 때, 그 프로그램의 어느 부분까지 수행했는지를 저장하기 위한 영역이 존재한다.
10 | 
11 | 
12 | 
13 | #### 컴퓨터 시스템의 작동 개요
14 | 
15 | CPU가 수행해야 할 메모리 주소를 담고 있는 레지스터를 프로그램 카운터(Program Counter, 이하 PC)라 부른다. 즉, CPU는 매번 PC가 가리키는 메모리 영역의 명령을 처리하게 된다. PC는 항상 바로 다음 주소의 명령을 가리키게 되어 순차적인 수행이 이루어진다.
16 | 
17 | 
18 | 
19 | 컴퓨터 시스템을 구성하는 하드웨어로는 CPU와 메모리가 있고, 이 밖에 각 입출력 장치와 이들 장치를 전담하는 작은 CPU와 메모리가 있으며, 이는 각각 입출력 컨트롤러(I/O controller)와 로컬 버퍼라고 부른다. (입출력 장치별로 존재!)
20 | 
21 | 
22 | 
23 | 메모리에는 사용자 프로그램들과 운영 체제가 같이 올라가 수행된다. 
24 | 
25 | 예를 들어, PC가 메모리 주소 중 운영체제가 존재하는 부분을 가리키고 있다면, 현재 운영 체제의 코드를 수행 중이며, 이 경우 CPU가 커놀 모드에서 수행 중이라고 이야기 한다.
26 | 
27 | 
28 | 
29 | 반대로 PC가 사용자 프로그램이 존재하는 메모리 위치를 가리킬 경우, 그 메모리 위치에 올락가 있는 사용자 프로그램이 수행 중이며, 이 경우 사용자 모드에서 CPU가 수행되고 있다고 이야기 한다.
30 | 
31 | 
32 | 
33 | CPU가 수행하는 명령
34 | 
35 | 1) 일반 명령
36 | 
37 | - 메모리에서 자료를 읽어와서 CPU에서 계산하고 결과를 메모리에 쓰는 일련의 명령들.
38 | - 이러한 일반 명령은 모든 프로그램이 수행할 수 있다.
39 | 
40 | 2) 특권 명령
41 | 
42 | - 보안이 필요한 명령으로 입출력 장치, 타이머 등 각종 장치를 접근하는 명령.
43 | - 운영 체제만이 수행할 수 있도록 제한.
44 | 
45 | 
46 | 
47 | **일반 명령과 특권 명령의 실행 가능성을 체크하기 위해 CPU 내부에 모드 비트를 둔다.**
48 | 
49 | 책에서 설명하고 있는 내용은 앞 Chapter인 [컴퓨터 시스템의 동작 원리] 부분에서 나온 내용과 거의 동일하므로, 더 이상 정리하지 않고 이를 참고하길 바란다.
50 | 
51 | 
52 | 
53 | 
54 | 
55 | 
56 | 
57 | 
58 | 
59 | 
60 | 
61 | 
62 | 
63 | 
64 | 
65 | 
66 | 
67 | 
68 | 
69 | 
70 | 
71 | 
72 | 
73 | 
74 | 
75 | 
76 | 
77 | 
78 | 
79 | 
80 | 
81 | 
82 | 
83 | 
84 | 
85 | 
86 | 
87 | 
88 | 
89 | 
90 | 
91 | 
92 | 
93 | 


--------------------------------------------------------------------------------