master b478de0481da cached
214 files
513.8 KB
233.2k tokens
73 symbols
1 requests
Download .txt
Showing preview only (879K chars total). Download the full file or copy to clipboard to get everything.
Repository: MangKyu/tech-interview-for-developer
Branch: master
Commit: b478de0481da
Files: 214
Total size: 513.8 KB

Directory structure:
gitextract_nbg_fwwo/

├── .github/
│   └── FUNDING.yml
├── Algorithm/
│   ├── Binary Search.md
│   ├── DFS & BFS.md
│   ├── Hash Table 구현하기.md
│   ├── HeapSort.md
│   ├── LCA(Lowest Common Ancestor).md
│   ├── LIS (Longest Increasing Sequence).md
│   ├── MergeSort.md
│   ├── QuickSort.md
│   ├── README.md
│   ├── SAMSUNG Software PRO등급 준비.md
│   ├── Sort_Counting.md
│   ├── Sort_Radix.md
│   ├── code/
│   │   ├── Heap.java
│   │   ├── InsertionSort.java
│   │   ├── QuickSort.java
│   │   ├── bubbleSort.java
│   │   └── mergeSort.java
│   ├── professional/
│   │   └── 프로 준비법.md
│   ├── 간단하지만 알면 좋은 최적화들.md
│   ├── 다익스트라(Dijkstra).md
│   ├── 동적 계획법 (Dynamic Programming).md
│   ├── 비트마스크(BitMask).md
│   ├── 순열 & 조합.md
│   └── 최대공약수 & 최소공배수.md
├── Computer Science/
│   ├── Computer Architecture/
│   │   ├── ARM 프로세서.md
│   │   ├── 고정 소수점 & 부동 소수점.md
│   │   ├── 명령어 Cycle.md
│   │   ├── 중앙처리장치(CPU) 작동 원리.md
│   │   ├── 캐시 메모리(Cache Memory).md
│   │   ├── 컴퓨터의 구성.md
│   │   └── 패리티 비트 & 해밍 코드.md
│   ├── Data Structure/
│   │   ├── Array vs ArrayList vs LinkedList.md
│   │   ├── Array.md
│   │   ├── B Tree & B+ Tree.md
│   │   ├── Binary Search Tree.md
│   │   ├── Hash.md
│   │   ├── Heap.md
│   │   ├── Linked List.md
│   │   ├── README.md
│   │   ├── Stack & Queue.md
│   │   ├── Tree.md
│   │   ├── Trie.md
│   │   └── code/
│   │       ├── MaxHeap.java
│   │       ├── MinHeap.java
│   │       ├── binarySearchTree.java
│   │       ├── juggling_array.cpp
│   │       ├── linked_list.java
│   │       ├── linked_list_push.java
│   │       ├── maxvalue_array.cpp
│   │       ├── rearrange_array.cpp
│   │       ├── reversal_array.cpp
│   │       └── rotate_array.cpp
│   ├── Database/
│   │   ├── Redis.md
│   │   ├── SQL Injection.md
│   │   ├── SQL과 NOSQL의 차이.md
│   │   ├── Transaction Isolation Level.md
│   │   ├── Transaction.md
│   │   ├── [DB] Anomaly.md
│   │   ├── [DB] Index.md
│   │   ├── [DB] Key.md
│   │   ├── [Database SQL] JOIN.md
│   │   ├── 저장 프로시저(Stored PROCEDURE).md
│   │   └── 정규화(Normalization).md
│   ├── Network/
│   │   ├── DNS.md
│   │   ├── HTTP & HTTPS.md
│   │   ├── OSI 7 계층.md
│   │   ├── TCP (흐름제어혼잡제어).md
│   │   ├── TCP 3 way handshake & 4 way handshake.md
│   │   ├── TLS HandShake.md
│   │   ├── UDP.md
│   │   ├── [Network] Blocking Non-Blocking IO.md
│   │   ├── [Network] Blocking,Non-blocking & Synchronous,Asynchronous.md
│   │   ├── 대칭키 & 공개키.md
│   │   └── 로드 밸런싱(Load Balancing).md
│   ├── Operating System/
│   │   ├── CPU Scheduling.md
│   │   ├── DeadLock.md
│   │   ├── File System.md
│   │   ├── IPC(Inter Process Communication).md
│   │   ├── Interrupt.md
│   │   ├── Memory.md
│   │   ├── Operation System.md
│   │   ├── PCB & Context Switcing.md
│   │   ├── Page Replacement Algorithm.md
│   │   ├── Paging and Segmentation.md
│   │   ├── Process Address Space.md
│   │   ├── Process Management & PCB.md
│   │   ├── Process vs Thread.md
│   │   ├── Race Condition.md
│   │   ├── Semaphore & Mutex.md
│   │   └── [OS] System Call (Fork Wait Exec).md
│   └── Software Engineering/
│       ├── Clean Code & Refactoring.md
│       ├── Fuctional Programming.md
│       ├── Object-Oriented Programming.md
│       ├── TDD(Test Driven Development).md
│       ├── 데브옵스(DevOps).md
│       ├── 마이크로서비스 아키텍처(MSA).md
│       ├── 써드파티(3rd party)란.md
│       ├── 애자일(Agile).md
│       ├── 애자일(Agile)2.md
│       └── 클린코드(Clean Code) & 시큐어코딩(Secure Coding).md
├── Design Pattern/
│   ├── Adapter Pattern.md
│   ├── Composite Pattern.md
│   ├── Design Pattern_Adapter.md
│   ├── Design Pattern_Factory Method.md
│   ├── Design Pattern_Template Method.md
│   ├── Observer pattern.md
│   ├── SOLID.md
│   ├── Singleton Pattern.md
│   ├── Strategy Pattern.md
│   ├── Template Method Pattern.md
│   └── [Design Pattern] Overview.md
├── ETC/
│   ├── Collaborate with Git on Javascript and Node.js.md
│   ├── Git Commit Message Convention.md
│   ├── Git vs GitHub vs GitLab Flow.md
│   ├── GitHub Fork로 협업하기.md
│   ├── GitHub 저장소(repository) 미러링.md
│   ├── OPIC.md
│   ├── [인적성] 명제 추리 풀이법.md
│   ├── 반도체 개념정리.md
│   ├── 시사 상식.md
│   └── 임베디드 시스템.md
├── Interview/
│   ├── Interview List.md
│   ├── Mock Test/
│   │   ├── 2019년 #기업 2차 필기테스트 유형.md
│   │   ├── 2019년 #기업 필기테스트.md
│   │   ├── 2019년 면접질문.md
│   │   └── GML Test (2019-10-03).md
│   ├── README.md
│   └── [Java] Interview List.md
├── LICENSE
├── Language/
│   ├── [C++] Vector Container.md
│   ├── [C++] 가상 함수(virtual function).md
│   ├── [C++] 입출력 실행속도 줄이는 법.md
│   ├── [C] 구조체 메모리 크기 계산.md
│   ├── [C] 동적할당.md
│   ├── [C] 포인터(Pointer).md
│   ├── [Cpp] shallow copy vs deep copy.md
│   ├── [Java] Auto Boxing & Unboxing.md
│   ├── [Java] Interned String in JAVA.md
│   ├── [Java] Intrinsic Lock.md
│   ├── [Java] Java 8 정리.md
│   ├── [Java] wait notify notifyAll.md
│   ├── [Java] 직렬화(Serialization).md
│   ├── [Java] 컴포지션(Composition).md
│   ├── [Javascript] Closure.md
│   ├── [Javascript] ES2015+ 요약 정리.md
│   ├── [Javascript] 데이터 타입.md
│   ├── [Javasript] Object Prototype.md
│   ├── [Python] 매크로 라이브러리.md
│   ├── [c] C언어 컴파일 과정.md
│   ├── [java] Call by value와 Call by reference.md
│   ├── [java] Casting(업캐스팅 & 다운캐스팅).md
│   ├── [java] Java major feature changes.md
│   ├── [java] Java에서의 Thread.md
│   ├── [java] Record.md
│   ├── [java] Stream.md
│   ├── [java] String StringBuilder StringBuffer 차이.md
│   ├── [java] 자바 가상 머신(Java Virtual Machine).md
│   └── [java] 자바 컴파일 과정.md
├── Linux/
│   ├── Linux Basic Command.md
│   ├── Permission.md
│   └── Von Neumann Architecture.md
├── New Technology/
│   ├── AI/
│   │   ├── Linear regression 실습.md
│   │   └── README.md
│   ├── Big Data/
│   │   ├── DBSCAN 클러스터링 알고리즘.md
│   │   └── 데이터 분석.md
│   └── IT Issues/
│       ├── 2020 ICT 이슈.md
│       ├── AMD vs Intel.md
│       ├── README.md
│       ├── [2019.08.07] 이메일 공격 증가로 보안업계 대응 비상.md
│       ├── [2019.08.08] IT 수다 정리.md
│       └── [2019.08.20] Google, 크롬 브라우저에서 FTP 지원 중단 확정.md
├── README.md
├── Seminar/
│   ├── 2019 삼성전자 비전캠프.md
│   ├── 2019 삼성전자 오픈소스 컨퍼런스(SOSCON).md
│   ├── NCSOFT 2019 JOB Cafe.md
│   └── NHN 2019 OPEN TALK DAY.md
└── Web/
    ├── CSR & SSR.md
    ├── CSRF & XSS.md
    ├── Cookie & Session.md
    ├── DevOps/
    │   ├── [AWS] 스프링 부트 배포 스크립트 생성.md
    │   ├── [Travis CI] 프로젝트 연동하기.md
    │   └── 시스템 규모 확장.md
    ├── HTTP Request Methods.md
    ├── HTTP status code.md
    ├── JWT(JSON Web Token).md
    ├── Logging Level.md
    ├── Nuxt.js.md
    ├── OAuth.md
    ├── PWA (Progressive Web App).md
    ├── README.md
    ├── REST API.pptx
    ├── React/
    │   ├── React & Spring Boot 연동하여 환경 구축하기.md
    │   ├── React Fragment.md
    │   └── React Hook.md
    ├── Spring/
    │   ├── JPA.md
    │   ├── Spring MVC.md
    │   ├── Spring Security - Authentication and Authorization.md
    │   ├── [Spring Boot] SpringApplication.md
    │   ├── [Spring Boot] Test Code.md
    │   ├── [Spring Data JPA] 더티 체킹 (Dirty Checking).md
    │   └── [Spring] Bean Scope.md
    ├── UI와 UX.md
    ├── Vue/
    │   ├── Vue CLI + Spring Boot 연동하여 환경 구축하기.md
    │   ├── Vue.js + Firebase로 이메일 회원가입로그인 구현.md
    │   ├── Vue.js + Firebase로 페이스북(facebook) 로그인 연동하기.md
    │   └── Vue.js 라이프사이클 이해하기.md
    ├── Vue.js와 React의 차이.md
    ├── Web Server와 WAS의 차이.md
    ├── [Travis CI] 프로젝트 연동하기.md
    ├── [Web] REST API.md
    ├── 네이티브 앱 & 웹 앱 & 하이브리드 앱.md
    ├── 브라우저 동작 방법.md
    └── 인증방식.md

================================================
FILE CONTENTS
================================================

================================================
FILE: .github/FUNDING.yml
================================================
# These are supported funding model platforms

github: gyoogle
patreon: 
open_collective: # Replace with a single Open Collective username
ko_fi: 
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://www.paypal.me/gyoogle


================================================
FILE: Algorithm/Binary Search.md
================================================
## 이분 탐색(Binary Search)

> 탐색 범위를 두 부분으로 분할하면서 찾는 방식

처음부터 끝까지 돌면서 탐색하는 것보다 훨~~~씬 빠른 장점을 지님

```
* 시간복잡도
전체 탐색 : O(N)
이분 탐색 : O(logN)
```

<br>

#### 진행 순서

- 우선 정렬을 해야 함
- left와 right로 mid 값 설정
- mid와 내가 구하고자 하는 값과 비교
- 구할 값이 mid보다 높으면 : left = mid+1
  구할 값이 mid보다 낮으면 : right = mid - 1
- left > right가 될 때까지 계속 반복하기

<br>

#### Code

```java
public static int solution(int[] arr, int M) { // arr 배열에서 M을 찾자
	
    Arrays.sort(arr); // 정렬
	
    int start = 0;
    int end = arr.length - 1;
    int mid = 0;

    while (start <= end) {
        mid = (start + end) / 2;
        if (M == arr[mid]) {
            return mid;
        }else if (arr[mid] < M) {
            start = mid + 1;
        }else if (M < arr[mid]) {
            end = mid - 1;
        }
    }
    throw new NoSuchElementException("타겟 존재하지 않음");
}
```



================================================
FILE: Algorithm/DFS & BFS.md
================================================
# DFS & BFS

<br>

그래프 알고리즘으로, 문제를 풀 때 상당히 많이 사용한다.

경로를 찾는 문제 시, 상황에 맞게 DFS와 BFS를 활용하게 된다.

<br>

### DFS

> 루트 노드 혹은 임의 노드에서 **다음 브랜치로 넘어가기 전에, 해당 브랜치를 모두 탐색**하는 방법

**스택 or 재귀함수**를 통해 구현한다.

<br>

- 모든 경로를 방문해야 할 경우 사용에 적합

<img src="https://upload.wikimedia.org/wikipedia/commons/7/7f/Depth-First-Search.gif" width="300">

##### 시간 복잡도

- 인접 행렬 : O(V^2)
- 인접 리스트 : O(V+E)

> V는 접점, E는 간선을 뜻한다

<br>

##### Code

```c
#include <stdio.h>

int map[1001][1001], dfs[1001];

void init(int *, int size);

void DFS(int v, int N) {

	dfs[v] = 1;
	printf("%d ", v);

	for (int i = 1; i <= N; i++) {
		if (map[v][i] == 1 && dfs[i] == 0) {
			DFS(i, N);
		}
	}

}

int main(void) {

	init(map, sizeof(map) / 4);
	init(dfs, sizeof(dfs) / 4);

	int N, M, V;
	scanf("%d%d%d", &N, &M, &V);

	for (int i = 0; i < M; i++)
	{
		int start, end;
		scanf("%d%d", &start, &end);
		map[start][end] = 1;
		map[end][start] = 1;
	}

	DFS(V, N);

	return 0;
}

void init(int *arr, int size) {
	for (int i = 0; i < size; i++)
	{
		arr[i] = 0;
	}
}
```

<br>

<br>

### BFS

> 루트 노드 또는 임의 노드에서 **인접한 노드부터 먼저 탐색**하는 방법

**큐**를 통해 구현한다. (해당 노드의 주변부터 탐색해야하기 때문)

<br>

- 최소 비용(즉, 모든 곳을 탐색하는 것보다 최소 비용이 우선일 때)에 적합

<img src="https://upload.wikimedia.org/wikipedia/commons/5/5d/Breadth-First-Search-Algorithm.gif" width="300">

##### 시간 복잡도

- 인접 행렬 : O(V^2)
- 인접 리스트 : O(V+E)

##### Code

```c
#include <stdio.h>

int map[1001][1001], bfs[1001];
int queue[1001];

void init(int *, int size);

void BFS(int v, int N) {
	int front = 0, rear = 0;
	int pop;

	printf("%d ", v);
	queue[rear++] = v;
	bfs[v] = 1;

	while (front < rear) {
		pop = queue[front++];

		for (int i = 1; i <= N; i++) {
			if (map[pop][i] == 1 && bfs[i] == 0) {
				printf("%d ", i);
				queue[rear++] = i;
				bfs[i] = 1;
			}
		}
	}

	return;
}

int main(void) {

	init(map, sizeof(map) / 4);
	init(bfs, sizeof(bfs) / 4);
	init(queue, sizeof(queue) / 4);

	int N, M, V;
	scanf("%d%d%d", &N, &M, &V);

	for (int i = 0; i < M; i++)
	{
		int start, end;
		scanf("%d%d", &start, &end);
		map[start][end] = 1;
		map[end][start] = 1;
	}

	BFS(V, N);

	return 0;
}

void init(int *arr, int size) {
	for (int i = 0; i < size; i++)
	{
		arr[i] = 0;
	}
}
```

<br>

**연습문제** : [[BOJ] DFS와 BFS](https://www.acmicpc.net/problem/1260)

<br>

##### [참고 자료]

- [링크](https://developer-mac.tistory.com/64)

================================================
FILE: Algorithm/Hash Table 구현하기.md
================================================
# Hash Table 구현하기

> 알고리즘 문제를 풀기위해 필수적으로 알아야 할 개념

브루트 포스(완전 탐색)으로는 시간초과에 빠지게 되는 문제에서는 해시를 적용시켜야 한다.

<br>

[연습 문제 링크](<https://codeforces.com/contest/4/problem/C>)

<br>

N(1~100000)의 값만큼 문자열이 입력된다.

처음 입력되는 문자열은 "OK", 들어온 적이 있던 문자열은 "문자열+index"로 출력하면 된다.

ex)

##### Input

```
5
abcd
abc
abcd
abcd
ab
```

##### Output

```
OK
OK
abcd1
abcd2
OK
```

<br>

문제를 이해하는 건 쉽다. 똑같은 문자열이 들어왔는지 체크해보고, 들어온 문자열은 인덱스 번호를 부여해서 출력해주면 된다.

<br>

하지만, 현재 N값은 최대 10만이다. 브루트 포스로 접근하면 N^2이 되므로 100억번의 연산이 필요해서 시간초과에 빠질 것이다. 따라서 **'해시 테이블'**을 이용해 해결해야 한다. 

<br>

입력된 문자열 값을 해시 키로 변환시켜 저장하면서 최대한 시간을 줄여나가도록 구현해야 한다.

이 문제는 해시 테이블을 알고리즘에서 적용시켜보기 위해 연습하기에 아주 좋은 문제 같다. 특히 삼성 상시 SW역량테스트 B형을 준비하는 사람들에게 추천하고 싶은 문제다. 해시 테이블 구현을 연습하기 딱 좋다.

<br>

<br>

#### **해시 테이블 구현**

해시 테이블은 탐색을 최대한 줄여주기 위해, input에 대한 key 값을 얻어내서 관리하는 방식이다.

현재 최대 N 값은 10만이다. 이차원 배열로 1000/100으로 나누어 관리하면, 더 효율적일 것이다.

충돌 값이 들어오는 것을 감안해 최대한 고려해서, 나는 두번째 배열 값에 4를 곱해서 선언한다.

<br>

```

key 값을 얻어서 저장할 때, 서로다른 문자열이라도 같은 key 값으로 들어올 수 있다. 
(이것이 해시에 대한 이론을 배울 때 나오는 충돌 현상이다.)

충돌이 일어나는 것을 최대한 피해야하지만, 무조건 피할 수 있다는 보장은 없다. 그래서 두번째 배열 값을 조금 넉넉히 선언해두는 것이다.

```

이를 고려해 final 값으로 선언한 해시 값은 아래와 같다.

```java
static final int HASH_SIZE = 1000;
static final int HASH_LEN = 400;
static final int HASH_VAL = 17; // 소수로 할 것
```

HASH_VAL 값은 우리가 input 값을 받았을 때 해당하는 key 값을 얻을 때 활용한다.

최대한 input 값들마다 key 값이 겹치지 않기 위해 하기 위해서는 소수로 선언해야한다. (그래서 보통 17, 19, 23으로 선언하는 것 같다.)

<br>

key 값을 얻는 메소드 구현 방법은 아래와 같다. ( 각자 사람마다 다르므로 꼭 이게 정답은 아니다 )

```java
public static int getHashKey(String str) {
    
    int key = 0;
    
    for (int i = 0; i < str.length(); i++) {
        key = (key * HASH_VAL) + str.charAt(i);
    }
    
    if(key < 0) key = -key; // 만약 key 값이 음수면 양수로 바꿔주기
    
    return key % HASH_SIZE;
    
}
```

input 값을 매개변수로 받는다. 만약 string 값으로 들어온다고 가정해보자.

string 값의 한글자(character)마다 int형 값을 얻어낼 수 있다. 이를 활용해 string 값의 length만큼 반복문을 돌면서, 그 문자열만의 key 값을 만들어내는 것이 가능하다.

우리는 이 key 값을 배열 인덱스로 활용할 것이기 때문에 음수면 안된다. 만약 key 값의 결과가 음수면 양수로 바꿔주는 조건문이 필요하다.

<br>

마지막으로 return 값으로 key를 우리가 선언한 HASH_SIZE로 나눈 나머지 값을 얻도록 한다.

현재 계산된 key 값은 매우 크기 때문에 HASH_SIZE로 나눈 나머지 값으로 key를 활용할 것이다. (이 때문에 데이터가 많으면 많을수록 충돌되는 key값이 존재할 수 밖에 없다. - 우리는 최대한 충돌을 줄이면서 최적화시키기 위한 것..!)

<br>

이제 우리는 input으로 받은 string 값의 key 값을 얻었다.

해당 key 값의 배열에서 이 값이 들어온 적이 있는지 확인하는 과정이 필요하다.

<br>

이제 우리는 모든 곳을 탐색할 필요없이, 이 key에 해당하는 배열에서만 확인하면 되므로 시간이 엄~~청 절약된다.

<br>

```java
static int[][] data = new int[HASH_SIZE][HASH_LEN];

string str = "apple";

int key = getHashKey(str); // apple에 대한 key 값 얻음

data[key][index]; // 이곳에 apple을 저장해서 관리하면 찾는 시간을 줄일 수 있는 것
```

여기서 HASH_SIZE가 1000이었고, 우리가 key 값을 리턴할 때 1000으로 나눈 나머지로 저장했으므로 이 안에서만 key 값이 들어오게 된다는 것을 이해할 수 있다.

<br>

ArrayList로 2차원배열을 관리하면, 그냥 계속 추가해주면 되므로 구현이 간편하다.

하지만 삼성 sw 역량테스트 B형처럼 라이브러리를 사용하지 못하는 경우에는, 배열로 선언해서 추가해나가야 한다. 또한 ArrayList 활용보다 배열이 훨씬 시간을 줄일 수 있기 때문에 되도록이면 배열을 이용하도록 하자

<br>

여기서 끝은 아니다. 이제 우리는 단순히 key 값만 받아온 것 뿐이다.

해당 key 배열에서, apple이 들어온적이 있는지 없는지 체크해야한다. (문제에서 들어온적 있는건 숫자를 붙여서 출력해야 했기 때문이다.)

<br>

데이터의 수가 많으면 key 배열 안에서 다른 문자열이라도 같은 key로 저장되는 값들이 존재할 것이기 때문에 해당 key 배열을 돌면서 apple과 일치하는 문자열이 있는지 확인하는 과정이 필요하다.

<br>

따라서 key 값을 매개변수로 넣고 문자열이 들어왔던 적이 있는지 체크하는 함수를 구현하자

```java
public static int checking(int key) {
    
    int len = length[key]; // 현재 key에 담긴 수 (같은 key 값으로 들어오는 문자열이 있을 수 있다)
    
    if(len != 0) { // 이미 들어온 적 있음
        
        for (int i = 0; i < len; i++) { // 이미 들어온 문자열이 해당 key 배열에 있는지 확인
            if(str.equals(s_data[key][i])) {
                data[key][i]++;
                return data[key][i];
            }
        }
        
    }
    
    // 들어온 적이 없었으면 해당 key배열에서 문자열을 저장하고 길이 1 늘리기
    s_data[key][length[key]++] = str;

    return -1; // 처음으로 들어가는 경우 -1 리턴
}
```

length[] 배열은 HASH_SIZE만큼 선언된 것으로, key 값을 얻은 후, 처음 들어온 문자열일 때마다 숫자를 1씩 늘려서 해당 key 배열에 몇개의 데이터가 저장되어있는지 확인하는 공간이다.

<br>

**우리가 출력해야하는 조건은 처음 들어온건 "OK" 다시 또 들어온건 "data + 들어온 수"였다.**

<br>

- "OK"로 출력해야 하는 조건

  > 해당 key의 배열 length가 0일 때는 무조건 처음 들어오는 데이터다.
  >
  > 또한 1이상일 때, 그 key 배열 안에서 만약 apple을 찾지 못했다면 이 또한 처음 들어오는 데이터다.

<br>

- "data + 들어온 수"로 출력해야 하는 조건

  > 만약 1이상일 때 key 배열에서 apple 값을 찾았다면 이제 'apple+들어온 수'를 출력하도록 구현해야한다.

<br>

그래서 나는 3개의 배열을 선언해서 활용했다.

```java
static int[][] data = new int[HASH_SIZE][HASH_LEN];
static int[] length = new int[HASH_SIZE];
static String[][] s_data = new String[HASH_SIZE][HASH_LEN];
```

data[][] 배열 : input으로 받는 문자열이 들어온 수를 저장하는 곳

length[] 배열 : key 값마다 들어온 수를 저장하는 곳

s_data[][] 배열 : input으로 받은 문자열을 저장하는 곳 

<br>

진행 과정을 설명하면 아래와 같다. (apple - banana - abc - abc 순으로 입력되고, apple과 abc의 key값은 5로 같다고 가정하겠다.)

<br>

```
1. apple이 들어옴. key 값을 얻으니 5가 나옴. length[5]는 0이므로 처음 들어온 데이터임. length[5]++하고 "OK"출력

2. banana가 들어옴. key 값을 얻으니 3이 나옴. length[3]은 0이므로 처음 들어온 데이터임. length[3]++하고 "OK"출력

<< 중요 >>
3. abc가 들어옴. key 값을 얻으니 5가 나옴. length[5]는 0이 아님. 해당 key 값에 누가 들어온적이 있음. 
length[5]만큼 반복문을 돌면서 s_data[key]의 배열과 abc가 일치하는 값이 있는지 확인함. 현재 length[5]는 1이고, s_data[key][0] = "apple"이므로 일치하는 값이 없기 때문에 length[5]를 1 증가시키고 s_data[key][length[5]]에 abc를 넣고 "OK"출력

<< 중요 >>
4. abc가 들어옴. key 값을 얻으니 5가 나옴. length[5] = 2임.
s_data[key]를 2만큼 반복문을 돌면서 abc가 있는지 찾음. 1번째 인덱스 값에는 apple이 저장되어 있고 2번째 인덱스 값에서 abc가 일치함을 찾았음!!
따라서 해당 data[key][index] 값을 1 증가시키고 이 값을 return 해주면서 메소드를 끝냄
→ 메인함수에서 input으로 들어온 abc 값과 리턴값으로 나온 1을 붙여서 출력해주면 됨 (abc1)
```

<br>

진행과정을 통해 어떤 방식으로 구현되는지 충분히 이해할 수 있을 것이다.

<br>

#### 전체 소스코드

```java
package CodeForces;

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Solution {
	
	static final int HASH_SIZE = 1000;
	static final int HASH_LEN = 400;
	static final int HASH_VAL = 17; // 소수로 할 것
	
	static int[][] data = new int[HASH_SIZE][HASH_LEN];
	static int[] length = new int[HASH_SIZE];
	static String[][] s_data = new String[HASH_SIZE][HASH_LEN];
	static String str;
	static int N;

	public static void main(String[] args) throws Exception {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringBuilder sb = new StringBuilder();
		
		N = Integer.parseInt(br.readLine()); // 입력 수 (1~100000)
		
		for (int i = 0; i < N; i++) {
			
			str = br.readLine();
			
			int key = getHashKey(str);
			int cnt = checking(key);
			
			if(cnt != -1) { // 이미 들어왔던 문자열
				sb.append(str).append(cnt).append("\n");
			}
			else sb.append("OK").append("\n");
		}
		
		System.out.println(sb.toString());
	}
	
	public static int getHashKey(String str) {
		
		int key = 0;
		
		for (int i = 0; i < str.length(); i++) {
			key = (key * HASH_VAL) + str.charAt(i) + HASH_VAL;
		}
		
		if(key < 0) key = -key; // 만약 key 값이 음수면 양수로 바꿔주기
		
		return key % HASH_SIZE;
		
	}
	
	public static int checking(int key) {
		
		int len = length[key]; // 현재 key에 담긴 수 (같은 key 값으로 들어오는 문자열이 있을 수 있다)
		
		if(len != 0) { // 이미 들어온 적 있음
			
			for (int i = 0; i < len; i++) { // 이미 들어온 문자열이 해당 key 배열에 있는지 확인
				if(str.equals(s_data[key][i])) {
					data[key][i]++;
					return data[key][i];
				}
			}
			
		}
		
		// 들어온 적이 없었으면 해당 key배열에서 문자열을 저장하고 길이 1 늘리기
		s_data[key][length[key]++] = str;

		return -1; // 처음으로 들어가는 경우 -1 리턴
	}

}
```



================================================
FILE: Algorithm/HeapSort.md
================================================
#### 힙 소트(Heap Sort)

---



완전 이진 트리를 기본으로 하는 힙(Heap) 자료구조를 기반으로한 정렬 방식

***완전 이진 트리란?***

> 삽입할 때 왼쪽부터 차례대로 추가하는 이진 트리



힙 소트는 `불안정 정렬`에 속함



**시간복잡도**

|   평균   |   최선   |   최악   |
| :------: | :------: | :------: |
| Θ(nlogn) | Ω(nlogn) | O(nlogn) |



##### 과정

1. 최대 힙을 구성
2. 현재 힙 루트는 가장 큰 값이 존재함. 루트의 값을 마지막 요소와 바꾼 후, 힙의 사이즈 하나 줄임
3. 힙의 사이즈가 1보다 크면 위 과정 반복



<img src="https://t1.daumcdn.net/cfile/tistory/999896445AD4953023">

루트를 마지막 노드로 대체 (11 → 4), 다시 최대 힙 구성

<img src="https://t1.daumcdn.net/cfile/tistory/99E1AD445AD4953015">



이와 같은 방식으로 최대 값을 하나씩 뽑아내면서 정렬하는 것이 힙 소트



```java
public void heapSort(int[] array) {
    int n = array.length;
    
    // max heap 초기화
    for (int i = n/2-1; i>=0; i--){
        heapify(array, n, i); // 1
    }
    
    // extract 연산
    for (int i = n-1; i>0; i--) {
        swap(array, 0, i); 
        heapify(array, i, 0); // 2
    }
}
```



##### 1번째 heapify

> 일반 배열을 힙으로 구성하는 역할
>
> 자식노드로부터 부모노드 비교
>
> 
>
> - *n/2-1부터 0까지 인덱스가 도는 이유는?*
>
>   부모 노드의 인덱스를 기준으로 왼쪽 자식노드 (i*2 + 1), 오른쪽 자식 노드(i*2 + 2)이기 때문



##### 2번째 heapify

> 요소가 하나 제거된 이후에 다시 최대 힙을 구성하기 위함
>
> 루트를 기준으로 진행(extract 연산 처리를 위해)



```java
public void heapify(int array[], int n, int i) {
    int p = i;
    int l = i*2 + 1;
    int r = i*2 + 2;
    
    //왼쪽 자식노드
    if (l < n && array[p] < array[l]) {
        p = l;
    }
    //오른쪽 자식노드
    if (r < n && array[p] < array[r]) {
        p = r;
    }
    
    //부모노드 < 자식노드
    if(i != p) {
        swap(array, p, i);
        heapify(array, n, p);
    }
}
```

**다시 최대 힙을 구성할 때까지** 부모 노드와 자식 노드를 swap하며 재귀 진행



퀵정렬과 합병정렬의 성능이 좋기 때문에 힙 정렬의 사용빈도가 높지는 않음.

하지만 힙 자료구조가 많이 활용되고 있으며, 이때 함께 따라오는 개념이 `힙 소트`



##### 힙 소트가 유용할 때

- 가장 크거나 가장 작은 값을 구할 때

  > 최소 힙 or 최대 힙의 루트 값이기 때문에 한번의 힙 구성을 통해 구하는 것이 가능

- 최대 k 만큼 떨어진 요소들을 정렬할 때

  > 삽입정렬보다 더욱 개선된 결과를 얻어낼 수 있음



##### 전체 소스 코드

```java
private void solve() {
    int[] array = { 230, 10, 60, 550, 40, 220, 20 };
 
    heapSort(array);
 
    for (int v : array) {
        System.out.println(v);
    }
}
 
public static void heapify(int array[], int n, int i) {
    int p = i;
    int l = i * 2 + 1;
    int r = i * 2 + 2;
 
    if (l < n && array[p] < array[l]) {
        p = l;
    }
 
    if (r < n && array[p] < array[r]) {
        p = r;
    }
 
    if (i != p) {
        swap(array, p, i);
        heapify(array, n, p);
    }
}
 
public static void heapSort(int[] array) {
    int n = array.length;
 
    // init, max heap
    for (int i = n / 2 - 1; i >= 0; i--) {
        heapify(array, n, i);
    }
 
    // for extract max element from heap
    for (int i = n - 1; i > 0; i--) {
        swap(array, 0, i);
        heapify(array, i, 0);
    }
}
 
public static void swap(int[] array, int a, int b) {
    int temp = array[a];
    array[a] = array[b];
    array[b] = temp;
}
```



================================================
FILE: Algorithm/LCA(Lowest Common Ancestor).md
================================================
## LCA(Lowest Common Ancestor) 알고리즘

> 최소 공통 조상 찾는 알고리즘
>
> → 두 정점이 만나는 최초 부모 정점을 찾는 것!

트리 형식이 아래와 같이 주어졌다고 하자

<img src="https://media.geeksforgeeks.org/wp-content/cdn-uploads/lca.png" width=400>

4와 5의 LCA는? → 4와 5의 첫 부모 정점은 '2'

4와 6의 LCA는? → 첫 부모 정점은 root인 '1'

***어떻게 찾죠?***

해당 정점의 depth와 parent를 저장해두는 방식이다. 현재 그림에서의 depth는 아래와 같을 것이다.

```
[depth : 정점]
0 → 1(root 정점)
1 → 2, 3
2 → 4, 5, 6, 7
```

<br>

parent는 정점마다 가지는 부모 정점을 저장해둔다. 위의 예시에서 저장된 parent 배열은 아래와 같다.

```java
// 1 ~ 7번 정점 (root는 부모가 없기 때문에 0)
int parent[] = {0, 1, 1, 2, 2, 3, 3}
```

이제

이 두 배열을 활용해서 두 정점이 주어졌을 때 LCA를 찾을 수 있다. 과정은 아래와 같다.

```java
// 두 정점의 depth 확인하기
while(true){
	if(depth가 일치)
		if(두 정점의 parent 일치?) LCA 찾음(종료)
        else 두 정점을 자신의 parent 정점 값으로 변경
    else // depth 불일치
        더 depth가 깊은 정점을 해당 정점의 parent 정점으로 변경(depth가 감소됨)
}
```

<br>

트리 문제에서 공통 조상을 찾아야하는 문제나, 정점과 정점 사이의 이동거리 또는 방문경로를 저장해야 할 경우 사용하면 된다. 

================================================
FILE: Algorithm/LIS (Longest Increasing Sequence).md
================================================
## LIS (Longest Increasing Sequence)

> 최장 증가 수열 : 가장 긴 증가하는 부분 수열

[ 7, **2**, **3**, 8, **4**, **5** ] → 해당 배열에서는 [2,3,4,5]가 LIS로 답은 4

<br>

##### 구현 방법 (시간복잡도)

1. DP : O(N^2)
2. Lower Bound : O(NlogN)

<br>

##### DP 활용 코드

```java
int arr[] = {7, 2, 3, 8, 4, 5};
int dp[] = new int[arr.length]; // LIS 저장 배열


for(int i = 1; i < dp.length; i++) {
    for(int j = i-1; j>=0; j--) {
        if(arr[i] > arr[j]) {
            dp[i] = (dp[i] < dp[j]+1) ? dp[j]+1 : dp[i];
        }
    }
}

for (int i = 0; i < dp.length; i++) {
	if(max < dp[i]) max = dp[i];
}

// 저장된 dp 배열 값 : [0, 0, 1, 2, 2, 3]
// LIS : dp배열에 저장된 값 중 최대 값 + 1
```

<br>

하지만, N^2으로 해결할 수 없는 문제라면? (ex. 배열의 길이가 최대 10만일 때..)

이때는 Lower Bound를 활용한 LIS 구현을 진행해야한다.



================================================
FILE: Algorithm/MergeSort.md
================================================
#### 머지 소트(Merge Sort)

---



합병 정렬이라고도 부르며, 분할 정복 방법을 통해 구현

***분할 정복이란?***

> 큰 문제를 작은 문제 단위로 쪼개면서 해결해나가는 방식



빠른 정렬로 분류되며, 퀵소트와 함께 많이 언급되는 정렬 방식이다.



퀵소트와는 반대로 `안정 정렬`에 속함

**시간복잡도**

|   평균   |   최선   |   최악   |
| :------: | :------: | :------: |
| Θ(nlogn) | Ω(nlogn) | O(nlogn) |

요소를 쪼갠 후, 다시 합병시키면서 정렬해나가는 방식으로, 쪼개는 방식은 퀵정렬과 유사



- mergeSort

```java
public void mergeSort(int[] array, int left, int right) {
    
    if(left < right) {
        int mid = (left + right) / 2;
        
        mergeSort(array, left, mid);
        mergeSort(array, mid+1, right);
        merge(array, left, mid, right);
    }
    
}
```

정렬 로직에 있어서 merge() 메소드가 핵심



*퀵소트와의 차이점*

> 퀵정렬 : 우선 피벗을 통해 정렬(partition) → 영역을 쪼갬(quickSort)
>
> 합병정렬 : 영역을 쪼갤 수 있을 만큼 쪼갬(mergeSort) →  정렬(merge)



- merge()

```java
public static void merge(int[] array, int left, int mid, int right) {
    int[] L = Arrays.copyOfRange(array, left, mid + 1);
    int[] R = Arrays.copyOfRange(array, mid + 1, right + 1);
    
    int i = 0, j = 0, k = left;
    int ll = L.length, rl = R.length;
    
    while(i < ll && j < rl) {
        if(L[i] <= R[j]) {
            array[k] = L[i++];
        }
        else {
            array[k] = R[j++];
        }
        k++;
    }
    
    // remain
    while(i < ll) {
        array[k++] = L[i++];
    }
    while(j < rl) {
        array[k++] = R[j++];
    }
}
```

이미 **합병의 대상이 되는 두 영역이 각 영역에 대해서 정렬이 되어있기 때문**에 단순히 두 배열을 **순차적으로 비교하면서 정렬할 수가 있다.**





**★★★합병정렬은 순차적**인 비교로 정렬을 진행하므로, **LinkedList의 정렬이 필요할 때 사용하면 효율적**이다.★★★



*LinkedList를 퀵정렬을 사용해 정렬하면?*

> 성능이 좋지 않음
>
> 퀵정렬은, 순차 접근이 아닌 **임의 접근이기 때문**



**LinkedList는 삽입, 삭제 연산에서 유용**하지만 **접근 연산에서는 비효율적**임

따라서 임의로 접근하는 퀵소트를 활용하면 오버헤드 발생이 증가하게 됨

> 배열은 인덱스를 이용해서 접근이 가능하지만, LinkedList는 Head부터 탐색해야 함
>
> 배열[O(1)] vs LinkedList[O(n)] 





```java
private void solve() {
    int[] array = { 230, 10, 60, 550, 40, 220, 20 };
 
    mergeSort(array, 0, array.length - 1);
 
    for (int v : array) {
        System.out.println(v);
    }
}
 
public static void mergeSort(int[] array, int left, int right) {
    if (left < right) {
        int mid = (left + right) / 2;
 
        mergeSort(array, left, mid);
        mergeSort(array, mid + 1, right);
        merge(array, left, mid, right);
    }
}
 
public static void merge(int[] array, int left, int mid, int right) {
    int[] L = Arrays.copyOfRange(array, left, mid + 1);
    int[] R = Arrays.copyOfRange(array, mid + 1, right + 1);
 
    int i = 0, j = 0, k = left;
    int ll = L.length, rl = R.length;
 
    while (i < ll && j < rl) {
        if (L[i] <= R[j]) {
            array[k] = L[i++];
        } else {
            array[k] = R[j++];
        }
        k++;
    }
 
    while (i < ll) {
        array[k++] = L[i++];
    }
 
    while (j < rl) {
        array[k++] = R[j++];
    }
}
```



================================================
FILE: Algorithm/QuickSort.md
================================================
안전 정렬 : 동일한 값에 기존 순서가 유지 (버블, 삽입)

불안정 정렬 : 동일한 값에 기존 순서가 유지X (선택,퀵)



#### 퀵소트

---

퀵소트는 최악의 경우 O(n^2), 평균적으로 Θ(nlogn)을 가짐



```java
public void quickSort(int[] array, int left, int right) {
    
    if(left >= right) return;
    
    int pi = partition(array, left, right);
    
    quickSort(array, left, pi-1);
    quickSort(array, pi+1, right);
    
}
```



피벗 선택 방식 : 첫번째, 중간, 마지막, 랜덤

(선택 방식에 따라 속도가 달라지므로 중요함)



```java
public int partition(int[] array, int left, int right) {
    int pivot = array[left];
    int i = left, j = right;
    
    while(i < j) {
        while(pivot < array[j]) {
            j--;
        }
        while(i<j && pivot >= array[i]){
            i++;
        }
        swap(array, i, j);
    }
    array[left] = array[i];
    array[i] = pivot;
    
    return i;
}
```

1. 피벗 선택
2. 오른쪽(j)에서 왼쪽으로 가면서 피벗보다 작은 수 찾음
3. 왼쪽(i)에서 오른쪽으로 가면서 피벗보다 큰 수 찾음
4. 각 인덱스 i, j에 대한 요소를 교환
5. 2,3,4번 과정 반복
6. 더이상 2,3번 진행이 불가능하면, 현재 피벗과 교환
7. 이제 교환된 피벗 기준으로 왼쪽엔 피벗보다 작은 값, 오른쪽엔 큰 값들만 존재함



---



버블정렬은 모든 배열의 요소에 대한 인덱스를 하나하나 증가하며 비교해나가는 O(n^2)

퀵정렬의 경우 인접한 것이 아닌 서로 먼 거리에 있는 요소를 교환하면서 속도를 줄일 수 있음

But, **피벗 값이 최소나 최대값으로 지정되어 파티션이 나누어지지 않았을 때** O(n^2)에 대한 시간복잡도를 가짐



#### 퀵소트 O(n^2) 해결 방법

---

이런 상황에서는 퀵소트 장점이 사라지므로, 피벗을 선택할 때 `중간 요소`로 선택하면 해결이 가능함



```java
public int partition(int[] array, int left, int right) {
    int mid = (left + right) / 2;
    swap(array, left, mid);
    ...
}
```

이는 다른 O(nlogn) 시간복잡도를 가진 소트들보다 빠르다고 알려져있음

> 먼거리 교환 처리 + 캐시 효율(한번 선택된 기준은 제외시킴)



```java
private void solve() {
    int[] array = { 80, 70, 60, 50, 40, 30, 20 };
    quicksort(array, 0, array.length - 1);
 
    for (int v : array) {
        System.out.println(v);
    }
}
 
public static int partition(int[] array, int left, int right) {
    int mid = (left + right) / 2;
    swap(array, left, mid);
 
    int pivot = array[left];
    int i = left, j = right;
 
    while (i < j) {
        while (pivot < array[j]) {
            j--;
        }
 
        while (i < j && pivot >= array[i]) {
            i++;
        }
        swap(array, i, j);
    }
    array[left] = array[i];
    array[i] = pivot;
    return i;
}
 
public static void swap(int[] array, int a, int b) {
    int temp = array[b];
    array[b] = array[a];
    array[a] = temp;
}
 
public static void quicksort(int[] array, int left, int right) {
    if (left >= right) {
        return;
    }
 
    int pi = partition(array, left, right);
 
    quicksort(array, left, pi - 1);
    quicksort(array, pi + 1, right);
}

```



================================================
FILE: Algorithm/README.md
================================================
## 알고리즘(코딩테스트) 문제 접근법

<br>

#### Data Structure

1. **배열** : 임의의 사이즈를 선언 (Heap, Queue, Binary Tree, Hashing 사용)
2. **스택** : 행 특정조건에 따라 push, pop 적용
3. **큐** : BFS를 통해 순서대로 접근할 때 적용
4. **연결리스트** : 배열 구현, 포인터 구현 2가지 방법 - 삽입,삭제가 많이 일어날 때 활용하기
5. **그래프** : 경우의 수, 연결 관계가 있을 때 적용
6. **해싱** : 데이터 수만큼 메모리에 생성할 수 없는 상황에 적용
7. **트리** : Heap과 BST(이진탐색)

<br>

#### Algorithm

1. **★재귀(Recursion)** : 가장 많이 활용. 중요한 건 호출 횟수를 줄여야 함 (반복 조건, 종료 조건 체크)
2. **★BFS, DFS** : 2차원 배열에서 확장 시, 경우의 수를 탐색할 때 구조체(class)와 visited 체크를 사용함
3. **★정렬** : 퀵소트나 머지소트가 대표적이지만, 보통 퀵소트를 사용함
4. **★메모이제이션(memoization)** : 이전 결과가 또 사용될 때, 반복 작업을 안하도록 저장
5. **★이분탐색(Binary Search)** : logN으로 시간복잡도를 줄일 수 있는 간단하면서 핵심적인 알고리즘
6. **최소신장트리(MST)** : 사이클이 포함되지 않고 모든 정점이 연결된 트리에 사용 (크루스칼, 프림)
7. **최소공통조상(LCA)** : 경우의 수에서 조건이 겹치는 경우. 최단 경로 탐색시 공통인 경우가 많을 때 적용
8. **Disjoint-Set** : 서로소 집합. 인접한 집함의 모임으로 Tree의 일종이며 시간복잡도가 낮음
9. **분할 정복** : 머지 소트에 사용되며 범위를 나누어 확인할 때 사용
10. **트라이(Trie)** : 모든 String을 저장해나가며 비교하는 방법
11. **비트마스킹** : `|는 OR, &는 AND, ^는 XOR` <<를 통해 메모리를 절약할 수 있음

<br>

- Sort 시간복잡도

<img src="https://gmlwjd9405.github.io/images/algorithm-quick-sort/sort-time-complexity.png">



================================================
FILE: Algorithm/SAMSUNG Software PRO등급 준비.md
================================================
## SAMSUNG Software PRO등급 준비

작성 : 2020.08.10.

<br>

#### 역량 테스트 단계

---

- *Advanced*

- #### *Professional*

- *Expert*

<br>

**시험 시간 및 문제 수** : 4시간 1문제

Professional 단계부터는 라이브러리를 사용할 수 없다.

> C/Cpp 경우, 동적할당 라이브러리인 `malloc.h`까지만 허용

<br>

또한 전체적인 로직은 구현이 되어있는 상태이며, 사용자가 필수적으로 구현해야 할 메소드 부분이 빈칸으로 제공된다. (`main.cpp`와 `user.cpp`가 주어지며, 우리는 `user.cpp`를 구현하면 된다)

<br>

크게 두 가지 유형으로 출제되고 있다.

1. **실행 시간을 최대한 감소**시켜 문제를 해결하라
2. **쿼리 함수를 최소한 실행**시켜 문제를 해결하라

결국, 최대한 **효율적인 코드를 작성하여 시간, 메모리를 절약하는 것**이 Professinal 등급의 핵심이다.

<br>

Professional 등급 문제를 해결하기 위해 필수적으로 알아야 할 것(직접 구현할 수 있어야하는) 들

##### [박트리님 블로그 참고 - '역량테스트 B형 공부법'](https://baactree.tistory.com/53)

- 큐, 스택
- 정렬
- 힙
- 해싱
- 연결리스트
- 트리
- 메모이제이션
- 비트마스킹
- 이분탐색
- 분할정복

추가 : 트라이, LCA, BST, 세그먼트 트리 등 

<br>

## 문제 풀기 연습

> 60분 - 설계
>
> 120분 - 구현
>
> 60분 - 디버깅 및 최적화 

<br>

### 설계

---

1. #### 문제 빠르게 이해하기

   시험 문제는 상세한 예제를 통해 충분히 이해할 수 있도록 제공된다. 따라서 우선 읽으면서 전체적으로 어떤 문제인지 **전체적인 틀을 파악**하자

   <br>

2. #### 구현해야 할 함수 확인하기

   문제에 사용자가 구현해야 할 함수가 제공된다. 특히 필요한 파라미터와 리턴 타입을 알려주므로, 어떤 방식으로 인풋과 아웃풋이 이뤄질 지 함수를 통해 파악하자

   <br>

3. #### 제약 조건 확인하기

   문제의 전체적인 곳에서, 범위 값이 작성되어 있을 것이다. 또한 문제의 마지막에는 제약 조건이 있다. 이 조건들은 문제를 풀 때 핵심이 되는 부분이다. 반드시 체크를 해두고, 설계 시 하나라도 빼먹지 않도록 주의하자

   <br>

4. #### 해결 방법 고민하기

   문제 이해와 구현 함수 파악이 끝났다면, 어떤 방식으로 해결할 것인지 작성해보자.

   전체적인 프로세스를 전개하고, 이때 필요한 자료구조, 구조체 등 설계의 큰 틀부터 그려나간다.

   최대값으로 문제에 주어졌을 때 필요한 사이즈가 얼마인 지, 어떤 타입의 변수들을 갖추고 있어야 하는 지부터 해시나 연결리스트를 사용할 자료구조에 대해 미리 파악 후 작성해두도록 한다.

   <br>

5. #### 수도 코드 작성하기

   각 프로세스 별로, 필요한 로직에 대해 간단히 수도 코드를 작성해두자. 특히 제약 조건이나 놓치기 쉬운 것들은 미리 체크해두고, 작성해두면 구현으로 옮길 때 실수를 줄일 수 있다.

<br>

##### *만약 설계 중 도저히 흐름이 이해가 안간다면?*

> 높은 확률로 main.cpp에서 답을 찾을 수 있다. 문제 이해가 잘 되지 않을 때는, main.cpp와 user.cpp 사이에 어떻게 연결되는 지 main.cpp 코드를 뜯어보고 이해해보자.

<br>

### 구현

---

1. #### 설계한 프로세스를 주석으로 옮기기

   내가 해결할 방향에 대해 먼저 코드 안에 주석으로 핵심만 담아둔다. 이 주석을 보고 필요한 부분을 구현해나가면 설계를 완벽히 옮기는 데 큰 도움이 된다.

   <br>

2. #### 먼저 전역에 필요한 부분 작성하기

   소스 코드 내 전체적으로 활용될 구조체 및 전역 변수들에 대한 부분부터 구현을 시작한다. 이때 `#define`와 같은 전처리기를 적극 활용하여 선언에 필요한 값들을 미리 지정해두자

   <br>

3. #### Check 함수들의 동작 여부 확인하기

   문자열 복사, 비교 등 모두 직접 구현해야 하므로, 혹시 실수를 대비하여 함수를 만들었을 때 제대로 동작하는 지 체크하자. 이때 실수한 걸 넘어가면, 디버깅 때 찾기 위해서 엄청난 고생을 할 수도 있다.

   <br>

4. #### 다시 한번 제약조건 확인하기

   결국 디버깅에서 문제가 되는 건 제약 조건을 제대로 지키지 않았을 경우가 다반사다. 코드 내에서 제약 조건을 모두 체크하여 잘 구현했는 지 확인해보자

<br>

### 디버깅 및 최적화

---

1. #### input 데이터 활용하기

   input 데이터가 text 파일로 주어진다. 물론 방대한 데이터의 양이라 디버깅을 하려면 매우 까다롭다. 보통 1~2번 테스트케이스는 작은 데이터 값이므로, 이 값들을 활용해 문제점을 찾아낼 수도 있다.

   <br>

2. #### main.cpp를 디버깅에 활용하기

   문제가 발생했을 때, main.cpp를 활용하여 디버깅을 할 수도 있다. 문제가 될만한 부분에 출력값을 찍어보면서 도움이 될만한 부분을 찾아보자. 문제에 따라 다르겠지만, 생각보다 main.cpp 안의 코드에서 중요한 정보들을 깨달을 수도 있다.

   <br>

3. #### init 함수 고민하기

   어쩌면 가장 중요한 함수이기도 하다. 이 초기화 함수를 얼마나 효율적으로 구현하느냐에 따라 합격 유무가 달라진다. 최대한 매 테스트케이스마다 초기화하는 변수들이나 공간을 줄여야 실행 시간을 줄일 수 있다. 따라서 인덱스를 잘 관리하여 init 함수를 잘 짜보는 연습을 해보자

   <br>

4. #### 실행 시간 감소 고민하기

   이 밖에도 실행 시간을 줄이기 위한 고민을 끝까지 해야하는 것이 중요하다. 문제를 accept 했다고 해서 합격을 하는 시험이 아니다. 다른 지원자들보다 효율적이고 빠른 시간으로 문제를 풀어야 pass할 수 있다. 내가 작성한 자료구조보다 더 빠른 해결 방법이 생각났다면, 수정 과정을 거쳐보기도 하고, 많이 활용되는 변수에는 register를 적용하는 등 최대한 실행 시간을 감소시킬 수 있는 방안을 생각하여 적용하는 시도를 해야한다.

<br>

<br>

## 시험 대비

1. #### 비슷한 문제 풀어보기

   임직원들만 이용할 수 있는 사내 SWEA 사이트에서 기출과 유사한 유형의 문제들을 제공해준다. 특히 시험 환경과 똑같이 이뤄지기 때문에 연습해보기 좋다. 많은 문제들을 풀어보면서 유형에 익숙해지는 것이 가장 중요할 것 같다.

   <br>

2. #### 다른 사람 코드로 배우기

   이게 개인적으로 핵심인 것 같다. 1번에서 말한 사이트에서 기출 유형 문제들을 해결한 사람들의 코드를 볼 수 있도록 제공되어 있다. 특히 해결된 코드의 실행 시간이나 사용 메모리도 볼 수 있다는 점이 좋다. 따라서 문제 해결에 어려움이 있거나, 더 나은 코드를 배우기 위해 적극적으로 활용해야 한다.

   <br>

<br>

올해 안에 꼭 합격하자!
(2021.05 합격)


================================================
FILE: Algorithm/Sort_Counting.md
================================================
#### Comparison Sort

------

> N개 원소의 배열이 있을 때, 이를 모두 정렬하는 가짓수는 N!임
>
> 따라서, Comparison Sort를 통해 생기는 <u>트리의 말단 노드</u>가 N! 이상의 노드 갯수를 갖기 위해서는, 2^h >= N! 를 만족하는 h를 가져야 하고, 이 식을 h > O(nlgn)을 가져야 한다. (h는 트리의 높이,,, 즉 Comparison sort의 시간 복잡도임)

이런 O(nlgn)을 줄일 수 있는 방법은 Comparison을 하지 않는 것



#### Counting Sort 과정

----

시간 복잡도 : O(n + k) -> k는 배열에서 등장하는 최대값

공간 복잡도 : O(k) -> k만큼의 배열을 만들어야 함.

Counting이 필요 : 각 숫자가 몇 번 등장했는지 센다.

```c
int arr[5]; 		// [5, 4, 3, 2, 1]
int sorted_arr[5];
// 과정 1 - counting 배열의 사이즈를 최대값 5가 담기도록 크게 잡기
int counting[6];	// 단점 : counting 배열의 사이즈의 범위를 가능한 값의 범위만큼 크게 잡아야 하므로, 비효율적이 됨.

// 과정 2 - counting 배열의 값을 증가해주기.
for (int i = 0; i < arr.length; i++) {
    counting[arr[i]]++;
}
// 과정 3 - counting 배열을 누적합으로 만들어주기.
for (int i = 1; i < counting.length; i++) {
    counting[i] += counting[i - 1];
}
// 과정 4 - 뒤에서부터 배열을 돌면서, 해당하는 값의 인덱스에 값을 넣어주기.
for (int i = arr.length - 1; i >= 0; i--) {
    sorted_arr[counting[arr[i]] - 1] = arr[i];
    counting[arr[i]]--;
}
```

* 사용 : 정렬하는 숫자가 특정한 범위 내에 있을 때 사용

  (Suffix Array 를 얻을 때, 시간복잡도 O(nlgn)으로 얻을 수 있음.)

* 장점 : O(n) 의 시간복잡도

* 단점 : 배열 사이즈 N 만큼 돌 때, 증가시켜주는 Counting 배열의 크기가 큼.

  (메모리 낭비가 심함)

================================================
FILE: Algorithm/Sort_Radix.md
================================================
#### Comparison Sort

---

> N개 원소의 배열이 있을 때, 이를 모두 정렬하는 가짓수는 N!임
>
> 따라서, Comparison Sort를 통해 생기는 <u>트리의 말단 노드</u>가 N! 이상의 노드 갯수를 갖기 위해서는, 2^h >= N! 를 만족하는 h를 가져야 하고, 이 식을 h > O(nlgn)을 가져야 한다. (h는 트리의 높이,,, 즉 Comparison sort의 시간 복잡도임)

이런 O(nlgn)을 줄일 수 있는 방법은 Comparison을 하지 않는 것



#### Radix sort

----

데이터를 구성하는 기본 요소 (Radix) 를 이용하여 정렬을 진행하는 방식

> 입력 데이터의 최대값에 따라서 Counting Sort의 비효율성을 개선하기 위해서, Radix Sort를 사용할 수 있음.
>
> 자릿수의 값 별로 (예) 둘째 자리, 첫째 자리) 정렬을 하므로, 나올 수 있는 값의 최대 사이즈는 9임 (범위 : 0 ~ 9)

* 시간 복잡도 : O(d * (n + b))  

  -> d는 정렬할 숫자의 자릿수, b는 10 (k와 같으나 10으로 고정되어 있다.)

  ( Counting Sort의 경우 : O(n + k) 로 배열의 최댓값 k에 영향을 받음 )

* 장점 : 문자열, 정수 정렬 가능

* 단점 : 자릿수가 없는 것은 정렬할 수 없음. (부동 소숫점)

  중간 결과를 저장할 bucket 공간이 필요함.

#### 소스 코드

```c
void countSort(int arr[], int n, int exp) {
	int buffer[n];
    int i, count[10] = {0};
    
    // exp의 자릿수에 해당하는 count 증가
    for (i = 0; i < n; i++){
        count[(arr[i] / exp) % 10]++;
    }
    // 누적합 구하기
    for (i = 1; i < 10; i++) {
        count[i] += count[i - 1];
    }
    // 일반적인 Counting sort 과정
    for (i = n - 1; i >= 0; i--) {
        buffer[count[(arr[i]/exp) % 10] - 1] = arr[i];
        count[(arr[i] / exp) % 10]--;
    }
    for (i = 0; i < n; i++){
        arr[i] = buffer[i];
    }
}

void radixsort(int arr[], int n) {
     // 최댓값 자리만큼 돌기
    int m = getMax(arr, n);
    
    // 최댓값을 나눴을 때, 0이 나오면 모든 숫자가 exp의 아래
    for (int exp = 1; m / exp > 0; exp *= 10) {
        countSort(arr, n, exp);
    }
}
int main() {
    int arr[] = {170, 45, 75, 90, 802, 24, 2, 66};
    int n = sizeof(arr) / sizeof(arr[0]);			// 좋은 습관
    radixsort(arr, n);
    
    for (int i = 0; i < n; i++){
        cout << arr[i] << " ";
    }
    return 0;
}
```



#### 질문

---

Q1) 왜 낮은 자리수부터 정렬을 합니까?

MSD (Most-Significant-Digit) 과 LSD (Least-Significant-Digit)을 비교하라는 질문

MSD는 가장 큰 자리수부터 Counting sort 하는 것을 의미하고, LSD는 가장 낮은 자리수부터 Counting sort 하는 것을 의미함. (즉, 둘 다 할 수 있음)

* LSD의 경우 1600000 과 1을 비교할 때, Digit의 갯수만큼 따져야하는 단점이 있음.
  그에 반해 MSD는 마지막 자리수까지 확인해 볼 필요가 없음.
* LSD는 중간에 정렬 결과를 알 수 없음. (예) 10004와 70002의 비교)
  반면, MSD는 중간에 중요한 숫자를 알 수 있음. 따라서 시간을 줄일 수 있음. 그러나, 정렬이 되었는지 확인하는 과정이 필요하고, 이 때문에 메모리를 더 사용
* LSD는 알고리즘이 일관됨 (Branch Free algorithm)
  그러나 MSD는 일관되지 못함. --> 따라서 Radix sort는 주로 LSD를 언급함.
* LSD는 자릿수가 정해진 경우 좀 더 빠를 수 있음.

================================================
FILE: Algorithm/code/Heap.java
================================================
public class Heap {
	
	static int N, heapSize;
	static int[] arr;
	
	static void init(int n) {
		N = n;
		arr = new int[N+1];
		heapSize = 0;
	}
	
	static void add(int n) {
		arr[++heapSize] = n;
		
		for (int i = heapSize; i > 1; i/=2) {
			if(arr[i] < arr[i/2]) {
				swap(i/2, i);
			}
			else break;
		}
	}
	static int remove(int[] arr) {
		if(heapSize == 0) return 0;
		
		int rm = arr[1];
		arr[1] = arr[heapSize];
		arr[heapSize--] = 0;
		
		for (int i = 1; i*2 <= heapSize;) {
			
			if(i*2+1 <= heapSize) {
			
				if(arr[i] < arr[i*2] && arr[i] < arr[i*2+1]) break;
				
				else if(arr[i*2] < arr[i*2+1]) {
					swap(i, i*2);
					i = i*2;
				}
				else {
					swap(i, i*2+1);
					i = i*2+1;
				}
			}
			else {
				if(arr[i] > arr[i*2]) {
					swap(i, i*2);
					i = i*2;
				}
				else
					break;
			}
		}
		
		return rm;
	}
	
	static void swap(int a, int b) {
		int temp = arr[a];
		arr[a] = arr[b];
		arr[b] = temp;
	}
}


================================================
FILE: Algorithm/code/InsertionSort.java
================================================
public class InsertionSort {
    
    static int[] arr = {10, 2, 6, 4, 3, 7, 5};
    
    public static void insertionSort(int[] arr) {
        for(int i = 1; i < arr.length; i++) {
            int num = arr[i]; // 기준
            int aux = i - 1; // 비교대상
            
            while(aux >= 0 && num < arr[aux]) {
                arr[aux+1] = arr[aux];
                aux--;
            }
            arr[aux+1] = num;
        }
    }
    
    public static void main(String[] args) {
        
        insertionSort(arr);
        System.out.println(Arrays.toString(arr));
    }
    
}


================================================
FILE: Algorithm/code/QuickSort.java
================================================
import java.util.Arrays;

public class QuickSort {
	
	static int[] arr = {5, 1, 1, 2, 1, 4, 4, 4, 5, 5};
	
	public static void main(String[] args) throws Exception {
		
		quickSort(arr, 0, arr.length-1);
		
		System.out.println(Arrays.toString(arr));
		
	}
	
	public static void quickSort(int[] arr, int start, int end) {
		
		if(start >= end) return;
		
		if(start < end) {
			
			int i = start-1;
			int j = end+1;
			int pivot = arr[(start+end)/2];
			
			while(i < j) {
				
				while(arr[++i] < pivot) {}
				while(arr[--j] > pivot) {}
				
				if (i >= j) break;
				
				int temp = arr[i];
				arr[i] = arr[j];
				arr[j] = temp;
			}
			
			quickSort(arr, start, i-1);
			quickSort(arr, j+1, end);
		}
		
	}
}


================================================
FILE: Algorithm/code/bubbleSort.java
================================================
void bubbleSort(int[] arr) {
    int temp = 0;
	for(int i = 0; i < arr.length; i++) {
		for(int j= 1 ; j < arr.length-i; j++) {
			if(arr[j-1] > arr[j]) {
				temp = arr[j-1];
				arr[j-1] = arr[j];
				arr[j] = temp;
			}
		}
	}
	System.out.println(Arrays.toString(arr));
}


================================================
FILE: Algorithm/code/mergeSort.java
================================================
import java.util.Arrays;
import java.util.Random;

public class mergeSort {
	// SIZE 십 만
	static int MAX_LEN = 100_000;

	public static void main(String[] args) {

		Random r = new Random(100);
		int merge_idx, collections_idx;
		int arr_merge[], arr_collections[];

		merge_idx = 0;
		collections_idx = 0;
		arr_merge = new int[MAX_LEN];
		arr_collections = new int[MAX_LEN];

		// 랜덤으로 배열을 생성하는 부분
		for (int i = 0; i < MAX_LEN; i++) {
			int temp = (r.nextInt() % 10000);
			arr_merge[merge_idx++] = temp;
			arr_collections[collections_idx++] = temp;
		}

		Arrays.sort(arr_collections);
		mergeSort(arr_merge, 0, MAX_LEN - 1);

		// 정렬이 제대로 되었는지 확인하는 부분.
		for (int i = 0; i < MAX_LEN; i++) {
			if (arr_collections[i] != arr_merge[i]) {
				System.out.println("MergeSort 실패!");
				return;
			}
		}
		System.out.println("MergeSort 성공");
		return;
	}

	private static void mergeSort(int[] arr, int left, int right) {

		// (1) 재귀 호출을 통해 더이상 쪼개지지 않을 때까지 쪼개야 된다.
		if (left >= right)
			return;

		int mid = (left + right) / 2;
		int i = left;
		int j = mid+1;

		mergeSort(arr, left, mid);
		mergeSort(arr, mid+1, right);

		// (2) 배열을 인덱스를 통해서 절반으로 쪼개고, 한쪽이 다 쓸 때까지 반복문을 돌린다.
		int[] buffer = new int[right - left + 1];
		int bidx = 0;
		
		// 왼쪽이랑 오른쪽 각각 비교
		while (true) {
			if(arr[i] <= arr[j]) { // stable
				buffer[bidx++] = arr[i];
				i++;
			} else {
				buffer[bidx++] = arr[j];
				j++;
			}
			
			if(i > mid || j > right) 
				break;
		}

		// (3) 남은 것(오른쪽 or 왼쪽)을 전부 buffer에 넣어야 한다.
		// 왼쪽 전부 써버리기
		while(i <= mid) {
			buffer[bidx++] = arr[i++];
		}
		//오른쪽 전부 써버리기
		while(j <= right) {
			buffer[bidx++] = arr[j++];
		}

		// (4) buffer에 있는 것을 기존 배열의 인덱스 위에 덮어준다.
		for (int k = 0; k < bidx; k++) {
			arr[left+k] = buffer[k];
		}
	}
}


================================================
FILE: Algorithm/professional/프로 준비법.md
================================================
# 프로 준비법

<br>

#### Professional 시험 주요 특징

- 4시간동안 1문제를 푼다.
- 언어는 `c, cpp, java`로 가능하다.
- 라이브러리를 사용할 수 없으며, 직접 자료구조를 구현해야한다. (`malloc.h`만 가능)
- 전체적인 로직은 구현이 되어있는 상태이며, 사용자가 구현해야 할 메소드 부분이 빈칸으로 제공된다. (`main.cpp`와 `user.cpp`가 주어지며, 우리는 `user.cpp`를 구현하면 된다)
- 시험 유형 2가지
  - 1) 내부 테스트케이스를 제한 메모리, 시간 내에 해결해야한다. (50개 3초, 메모리 256MB 이내)
  - 2) 주어진 쿼리 함수를 최소한으로 호출하여 문제를 해결해야 한다.
- 주로 샘플 테스트케이스는 5개가 주어지며, 이를 활용해 디버깅을 해볼 수 있다.
- 시험장에서는 Reference Code가 주어지며 사용할 수 있다. (자료구조, 알고리즘)

<br>

#### 핵심 자료구조

- Queue, Stack
- Sort
- Linked List
- Hash
- Heap
- Binary Search

<br>

### 학습 시작

---

#### 1) Visual Studio 설정하기

1. Visual C++ 빈 프로젝트 생성

2. `user.cpp`와 `main.cpp` 생성

3. 프로젝트명 오른쪽 마우스 클릭 → 속성

4. `C/C++`에서 SDL 검사 아니요로 변경

   > 디버깅할 때 scanf나 printf를 사용하기 위함

5. `링커/시스템`에서 맨위 `하위 시스템`이 공란이면 `콘솔(/SUBSYSTEM:CONSOLE)`로 설정

   > 공란이면 run할 때 콘솔창이 켜있는 상태로 유지가 되지 않음 (반드시 설정)

<br>

#### 2) cpp로 프로 문제 풀 때 알아야 할 것

- printf로 출력 확인해보기 위한 라이브러리 : `#include <stdio.h>`. 제출시에는 꼭 지우기

- 구조체 : `struct`

- 포인터 : 주소값 활용

- 문자열

  > 문자열의 맨 마지막에는 항상 `'\0'`로 끝나야한다.

  - 문자열 복사 (a에 b를 복사)

    ```cpp
    char a[5];
    char b[5] = {'a', 'b', 'c', 'd', '\0'};
    
    void strcopy(char *a, char *b) {
        while(*a++ = *b++);
    }
    
    int main(void) {
        strcopy(a, b); // a 배열에 b의 'abcd'가 저장됌
    }
    ```

  - 문자열 비교

    ```cpp
    char a[5] = {'b', 'b', 'c', 'd', '\0'};
    char b[5] = {'a', 'b', 'c', 'd', '\0'};
    
    int strcompare(char *a, char *b) {
        int i;
        for(i = 0; a[i] && a[i] == b[i]; ++i);
        
        return a[i] - b[i];
    }
    
    int main(void) {
        int res = strcompare(a, b); // a가 b보다 작으면 음수, 크면 양수, 같으면 0
    }
    ```

  - 문자열 초기화

    > 특수히 중간에 초기화가 필요할 때만 사용

    ```cpp
    void strnull(char *a) {
        *a = 0;
    }
    ```

================================================
FILE: Algorithm/간단하지만 알면 좋은 최적화들.md
================================================
## [알고리즘] 간단하지만 알면 좋은 최적화들

**1. for문의 ++i와 i++ 차이**

```
for(int i = 0; i < 1000; i++) { ... } 

for(int i = 0; i < 1000; ++i) { ... }
```

내부 operator 로직을 보면 i++은 한번더 연산을 거친다.

따라서 ++i가 미세하게 조금더 빠르다.

하지만 요즘 컴파일러는 거의 차이가 없어지게 되었다고 한다.

  

**2. if/else if vs switch case**

> '20개의 가지 수, 10억번의 연산이 진행되면?' 

if/else 활용 : 약 20초

switch case : 약 15초

 

**switch case**가 더 빠르다. (경우를 찾아서 접근하기 때문에 더 빠르다)

if-else 같은 경우는 다 타고 들어가야하기 때문에 더 느리다.

  

**3. for문 안에서 변수 선언 vs for문 밖에서 변수 선언** 

임시 변수의 선언 위치에 따른 비교다.

for문 밖에서 변수를 선언하는 것이 더 빠르다.

 

 

**4. 재귀함수 파라미터를 전역으로 선언한 것 vs 재귀함수를 모두 파라미터로 넘겨준 것**

> '10억번의 연산을 했을 때?' 

전역으로 선언 : 약 6.8초

파라미터로 넘겨준 것 : 약 9.6초

 

함수를 계속해서 호출할 때, 스택에서 쌓인다. 파라미터들은 함수를 호출할 때마다 메모리 할당하는 동작을 반복하게 된다. 따라서 지역 변수로 사용하지 않는 것들은 전역 변수로 빼야한다.

================================================
FILE: Algorithm/다익스트라(Dijkstra).md
================================================
# 다익스트라(Dijkstra) 알고리즘

<br>

```
DP를 활용한 최단 경로 탐색 알고리즘
```

<br>



<img src="https://upload.wikimedia.org/wikipedia/commons/5/57/Dijkstra_Animation.gif">

<br>

다익스트라 알고리즘은 특정한 정점에서 다른 모든 정점으로 가는 최단 경로를 기록한다.

여기서 DP가 적용되는 이유는, 굳이 한 번 최단 거리를 구한 곳은 다시 구할 필요가 없기 때문이다. 이를 활용해 정점에서 정점까지 간선을 따라 이동할 때 최단 거리를 효율적으로 구할 수 있다.

<br>

다익스트라를 구현하기 위해 두 가지를 저장해야 한다.

- 해당 정점까지의 최단 거리를 저장

- 정점을 방문했는 지 저장

시작 정점으로부터 정점들의 최단 거리를 저장하는 배열과, 방문 여부를 저장하는 것이다.

<br>

다익스트라의 알고리즘 순서는 아래와 같다.

1. ##### 최단 거리 값은 무한대 값으로 초기화한다.

   ```java
   for(int i = 1; i <= n; i++){
       distance[i] = Integer.MAX_VALUE;
   }
   ```

2. ##### 시작 정점의 최단 거리는 0이다. 그리고 시작 정점을 방문 처리한다.

   ```java
   distance[start] = 0;
   visited[start] = true;
   ```

3. ##### 시작 정점과 연결된 정점들의 최단 거리 값을 갱신한다.

   ```java
   for(int i = 1; i <= n; i++){
       if(!visited[i] && map[start][i] != 0) {
       	distance[i] = map[start][i];
       }
   }
   ```

4. ##### 방문하지 않은 정점 중 최단 거리가 최소인 정점을 찾는다.

   ```java
   int min = Integer.MAX_VALUE;
   int midx = -1;
   
   for(int i = 1; i <= n; i++){
       if(!visited[i] && distance[i] != Integer.MAX_VALUE) {
       	if(distance[i] < min) {
               min = distance[i];
               midx = i;
           }
       }
   }
   ```

5. ##### 찾은 정점을 방문 체크로 변경 후, 해당 정점과 연결된 방문하지 않은 정점의 최단 거리 값을 갱신한다.

   ```java
   visited[midx] = true;
   for(int i = 1; i <= n; i++){
       if(!visited[i] && map[midx][i] != 0) {
       	if(distance[i] > distance[midx] + map[midx][i]) {
               distance[i] = distance[midx] + map[midx][i];
           }
       }
   }
   ```

6. ##### 모든 정점을 방문할 때까지 4~5번을 반복한다.

<br>

#### 다익스트라 적용 시 알아야할 점

- 인접 행렬로 구현하면 시간 복잡도는 O(N^2)이다.

- 인접 리스트로 구현하면 시간 복잡도는 O(N*logN)이다.

  > 선형 탐색으로 시간 초과가 나는 문제는 인접 리스트로 접근해야한다. (우선순위 큐)

- 간선의 값이 양수일 때만 가능하다.

<br>

<br>

#### [참고사항]

- [링크](https://ko.wikipedia.org/wiki/%EB%8D%B0%EC%9D%B4%ED%81%AC%EC%8A%A4%ED%8A%B8%EB%9D%BC_%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98)
- [링크](https://bumbums.tistory.com/4)

================================================
FILE: Algorithm/동적 계획법 (Dynamic Programming).md
================================================
## 동적 계획법 (Dynamic Programming)

> 복잡한 문제를 간단한 여러 개의 문제로 나누어 푸는 방법

<br>

흔히 말하는 DP가 바로 '동적 계획법'

**한 가지 문제**에 대해서, **단 한 번만 풀도록** 만들어주는 알고리즘이다.

즉, 똑같은 연산을 반복하지 않도록 만들어준다. 실행 시간을 줄이기 위해 많이 이용되는 수학적 접근 방식의 알고리즘이라고 할 수 있다.

<br>

동적 계획법은 **Optimal Substructure**에서 효과를 발휘한다.

*Optimal Substructure* : 답을 구하기 위해 이미 했던 똑같은 계산을 계속 반복하는 문제 구조

<br>

#### 접근 방식

커다란 문제를 쉽게 해결하기 위해 작게 쪼개서 해결하는 방법인 분할 정복과 매우 유사하다. 하지만 간단한 문제로 만드는 과정에서 중복 여부에 대한 차이점이 존재한다.

즉, 동적 계획법은 간단한 작은 문제들 속에서 '계속 반복되는 연산'을 활용하여 빠르게 풀 수 있는 것이 핵심이다.

<br>

#### 조건

- 작은 문제에서 반복이 일어남
- 같은 문제는 항상 정답이 같음

이 두 가지 조건이 충족한다면, 동적 계획법을 이용하여 문제를 풀 수 있다.

같은 문제가 항상 정답이 같고, 반복적으로 일어난다는 점을 활용해 메모이제이션(Memoization)으로 큰 문제를 해결해나가는 것이다.

<br>

*메모이제이션(Memoization)* : 한 번 계산한 문제는 다시 계산하지 않도록 저장해두고 활용하는 방식

> 피보나치 수열에서 재귀를 활용하여 풀 경우, 같은 연산을 계속 반복함을 알 수 있다.
>
> 이때, 메모이제이션을 통해 같은 작업을 되풀이 하지 않도록 구현하면 효율적이다.

```
fibonacci(5) = fibonacci(4) + fibonacci(3)
fibonacci(4) = fibonacci(3) + fibonacci(2)
fibonacci(3) = fibonacci(2) + fibonacci(1)

이처럼 같은 연산이 계속 반복적으로 이용될 때, 메모이제이션을 활용하여 값을 미리 저장해두면 효율적
```

피보나치 구현에 재귀를 활용했다면 시간복잡도는 O(2^n)이지만, 동적 계획법을 활용하면 O(N)으로 해결할 수 있다.

<br>

#### 구현 방식

- Bottom-up : 작은 문제부터 차근차근 구하는 방법
- Top-down : 큰 문제를 풀다가 풀리지 않은 작은 문제가 있다면 그때 해결하는 방법 (재귀 방식)

> Bottom-up은 해결이 용이하지만, 가독성이 떨어짐
>
> Top-down은 가독성이 좋지만, 코드 작성이 힘듬

<br>

동적 계획법으로 문제를 풀 때는, 우선 작은 문제부터 해결해나가보는 것이 좋다.

작은 문제들을 풀어나가다보면 이전에 구해둔 더 작은 문제들이 활용되는 것을 확인하게 된다. 이에 대한 규칙을 찾았을 때 **점화식**을 도출해내어 동적 계획법을 적용시키자

<br>

<br>

##### [참고 자료]

- [링크](https://namu.wiki/w/%EB%8F%99%EC%A0%81%20%EA%B3%84%ED%9A%8D%EB%B2%95)

================================================
FILE: Algorithm/비트마스크(BitMask).md
================================================
## 비트마스크(BitMask)

> 집합의 요소들의 구성 여부를 표현할 때 유용한 테크닉

<br>

##### *왜 비트마스크를 사용하는가?*

- DP나 순열 등, 배열 활용만으로 해결할 수 없는 문제
- 작은 메모리와 빠른 수행시간으로 해결이 가능 (But, 원소의 수가 많지 않아야 함)
- 집합을 배열의 인덱스로 표현할 수 있음

- 코드가 간결해짐

<br>

##### *비트(Bit)란?*

> 컴퓨터에서 사용되는 데이터의 최소 단위 (0과 1)
>
> 2진법을 생각하면 편하다.

<br>

우리가 흔히 사용하는 10진수를 2진수로 바꾸면?

`9(10진수) → 1001(2진수)`

<br>

#### 비트마스킹 활용해보기

> 0과 1로, flag 활용하기

[1, 2, 3, 4 ,5] 라는 집합이 있다고 가정해보자.

여기서 임의로 몇 개를 골라 뽑아서 확인을 해야하는 상황이 주어졌다. (즉, 부분집합을 의미)

```
{1}, {2} , ... , {1,2} , ... , {1,2,5} , ... , {1,2,3,4,5}
```

물론, 간단히 for문 돌려가며 배열에 저장하며 경우의 수를 구할 순 있다.

하지만 비트마스킹을 하면, 각 요소를 인덱스처럼 표현하여 효율적인 접근이 가능하다.

```
[1,2,3,4,5] → 11111
[2,3,4,5]   → 11110
[1,2,5]     → 10011
[2]         → 00010
```

집합의 i번째 요소가 존재하면 `1`, 그렇지 않으면 `0`을 의미하는 것이다.

이러한 2진수는 다시 10진수로 변환도 가능하다.

`11111`은 10진수로 31이므로, 부분집합을 **정수를 통해 나타내는 것**이 가능하다는 것을 알 수 있다.

> 31은 [1,2,3,4,5] 전체에 해당하는 부분집합에 해당한다는 의미!

이로써, 해당 부분집합에 i를 추가하고 싶을때 i번째 비트를 1로만 바꿔주면 표현이 가능해졌다.

이런 행위는 **비트 연산**을 통해 제어가 가능하다.

<br>

#### 비트 연산

> AND, OR, XOR, NOT, SHIFT

- AND(&) : 대응하는 두 비트가 모두 1일 때, 1 반환

- OR(|) : 대응하는 두 비트 중 모두 1이거나 하나라도 1일때, 1 반환

- XOR(^) : 대응하는 두 비트가 서로 다를 때, 1 반환

- NOT(~) : 비트 값 반전하여 반환

- SHIFT(>>, <<) : 왼쪽 혹은 오른쪽으로 비트 옮겨 반환

  - 왼쪽 시프트 : `A * 2^B`
  - 오른쪽 시프트 : `A / 2^B`

  ```
  [왼  쪽] 0001 → 0010 → 0100 → 1000 : 1 → 2 → 4 → 8
  [오른쪽] 1000 → 0100 → 0010 → 0001 : 8 → 4 → 2 → 1
  ```

<br>

비트연산 연습문제 : [백준 12813](https://www.acmicpc.net/problem/12813)

##### 구현 코드(C)

```C
#include <stdio.h>

int main(void) {
	unsigned char A[100001] = { 0, };
	unsigned char B[100001] = { 0, };
	unsigned char ret[100001] = { 0, };
	int i;

	scanf("%s %s", &A, &B);

    // AND
	for (i = 0; i < 100000; i++)
		ret[i] = A[i] & B[i];
	puts(ret);
    
    // OR
	for (i = 0; i < 100000; i++)
		ret[i] = A[i] | B[i];
	puts(ret);

    // XOR
	for (i = 0; i < 100000; i++)
		ret[i] = A[i] != B[i] ? '1' : '0';
	puts(ret);

    // ~A
	for (i = 0; i < 100000; i++)
		ret[i] = A[i] == '1' ? '0' : '1';
	puts(ret);

    // ~B
	for (i = 0; i < 100000; i++)
		ret[i] = B[i] == '1' ? '0' : '1';
	puts(ret);

	return 0;
}
```

<br>

연습이 되었다면, 다시 비트마스크로 돌아와 비트연산을 활용해보자

크게 삽입, 삭제, 조회로 나누어 진다.

<br>

#### 1.삽입

현재 이진수로 `10101`로 표현되고 있을 때, i번째 비트 값을 1로 변경하려고 한다.

i = 3일 때 변경 후에는 `11101`이 나와야 한다. 이때는 **OR연산을 활용**한다.

```
10101 | 1 << 3
```

`1 << 3`은 `1000`이므로 `10101 | 01000`이 되어 `11101`을 만들 수 있다.

<br>

#### 2.삭제

반대로 0으로 변경하려면, **AND연산과 NOT 연산을 활용**한다.

```
11101 & ~1 << 3
```

`~1 << 3`은 `10111`이므로, `11101 & 10111`이 되어 `10101`을 만들 수 있다.

<br>

#### 3.조회

i번째 비트가 무슨 값인지 알려면, **AND연산을 활용**한다.

```
10101 & 1 << i

3번째 비트 값 : 10101 & (1 << 3) = 10101 & 01000 → 0
4번째 비트 값 : 10101 & (1 << 4) = 10101 & 10000 → 10000
```

이처럼 결과값이 0이 나왔을 때는 i번째 비트 값이 0인 것을 파악할 수 있다. (반대로 0이 아니면 무조건 1인 것)

이러한 방법을 활용하여 문제를 해결하는 것이 비트마스크다.

<br>

비트마스크 연습문제 : [백준 2098](https://www.acmicpc.net/problem/2098)

<br>

해당 문제는 모든 도시를 한 번만 방문하면서 다시 시작점으로 돌아오는 최소 거리 비용을 구해야한다.

완전탐색으로 답을 구할 수는 있지만, N이 최대 16이기 때문에 16!으로 시간초과에 빠지게 된다.

따라서 DP를 활용해야 하며, 방문 여부를 배열로 관리하기 힘드므로 비트마스크를 활용하면 좋은 문제다.

<br>

<br>

##### [참고자료]

- [링크](https://mygumi.tistory.com/361)



================================================
FILE: Algorithm/순열 & 조합.md
================================================
# 순열 & 조합

<br>

### Java 코드

```java
import java.util.ArrayList;
import java.util.Arrays;

public class 순열조합 {
	static char[] arr = { 'a', 'b', 'c', 'd' };
	static int r = 2;

	//arr배열에서 r개를 선택한다.
	//선택된 요소들은 set배열에 저장.
	public static void main(String[] args) {

		set = new char[r];
		
		System.out.println("==조합==");
		comb(0,0);

		System.out.println("==중복조합==");
		rcomb(0, 0);
		
		visit = new boolean[arr.length];
		System.out.println("==순열==");
		perm(0);

		System.out.println("==중복순열==");
		rperm(0);
		
		System.out.println("==부분집합==");
		setList = new ArrayList<>();
		subset(0,0);
	}

	static char[] set;

	public static void comb(int len, int k) { // 조합
		if (len == r) {
			System.out.println(Arrays.toString(set));
			return;
		}
		if (k == arr.length)
			return;

		set[len] = arr[k];

		comb(len + 1, k + 1);
		comb(len, k + 1);

	}

	public static void rcomb(int len, int k) { // 중복조합
		if (len == r) {
			System.out.println(Arrays.toString(set));
			return;
		}
		if (k == arr.length)
			return;

		set[len] = arr[k];

		rcomb(len + 1, k);
		rcomb(len, k + 1);

	}

	static boolean[] visit;

	public static void perm(int len) {// 순열
		if (len == r) {
			System.out.println(Arrays.toString(set));
			return;
		}

		for (int i = 0; i < arr.length; i++) {
			if (!visit[i]) {
				set[len] = arr[i];
				visit[i] = true;
				perm(len + 1);
				visit[i] = false;
			}
		}
	}

	public static void rperm(int len) {// 중복순열
		if (len == r) {
			System.out.println(Arrays.toString(set));
			return;
		}

		for (int i = 0; i < arr.length; i++) {
			set[len] = arr[i];
			rperm(len + 1);
		}
	}

	static ArrayList<Character> setList;

	public static void subset(int len, int k) {// 부분집합
		System.out.println(setList);
		if (len == arr.length) {
			return;
		}
		for (int i = k; i < arr.length; i++) {
			setList.add(arr[i]);
			subset(len + 1, i + 1);
			setList.remove(setList.size() - 1);
		}
	}
}
```



================================================
FILE: Algorithm/최대공약수 & 최소공배수.md
================================================
### [알고리즘] 최대공약수 & 최소공배수

---

면접 손코딩으로 출제가 많이 되는 유형 - 초등학교 때 배운 최대공약수와 최소공배수를 구현하기

최대 공약수는 `유클리드 공식`을 통해 쉽게 도출해낼 수 있다.

ex) 24와 18의 최대공약수는?

##### 유클리드 호제법을 활용하자!

> 주어진 값에서 큰 값 % 작은 값으로 나머지를 구한다.
>
> 나머지가 0이 아니면, 작은 값 % 나머지 값을 재귀함수로 계속 진행
>
> 나머지가 0이 되면, 그때의 작은 값이 '최대공약수'이다.
>
> **최소 공배수**는 간단하다. 주어진 값들끼리 곱한 값을 '최대공약수'로 나누면 끝! 

```java
public static void main(String[] args) {
	int a = 24; int b = 18;
	int res = gcd(a,b);
	System.out.println("최대공약수 : " + res);
	System.out.println("최소공배수 : " + (a*b)/res); // a*b를 최대공약수로 나눈다
}

public static int gcd(int a, int b) { // 최대공약수
	
	if(a < b) swap(a,b)// b가 더 크면 swap
	
	int num = a%b;
	if(num == 0) return b;
	
	return gcd(b, num);
}
```


================================================
FILE: Computer Science/Computer Architecture/ARM 프로세서.md
================================================
## ARM 프로세서

<br>

*프로세서란?*

> 메모리에 저장된 명령어들을 실행하는 유한 상태 오토마톤

<br>

##### ARM : Advanced RISC Machine

즉, `진보된 RISC 기기`의 약자로 ARM의 핵심은 RISC이다.

RISC : Reduced Instruction Set Computing (감소된 명령 집합 컴퓨팅)

`단순한 명령 집합을 가진 프로세서`가 `복잡한 명령 집합을 가진 프로세서`보다 훨씬 더 효율적이지 않을까?로 탄생함

<br>

<br>

#### ARM 구조

---

<img src="https://t1.daumcdn.net/cfile/tistory/25788C3550CAF8731A" width="500">

<br>

ARM은 칩의 기본 설계 구조만 만들고, 실제 기능 추가와 최적화 부분은 개별 반도체 제조사의 영역으로 맡긴다. 따라서 물리적 설계는 같아도, 명령 집합이 모두 다르기 때문에 서로 다른 칩이 되기도 하는 것이 ARM.

소비자에게는 칩이 논리적 구조인 명령 집합으로 구성되면서, 이런 특성 때문에 물리적 설계 베이스는 같지만 용도에 따라 다양한 제품군을 만날 수 있는 특징이 있다.

아무래도 아키텍처는 논리적인 명령 집합을 물리적으로 표현한 것이므로, 명령어가 많고 복잡해질수록 실제 물리적인 칩 구조도 크고 복잡해진다.

하지만, ARM은 RISC 설계 기반으로 '단순한 명령집합을 가진 프로세서가 복잡한 것보다 효율적'임을 기반하기 때문에 명령 집합과 구조 자체가 단순하다. 따라서 ARM 기반 프로세서가 더 작고, 효율적이며 상대적으로 느린 것이다.

<br>

단순한 명령 집합은, 적은 수의 트랜지스터만 필요하므로 간결한 설계와 더 작은 크기를 가능케 한다. 반도체 기본 부품인 트랜지스터는 전원을 소비해 다이의 크기를 증가시키기 때문에 스마트폰이나 태블릿PC를 위한 프로세서에는 가능한 적은 트랜지스터를 가진 것이 이상적이다.

따라서, 명령 집합의 수가 적기 때문에 트랜지스터 수가 적고 이를 통해 크기가 작고 전원 소모가 낮은 ARM CPU가 스마트폰, 태블릿PC와 같은 모바일 기기에 많이 사용되고 있다.

<br>

<br>

#### ARM의 장점은?

---

<img src="https://t1.daumcdn.net/cfile/tistory/1970603350CD96BC35" width=200>

<br>

소비자에 있어 ARM은 '생태계'의 하나라고 생각할 수 있다. ARM을 위해 개발된 프로그램은 오직 ARM 프로세서가 탑재된 기기에서만 실행할 수 있다. (즉, x86 CPU 프로세서 기반 프로그램에서는 ARM 기반 기기에서 실행할 수 없음)

따라서 ARM에서 실행되던 프로그램을 x86 프로세서에서 실행되도록 하려면 (혹은 그 반대로) 프로그램에 수정이 가해져야만 한다.

 <br>

하지만, 하나의 ARM 기기에 동작하는 OS는 다른 ARM 기반 기기에서도 잘 동작한다. 이러한 장점 덕분에 수많은 버전의 안드로이드가 탄생하고 있으며 또한 HP나 블랙베리의 태블릿에도 안드로이드가 탑재될 수 있는 가능성이 생기게 된 것이다.

(하지만 애플사는 iOS 소스코드를 공개하지 않고 있기 때문에 애플 기기는 불가능하다)

ARM을 만드는 기업들은 전력 소모를 줄이고 성능을 높이기 위해 설계를 개선하며 노력하고 있다.

<br>

<br>

<br>

##### [참고 자료]

- [링크](https://sergeswin.com/611)


================================================
FILE: Computer Science/Computer Architecture/고정 소수점 & 부동 소수점.md
================================================
## 고정 소수점 & 부동 소수점

<br>

컴퓨터에서 실수를 표현하는 방법은 `고정 소수점`과 `부동 소수점` 두가지 방식이 존재한다.

<br>

1. #### 고정 소수점(Fixed Point)

   > 소수점이 찍힐 위치를 미리 정해놓고 소수를 표현하는 방식 (정수 + 소수)
   >
   > ```
   > -3.141592는 부호(-)와 정수부(3), 소수부(0.141592) 3가지 요소 필요함
   > ```

   ![고정 소수점 방식](http://tcpschool.com/lectures/img_c_fixed_point.png)

   **장점** : 실수를 정수부와 소수부로 표현하여 단순하다.

   **단점** : 표현의 범위가 너무 적어서 활용하기 힘들다. (정수부는 15bit, 소수부는 16bit)

   <br>

   <br>

2. #### 부동 소수점(Floating Point)

   > 실수를 가수부 + 지수부로 표현한다.
   >
   > - 가수 : 실수의 실제값 표현
   > - 지수 : 크기를 표현함. 가수의 어디쯤에 소수점이 있는지 나타냄

   **지수의 값에 따라 소수점이 움직이는 방식**을 활용한 실수 표현 방법이다.

   즉, 소수점의 위치가 고정되어 있지 않는다.

   ![32비트 부동 소수점](http://tcpschool.com/lectures/img_c_floating_point_32.png)

   **장점** : 표현할 수 있는 수의 범위가 넓어진다. (현재 대부분 시스템에서 활용 중)

   **단점** :  오차가 발생할 수 있다. (부동소수점으로 표현할 수 있는 방법이 매우 다양함)
   
   <br>

   <br>
   
3. #### 고정 소수점과 부동 소수점의 일반적인 사용 사례.

**고정 소수점 사용 상황.**
1. 임베디드 시스켐과 마이크로컨트롤러
    - 메모리와 처리 능력이 제한된 환경에서 고정 소수점 연산이 일반적입니다. 이는 부동 소수점 연산을 지원하는 하드웨어가 없거나, 그러한 연산이 배터리 수명이나 다른 자원을 과도하게 소모할 수 있기 때문입니다.

2. 실시간 시스템
    - 예측 가능한 실행 시간이 중요한 실시간 응용 프로그램에서는 고정 소수점 연산이 선호됩니다. 이는 부동 소수점 연산이 가변적인 실행 시간을 가질 수 있기 때문입니다.

3. 비용 민감형 하드웨어
    - 부동 소수점 연산자를 지원하는 비용이 더 들 수 있어, 가격을 낮추기 위해 고정 소수점 연산을 사용하는 경우가 있습니다.

4. 디지털 신호 처리(DSP)
    - 일부 디지털 신호 처리 알고리즘은 정확하게 정의된 범위 내의 값을 사용하기 때문에 고정 소수점 연산으로 충분한 경우가 많습니다.

**부동 소수점 사용 상황.**
1. 과학적 계산
    - 넓은 범위의 값과 높은 정밀도가 요구되는 과학적 및 엔지니어링 계산에는 부동 소수점이 사용됩니다.

2. 3D 그래픽스
    - 3D 모델링과 같은 그래픽 작업에서는 부동 소수점 연산이 광범위하게 사용되며, 높은 정밀도와 다양한 크기의 값을 처리할 수 있어야 합니다.

3. 금융 분석
    - 복잡한 금융 모델링과 위험 평가에서는 높은 수준의 정밀도가 필요할 수 있으며, 부동 소수점 연산이 적합할 수 있습니다.

4. 컴퓨터 시뮬레이션
    - 물리적 시스템의 시뮬레이션은 넓은 범위의 값과 높은 정밀도를 요구하기 때문에, 부동 소수점 연산이 필수적입니다.

**결론.**
- 고정 소수점은 주로 리소스가 제한적이고 높은 정밀도가 필요하지 않은 환경에서 사용됩니다.
- 부동 소수점은 더 넓은 범위와 높은 정밀도를 필요로 하는 복잡한 계산에 적합합니다.
- 현대 프로세서의 경우, 부동 소수점 연산의 속도도 매우 빨라져서 예전만큼 고정 소수점과 부동 소수점 사이의 성능 차이가 크지 않을 수 있습니다.


================================================
FILE: Computer Science/Computer Architecture/명령어 Cycle.md
================================================
## 명령어 Cycle

- PC : 다음 실행할 명령어의 주소를 저장
- MAR : 다음에 읽거나 쓸 기억장소의 주소를 지정
- MBR : 기억장치에 저장될 데이터 혹은 기억장치로부터 읽은 데이터를 임시 저장
- IR : 현재 수행 중인 명령어 저장
- ALU : 산술연산과 논리연산 수행

<br>

#### Fetch Cycle

---

> 명령어를 주기억장치에서 CPU 명령어 레지스터로 가져와 해독하는 단계

1) PC에 있는 명령어 주소를 MAR로 가져옴 (그 이후 PC는 +1)

2) MAR에 저장된 주소에 해당하는 값을 메모리에서 가져와서 MBR에 저장

(이때 가져온 값은 Data 또는 Opcode(명령어))

3) 만약 Opcode를 가져왔다면, IR에서 Decode하는 단계 거침 (명령어를 해석하여 Data로 만들어야 함)

4) 1~2과정에서 가져온 데이터를 ALU에서 수행 (Excute Cycle). 연산 결과는 MBR을 거쳐 메모리로 다시 저장

================================================
FILE: Computer Science/Computer Architecture/중앙처리장치(CPU) 작동 원리.md
================================================
## 중앙처리장치(CPU) 작동 원리



CPU는 컴퓨터에서 가장 핵심적인 역할을 수행하는 부분. '인간의 두뇌'에 해당

크게 연산장치, 제어장치, 레지스터 3가지로 구성됨



- ##### 연산 장치

  > 산술연산과 논리연산 수행 (따라서 산술논리연산장치라고도 불림)
  >
  > 연산에 필요한 데이터를 레지스터에서 가져오고, 연산 결과를 다시 레지스터로 보냄

- ##### 제어 장치

  > 명령어를 순서대로 실행할 수 있도록 제어하는 장치
  >
  > 주기억장치에서 프로그램 명령어를 꺼내 해독하고, 그 결과에 따라 명령어 실행에 필요한 제어 신호를 기억장치, 연산장치, 입출력장치로 보냄
  >
  > 또한 이들 장치가 보낸 신호를 받아, 다음에 수행할 동작을 결정함

- ##### 레지스터

  > 고속 기억장치임
  >
  > 명령어 주소, 코드, 연산에 필요한 데이터, 연산 결과 등을 임시로 저장
  >
  > 용도에 따라 범용 레지스터와 특수목적 레지스터로 구분됨
  >
  > 중앙처리장치 종류에 따라 사용할 수 있는 레지스터 개수와 크기가 다름
  >
  > - 범용 레지스터 : 연산에 필요한 데이터나 연산 결과를 임시로 저장
  > - 특수목적 레지스터 : 특별한 용도로 사용하는 레지스터



#### 특수 목적 레지스터 중 중요한 것들

- MAR(메모리 주소 레지스터) : 읽기와 쓰기 연산을 수행할 주기억장치 주소 저장
- PC(프로그램 카운터) : 다음에 수행할 명령어 주소 저장
- IR(명령어 레지스터) : 현재 실행 중인 명령어 저장
- MBR(메모리 버퍼 레지스터) : 주기억장치에서 읽어온 데이터 or 저장할 데이터 임시 저장
- AC(누산기) : 연산 결과 임시 저장



#### CPU의 동작 과정

1. 주기억장치는 입력장치에서 입력받은 데이터 또는 보조기억장치에 저장된 프로그램 읽어옴
2. CPU는 프로그램을 실행하기 위해 주기억장치에 저장된 프로그램 명령어와 데이터를 읽어와 처리하고 결과를 다시 주기억장치에 저장
3. 주기억장치는 처리 결과를 보조기억장치에 저장하거나 출력장치로 보냄
4. 제어장치는 1~3 과정에서 명령어가 순서대로 실행되도록 각 장치를 제어



##### 명령어 세트란?

CPU가 실행할 명령어의 집합

> 연산 코드(Operation Code) + 피연산자(Operand)로 이루어짐
>
> 연산 코드 : 실행할 연산
>
> 피연산자 : 필요한 데이터 or 저장 위치



연산 코드는 연산, 제어, 데이터 전달, 입출력 기능을 가짐

피연산자는 주소, 숫자/문자, 논리 데이터 등을 저장



CPU는 프로그램 실행하기 위해 주기억장치에서 명령어를 순차적으로 인출하여 해독하고 실행하는 과정을 반복함

CPU가 주기억장치에서 한번에 하나의 명령어를 인출하여 실행하는데 필요한 일련의 활동을 '명령어 사이클'이라고 말함

명령어 사이클은 인출/실행/간접/인터럽트 사이클로 나누어짐

주기억장치의 지정된 주소에서 하나의 명령어를 가져오고, 실행 사이클에서는 명령어를 실행함. 하나의 명령어 실행이 완료되면 그 다음 명령어에 대한 인출 사이클 시작



##### 인출 사이클과 실행 사이클에 의한 명령어 처리 과정

> 인출 사이클에서 가장 중요한 부분은 PC(프로그램 카운터) 값 증가

- PC에 저장된 주소를 MAR로 전달

- 저장된 내용을 토대로 주기억장치의 해당 주소에서 명령어 인출
- 인출한 명령어를 MBR에 저장
- 다음 명령어를 인출하기 위해 PC 값 증가시킴
- 메모리 버퍼 레지스터(MBR)에 저장된 내용을 명령어 레지스터(IR)에 전달

```
T0 : MAR ← PC
T1 : MBR ← M[MAR], PC ← PC+1
T2 : IR ← MBR
```

여기까지는 인출하기까지의 과정



##### 인출한 이후, 명령어를 실행하는 과정

> ADD addr 명령어 연산

```
T0 : MAR ← IR(Addr)
T1 : MBR ← M[MAR]
T2 : AC ← AC + MBR
```

이미 인출이 진행되고 명령어만 실행하면 되기 때문에 PC를 증가할 필요x

IR에 MBR의 값이 이미 저장된 상태를 의미함

따라서 AC에 MBR을 더해주기만 하면 됨

> LOAD addr 명령어 연산

```
T0 : MAR ← IR(Addr)
T1 : MBR ← M[MAR]
T2 : AC ← MBR
```

기억장치에 있는 데이터를 AC로 이동하는 명령어

> STA addr 명령어 연산

```
T0 : MAR ← IR(Addr)
T1 : MBR ← AC
T2 : M[MAR] ← MBR
```

AC에 있는 데이터를 기억장치로 저장하는 명령어

> JUMP addr 명령어 연산

```
T0 : PC ← IR(Addr)
```

PC값을 IR의 주소값으로 변경하는 분기 명령어




================================================
FILE: Computer Science/Computer Architecture/캐시 메모리(Cache Memory).md
================================================
## 캐시 메모리(Cache Memory)

속도가 빠른 장치와 느린 장치에서 속도 차이에 따른 병목 현상을 줄이기 위한 메모리를 말한다.

<br>

```
ex1) CPU 코어와 메모리 사이의 병목 현상 완화
ex2) 웹 브라우저 캐시 파일은, 하드디스크와 웹페이지 사이의 병목 현상을 완화
```

<br>

CPU가 주기억장치에서 저장된 데이터를 읽어올 때, 자주 사용하는 데이터를 캐시 메모리에 저장한 뒤, 다음에 이용할 때 주기억장치가 아닌 캐시 메모리에서 먼저 가져오면서 속도를 향상시킨다.

속도라는 장점을 얻지만, 용량이 적기도 하고 비용이 비싼 점이 있다.

<br>

CPU에는 이러한 캐시 메모리가 2~3개 정도 사용된다. (L1, L2, L3 캐시 메모리라고 부른다)

속도와 크기에 따라 분류한 것으로, 일반적으로 L1 캐시부터 먼저 사용된다. (CPU에서 가장 빠르게 접근하고, 여기서 데이터를 찾지 못하면 L2로 감)

<br>

***듀얼 코어 프로세서의 캐시 메모리*** : 각 코어마다 독립된 L1 캐시 메모리를 가지고, 두 코어가 공유하는 L2 캐시 메모리가 내장됨

만약 L1 캐시가 128kb면, 64/64로 나누어 64kb에 명령어를 처리하기 직전의 명령어를 임시 저장하고, 나머지 64kb에는 실행 후 명령어를 임시저장한다. (명령어 세트로 구성, I-Cache - D-Cache)

- L1 : CPU 내부에 존재
- L2 : CPU와 RAM 사이에 존재
- L3 : 보통 메인보드에 존재한다고 함

> 캐시 메모리 크기가 작은 이유는, SRAM 가격이 매우 비쌈

<br>

***디스크 캐시*** : 주기억장치(RAM)와 보조기억장치(하드디스크) 사이에 존재하는 캐시

<br>

#### 캐시 메모리 작동 원리

- ##### 시간 지역성

  for나 while 같은 반복문에 사용하는 조건 변수처럼 한번 참조된 데이터는 잠시후 또 참조될 가능성이 높음

- ##### 공간 지역성

  A[0], A[1]과 같은 연속 접근 시, 참조된 데이터 근처에 있는 데이터가 잠시후 또 사용될 가능성이 높음

> 이처럼 참조 지역성의 원리가 존재한다.

<br>

캐시에 데이터를 저장할 때는, 이러한 참조 지역성(공간)을 최대한 활용하기 위해 해당 데이터뿐만 아니라, 옆 주소의 데이터도 같이 가져와 미래에 쓰일 것을 대비한다.

CPU가 요청한 데이터가 캐시에 있으면 'Cache Hit', 없어서 DRAM에서 가져오면 'Cache Miss'

<br>

#### 캐시 미스 경우 3가지

1. ##### Cold miss

   해당 메모리 주소를 처음 불러서 나는 미스

2. ##### Conflict miss

   캐시 메모리에 A와 B 데이터를 저장해야 하는데, A와 B가 같은 캐시 메모리 주소에 할당되어 있어서 나는 미스 (direct mapped cache에서 많이 발생)

   ```
   항상 핸드폰과 열쇠를 오른쪽 주머니에 넣고 다니는데, 잠깐 친구가 준 물건을 받느라 손에 들고 있던 핸드폰을 가방에 넣었음. 그 이후 핸드폰을 찾으려 오른쪽 주머니에서 찾는데 없는 상황
   ```

3. ##### Capacity miss

   캐시 메모리의 공간이 부족해서 나는 미스 (Conflict는 주소 할당 문제, Capacity는 공간 문제)

<br>

캐시 **크기를 키워서 문제를 해결하려하면, 캐시 접근속도가 느려지고 파워를 많이 먹는 단점**이 생김

<br>

####  구조 및 작동 방식

- ##### Direct Mapped Cache

  <img src="https://file.namu.moe/file/8bc9e381797334eb33da66e3ba501be191171b1c5abb113ab52fed45a20084b1c8d2eb5a0ba399d67b38a9d5990b5d5a">

  가장 기본적인 구조로, DRAM의 여러 주소가 캐시 메모리의 한 주소에 대응되는 다대일 방식

  현재 그림에서는 메모리 공간이 32개(00000~11111)이고, 캐시 메모리 공간은 8개(000~111)인 상황

  ex) 00000, 01000, 10000, 11000인 메모리 주소는 000 캐시 메모리 주소에 맵핑

  이때 000이 '인덱스 필드', 인덱스 제외한 앞의 나머지(00, 01, 10, 11)를 '태그 필드'라고 한다.

  이처럼 캐시메모리는 `인덱스 필드 + 태그 필드 + 데이터 필드`로 구성된다.

  간단하고 빠른 장점이 있지만, **Conflict Miss가 발생하는 것이 단점**이다. 위 사진처럼 같은 색깔의 데이터를 동시에 사용해야 할 때 발생한다.

  <br>

- ##### Fully Associative Cache 

  비어있는 캐시 메모리가 있으면, 마음대로 주소를 저장하는 방식

  저장할 때는 매우 간단하지만, 찾을 때가 문제

  조건이나 규칙이 없어서 특정 캐시 Set 안에 있는 모든 블럭을 한번에 찾아 원하는 데이터가 있는지 검색해야 한다. CAM이라는 특수한 메모리 구조를 사용해야하지만 가격이 매우 비싸다.

  <br>

- ##### Set Associative Cache

  Direct + Fully 방식이다. 특정 행을 지정하고, 그 행안의 어떤 열이든 비어있을 때 저장하는 방식이다. Direct에 비해 검색 속도는 느리지만, 저장이 빠르고 Fully에 비해 저장이 느린 대신 검색이 빠른 중간형이다.

  > 실제로 위 두가지보다 나중에 나온 방식

<br>

<br>

##### [참고 자료]

- [링크](https://it.donga.com/215/ )

- [링크](https://namu.moe/w/%EC%BA%90%EC%8B%9C%20%EB%A9%94%EB%AA%A8%EB%A6%AC)


================================================
FILE: Computer Science/Computer Architecture/컴퓨터의 구성.md
================================================
## 컴퓨터의 구성

컴퓨터가 가지는 구성에 대해 알아보자

<br>

컴퓨터 시스템은 크게 하드웨어와 소프트웨어로 나누어진다.

**하드웨어** : 컴퓨터를 구성하는 기계적 장치

**소프트웨어** : 하드웨어의 동작을 지시하고 제어하는 명령어 집합

<br>

#### 하드웨어

---

- 중앙처리장치(CPU)
- 기억장치 : RAM, HDD
- 입출력 장치 : 마우스, 프린터

#### 소프트웨어

---

- 시스템 소프트웨어 : 운영체제, 컴파일러
- 응용 소프트웨어 : 워드프로세서, 스프레드시트

<br>

먼저 하드웨어부터 살펴보자

<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAVsAAACRCAMAAABaFeu5AAABgFBMVEX///+74OMAAAC+5OeWtrmGhoacvcDl5OSwrq7/IwD/+vn/YkK33N+53+LPzs7/0slobW15g4T39vb/NQDd66yutZLlxY10fmv3hVJqfoD/ZgD/YQCx1NeTkpKGoqT/5t/FxcXq6urQ0ND/k3z/AAD/WwDi56n/dSX/wZ3/8+v/zLLl5eXY3aK5vYrszI//8/D/xaelqXukpKRmenx3jpDJzZenyMv/upY4RET/chMdIyNZa2xKSkpYWFhJV1j/w7cvODl6enqOqqwUGBgpMTL/3dViYmJTU1MzPj+oqKhDUFH/uKp9lpjJ8fT/pJEnJyf/iXD/WzP/b1JXX1n/dFj/nYr/g2f/6dn/hkL/Xjb/1r3/y8D/sKH/qnprbVz/mmHZoGvBhlj/SBOXeml9a2cAFBj/hjaliIKlcmb/pnSIfHCpakH/Tij/l1fUm2eYm27Ev4qZmn7sun90d1f4azn/q4pRAADPn5a2WD/+n2SwiHKwVhiwYS6yaljSzZS7w5/oVKRGAAAbLklEQVR4nO2djX/aSHrHxYwQIAvD4W6vYAESjnc3YXNkQVGIxIuQBMYYg+31SxI72dZtc3ett9vr9dpeXy7/ep+RBAaMjBCYsEl+H38MkkYa9NWjZ2YezYwoamFdbRQuXzezGweF0zN255y92sjGbmKF4yvq/JzqnbD1183mRr1w2qOOYHmjELtpFk4Li+f7OejsplC/jjVvDgobO+zRCdu7yca2LgvXPerkhNo5LhxcN62NZ+z5KQuJL7diV1vZj/2rfzli7y6z0zdaWy4PJnf4oqmqn819gxe+uARvOno09w2+8/oLXE9i5+d0cHxSiB03C68PqNMj6uyUrW9kmxuXhdMr9ugIyr/C5XEzSzbukI0HJ9kYbDy5Ys9hGQrH42z2uM6enlFQclobY9mTA8rZ+JpsLJz0qJ0j9uq0cLlBillypJ0T6uB1tnlsHeloh+05G+vUCRzplDqAYvZozXxVsz7/D4LyDoq07FaPOj6ljm7Yg61m7LqePT5jT0+pnetCnWy8Yo/PqfPX7NV1lmy86bEnJHEBEpONN0fU+QYpOS+vL7NQcr6GxDcsFJPNrYPCzQ51ahWrUMxCYooc6YaCjbEtOBLJhj2DYnYrBomp6yPq9IbqbWXX7n6a3yewR6QOxg6LPNZt4c7GWctjO993pOnZXl6um93O/YOgprZm9uFo7crYwidTV2VPN9YM7k5kbp/Qm7/atgqxV7018wmXc4MqbHxpl3kTO/+19rHLKgSN8jW7n3rHoz+I9aLLesFTusU095mwO+drxvZq7GL3Xm/M1lbES6pF9Sn4nTED2Ymsi+b36VDGrpmzOhi7kXYi13+zDvp3P2xP1q0O1rsZZ/v6679aA/2bD7brV8aOx2qA7XdfO3r+86/n1B+ffj2i+Xf/frCrP7Z1H6GRB9Vlb8JuB2yf/0BH8VwKyKWfh2S/e9fl5tsd890/frcAW3bjeM18ws7YSQDbv3xn652MA3MKc+pTZ+/vfs7g+feXfnb2/ls/dpttLg/LUpRtjt5It2yfl+ZGA3Ayv34+uDT8/LsH5B+ef1JsY+Nsj//y3NJTyQ9b+t1Te/fnKudjd/6Hr+y9/bBlT9YtfjseqwG2/2qf3fc+2X61ANvAkO2/fBJl2fhzB8L2qaVRtgPPiQcLTtk12Hr7Fdjauz912GJ89zABPLr/yO6Erb23L7ZrF7+drIMdO2x+ttlyINxVu2Uo2WSGxwGs1xhMZ4i4ZA0ARvVMRoZSjPjnO2w5XerysE+Zga20BF+TNR7L1u68vZbJZGgoxTq8xfYP9t5/58cnrF2s5o5P+N6WxRbT7XJZy6iohGisG8jQMZbgawcRyR0UBVvWEOoe8krZYevsb7MtIRNpTLID+wRwyZADuKPwcAiiTJesPVQRqmGsIoetvbcvtr11i9/Wd8brt2NsA4xqohpN2DJRsyOXFc5iy3MqonlALEfpZKlUSnZ502HrwPn+B2CLGVQKMEgtK4RioIPg0tSALcd1UZIPSEjneKlE9ueBLV6Q7SrbZWwW/lgqWyCOqGAtTC7fLjjLRxNsMTE2zmIrI+mwi5hDYm2YMVCNO+wgg7ZtUJnOVkddjJFq7yMj1CFsaQ7zHWQyhxIykgyyb4ElsGV3VvcMvf6oWX9Uz0Z22OsN6iRS6D1qNh9dFSKn1MY1C67g4FG9+ajXe3RCbUTYs0fN2KOr7NbWONtAtIbg9A1gS4PV6SipILDYJKpl4LOGJJkw6xxiTpnCNiArZYCfNCAtljWzi1S+Bs5AR0qmjboSUgE5WD9n+YQlsF2Zv40dx7JnzULvkro6oA56bGynUNhpsr06dXBFmrrNs2zhLHb1mmykYGMWNp5M2G2AV1CGqSGLbYbYoQS+k6upPKZVsD5wtxgoRzE/lS3OKAZSZeJvo22kB5JwPYwML3WYQ16l4S6A3WXiMJbBdv1iNeOa9Lc4idqdQ8cnJOEulq37G4joGZ1WVSjLeEVD0i3b78fKsgDDgGVb++gZSCxb/hZ2gsqFLtWg8oFrhlmLLqUsW+GzyOaplzbgZPx2vJ6QQSWwVYstlPCSUQ5YZRlXMrROx1S6OMCUDbmEMpw5rZ4A+4NNwofBYNmUSFVWLfMYd02z09EMFTyvSlyEuhSfcLq6fhPgbD2kulsHG63fAglOlWy2chlBhdRiy6AkFHMc8ZQlcMOclrxlO1q/xV2k8yCZ4UidwfoqRwNR1AbApJ4AXkaCyln71m7912/XvavFZLuMswjZ9VuASWzQqoMpZlfXoUSDwo7c4tHAbf12gq0jGTs1AkQquTWU1PWuqYBPIOYaiA7tdpF22Qr7LGWvvPy82NXUNu9oPIG0y7RBxBFnSGtKLmmGUZYID3s9FG8O2+f2/jZbuwVG2nAB3vmmc+BupbJhaOptFBMnnXaZzdZXPGGVsRpvPmG8r930ONho9MCOCuCxkMDtavrdh/FYzUjCia+Bu7sHFoqDUc3VxRgLTS+X0S1++zTpJw6m//rDYvHbrxaJ367O3xZintjGprP97h03P1xc+sMgNv5H2sfumXcf/LNdP58wWU8YPi97Cu4Qk7ZBYPAvEBhZtFeMrcRcF9zt4HHbO8YOR47t4XiEwO0HHtmd/uEPzxd4XlZf3RgXj2XZwYTdDp/zfv+DmpxLpR/effVh+DDy+Tu1NN/+6rs/fPXdAs95VygSe5mt8UrhWP+Erz98NZ8+fHg+2sng+Zy7f/Xh+dcL9E9YZf/by61LD6nOrifqCb8Z0V/Pq9/8Zjm7/94P27Od1bV5j7zUSSbjt1sfuyOYra319gmUpzuEnehrtzVbES+JFtZax29jGzEPqa7GAhzZ2HT953+Afte0F66uXFLN1J92d+tjK37c3d09mJ52bk6rjNXEXnti66kA2CORADNvL/iPkz7ZTT0eXX78TSq1/dbv0T6mfPgEF23aYZaivcf5uV+4k2z/tJtKpV5e+DzahNiDq7Uuy1yUyOeArChaC+yZ7z7EE2wvXqaIlmS4q+x/exnxVAfzVmiICIUH35fmE9iLi5fbby8eu6afTyuM3/ppO7hqhC3YLQkDZbPkr0AeHhfgb7DcZFn3GNGkT6Col7svPOXvRT7KP7/KHnjB1vTWCB9hW9joNR/1qMgpdbJFnUWy9Ug9u3VWOD6hzrcKV+Rhcs/tKHfYsktku0qf4Cd+66pRu73KFnZi1Jn1fPgSbPisWTi7ZIcPk7M7rvWTB2W7SrstXM4fY3TVqL+dJbcDsuyz3dTFmLdeKtsVxm/v8XsjKnjyyvOwzV4fTN/w7av3qdSrV29GVi3VJ6zdc975fcIskbk4puoitQ1NhVcPZberrN9me57itz1PF3sZPoH6PWH7ZCzpMn3C2vW/9SjvbNnmuVv/7QtitmOF2RLZstmjc2/+bXGdR7YiHhqnHudP8M72LBKJvHbZ9nZ7+83YiiWybZLo6Iqe9F5ubW15CNYceOts7Z1t9mZry6Uwoy62349f7WX6hKNI5HxZx5oh9hxq90vTHP62FzlxvV3+/GR8eZlsm1tbK+ug0PRithPxW3cV9/Me8y1cu8cx7oQOXm5/6/Gws7Wzs7RDDSSGXfRfLuuFxMje48/LRpQQ3I47S/+37z3t//7Pf48s5TydcMjlWL/9rcuGTb9o99UMM5+6qjD7sMLch11cdLIhzvxhiXRJn/OwUjzkC62QnHdIMsa8epuXy1yXIZWf+7BLEN2YecL73fkPK8cTM487RQ3eR9+gkVMYr4M9HjwDSDM+uoMtLpwUZpxvIu5nMGu36ANtouRnbKd8e5OMx28vXr69cC6Zj8MuLpxJz7Aw0VcfQNqDs5nCNuojKz6eo9jHlmL1i8e3epPaTVl0f/XR2M6AIEp+Dks3fHjcAVuMb/u/4fGBs07v49HVhO2Tbeth1XUkNaHt1J8vPLAd+LK7q50fMtiMb1fPNLl52Eajw1MfHRs8esKBYb/gBdhiJkM6zeuqjGUaxGNZpTFvFZMcrIUkMsPI4HiID7HZ7k4R4b29m/p2NltuUArzQ4jdEpR/coYm/XDJD7Fz7yZ5O3c+wCWlGXeZZ7b4MFOr1chAlQBjnzA9zJL8kJEsF2QbVZGBOjxOIgYnDcVASYaM8Uja42YlaxyXipCKcY2M2bDYPn72hOjFW/vT1ovU9vY3Lx7P9gmYHoxk0DFd7nQ6pUCgZvC4BD/E5A9LkI096Jchg54wVhCSDnml45ft8IGlzZbLdFVTM0vdDIZs4eAZWoWzrNljK8hJYmySLDmzvRhbzCCV76LMIaFIS1IJlWoGnDTPSECZI8R5XSqVJJ2roYHdOjq7Hq2DXaQssh78LdhtF348GCawLZdRGdgqvAw/REeqTs5OZlSUYbiaCfaUSZLcebPml+2fXj1hR9mq5bKBlE5ZxYGMJKlIKhsK5COTLKOQ+zBLrbwgWx248nCVCFsVKYrS1VUyMJnroDJ/mESK5JiZfIft+FxAFy8c+5jJFq6b0a4BRpn4hCiqYcJWR91DzsqJx4eyad8p5mDQr+yJLft4it7u7tp0HbYynGDNSNKQe5ucsJ6pKWT8K2QZtbJ0Rgjx7QXZBmRTy9QQbbM1aJnR29bN2jYkxSBjlTIBnm8jmcd32LrMNz7TJ+iGmeQxnJE9FwCSLLa80s+A6XDgE7iMYkqoDfdqjeF4xqjJvDe7/embKXpJythXTwoOW76mqDSX6SilAC5r4FkzJlw6yFKTkAb3C2zkGaXM89yidgtn2kFGJoptuzUMACshPaAq+iFdhq+yPW5WxnfZ9qZP/DSLLSd3aV6WeVlnOGsEGmOxxXQHKd0A8be81pGxbjKqac1ogdoc9sb2vXsh+80bh62qaVCU1Tqalgxo5IQVuIYyXy4zOGMycJKYXG8jgBdnG+BV/fAQH3YN8DndbjdDy3SSACWluSxZg8NUQ1GnsB2P3+YGv2EG2+FIPFCXjJWEooywBeaWdInDUbueoqpQsPCmCem8sX3y7RT9tL29/YoEKG22tFRKdlANPCoTYMgJM5Alb2dJy2qHg1NvK5DlEuyWQWVw3ckyGRqqgftRDPC5UCcDD28qZjKKOQlJEuR1h+24NlE/KHpgG+B1XafbCP7rPBSjZd5mC67CkqIwGHc1o99XTD1ARu3SNYNeoCx7u/v+iVUU2Gxx0mxrpqYZSYxpxT5hk7ayhK8m1B4gS1019OWwJfNnELbO+MMkeEAOtWVi07C2Syyr1g7css0VLf32d8Vb7QeJIQZDHsoyUqXtIKtmS6ZFwA5bJ3fVGvRLxu/JZBKVEsrANS8twPbZMyfe7rCVOpYQtICHWeqYVFNIlohkCfeJpi6FrUn8j2nVZO2IEmHbVnRZBhcoY46GdPxoWVZErjLSntq8ZFYJ8mkd22brZH5IBv3KRpmW5YzS4aFSQQbrcguwHcphW0MlS5lhA7BLKp2IZKmbGgdZkvPkOG3B+i1cKnu8UUkdIMGM2cWwGqrVqEYHhi1P1Ryw3XdA/uNdtq1Nb2zVttPqtJfV9jD3DPEJNKnKK9aoXTsFX1aXxTaptYk0ddiOzxCfwEC9HhlWO9RuY3Od2qJsXVv3YKvc6FqrDW7724Sl+lkhcSsBaFi+2E+sJjoBDurXPD8WQ5hMcUfe4wlu0Ywoz0fvnrBPtjNijFNnnBwpy8bjtwJqCdaXJcXB5p3v0gPbWTHGaVn6Y+s3Nj5kOx6/FQfrP1psvDiDrc/YeNoPWyE59Aeexan7w6xc+jHmSvM/KlqCmJYwK4hdzMx/WLka9vqUekz7qk7Pp4yavj0Dt752gpqZ87BLkNTy8Kg3XZr3hLvVouDrgRmVC86r8IhxuL5jK5Se+7hu+vt/9pgwLWx6YCDMm386vOnjkY6lhJgPzaF8Pj9yAve8G+6ew+bFdFGcOKhb6nz+99+ERjbmhb2KMDVxPiR6Mq+Ea17Tf0Ao789qF5WPdxoSiWZl/Pc+du/W9zi1PdYxKYeQ794Yvyh5Gl92V8WJ/mFPXr1yhft2O/VytLPSZ8PWn8Q+Qtroim93U25sL75JpcZ61H02bF3itzNkBSNGDffbbVe2Vm/x9yOG+/mw9TOBTqJP2I56XHe2F9uE7ajhfjZsfSmsANy+ItyucWf7+OINlGUXIwOiPxu2B34mjRXFMEJC3pPdQjUvtf1sdPmzYetxrPSkBITGWlBf2E6Rj/dKE31h60ExfwPevrD1oPnfIWvpC1sPGp/r0rO+sPUgj+PQJ/WFrQd98QkPp5i/yTfXnm0iVHTa5OnRz0SCSgtOArt6Hi4G0w/0G3wO3l53tmKo1aqIFBUKUWGUoDb3G3mhH6KEaiuXrlpQxZYmkM90Rav4GyI1Ux+n7eBtkJ53Tc7VFNTSDa0iJIS+Fs4Zm4nw3p4Q7guJRiPeSO+Rhxu5VhVVyM8oKq3gzId0/uQzfuufrdCII9RqCH5yddXb1NuxGdzCrYZSqQhiMJiuAtN80WxUK1o4Lzaq4caehXKzX2kIYkLMVczKrAf3q9Uk22ee2ebsvju+LXdaz+fHb3e3v3kxYrvhfqPaBrahSj9d7AuiUGkV9/vhkFCMt7SqxVastONg0JVqa6+iLfs+suUrxjjJ9sWPr1KpH390mfxvwic0CNq4n0wt/bQ9ObDI0W7qxfAHiMH9YAvYUglBALZ5MGBBMMOhYitdjBO2oZAoNNJgr+CX9yqC4OsR+yz1/E2qNc72CYnR7r53sdwJtsRwDf+GQnri3pE1dmv7/cjEFzlh3+rrkAgJVSCXyAmb5DMvbKbjsL5YqTYarT0BTNwIakJonZzCOFvWMqZnLmknyzLib/3n/ObJFP24vb37/tnYtU2EnK4CYLqi1fvNsk4RYJPOCvB/c1MQQhS44KDwMBWFur+Xfk342zfbqe2f3OZVLKR2x+sJxtLrCS92B+N4RjSowVLOZ2LsUwyJUJIR+jnhgeoJPttlm+O3Nftqe/eJW1r2ybNxTxxfwGyn69mzaRc2MeNzsCh66xYxt3zGbyf1JvXee+LQA9XV103uc10m5tKrZ/Oln6qVnvnDy61fTWK/8at59E/BuZJPV/DTiuG4xBgTwQwXXbnkkufJ834JcplbONz9GH2bMVdbp4rmonLxCX66oy8Drq/JT+aTc/Xuevelu/vYla8xpw/FduZ4B69KJPJ5+3O8ghUSGsTv5ETRGdmRy1nbc414RVhO1kP5HCvtjdTHYytWqohMrpRI72lVsiIUbMGRw/GGFq+KVHqvkq82rCZEWNkjNfXQXsUoLtlyXeZeu48txsOP4YiCwHDSFplMfhHlAGxU5p0xTzgq3x6Pk92P7Zft3f7mjUarQSwyrWl78ClWW3utBBXUWhWjKiTiwcp+1dpe3DMUMv9QolVp7S+5uTj+ft6h7mNLd8lQGS5DBzDddcQHeDJGmsc8KmGs1zolGfPlWpRXiSTZUHEAM/CVJ5M9uBq0X7ZpNDFCOR+vmFXBYttqkCatuJlGArXXb5HlBImLVRrWBam2tHAuEcrDRag+eC3FmhD8HrZYNWTyol1FDVhTqCBkGAYTUEnoUAK26qGOOiVF43lNxXKthmBJhrVwUcodMu4fuddBPLCF1v9dkbil4z8dFYv25IghrR+0PKq4lxbEYDUeTIeFXDBeqRg223BlLxwSg/1qvFJdcoz86s4crbHz2Ay2yNQ0zSSjr3mZL6EaGCwXYMgLe7sWWxXxh13U7iAVkvNI4bBMJqhQyejmcndBtnH3cci3trsfTjcae1VRAIxGqyGG0+QZTytE5bS9fiOUCAf3hUpwMyEKm5vpeKtIEFe1xqaXoSze1ds46LHktfO9GHtVp+pX7EEkchq7Z+41sNtuJpPpGirxsYyiGV3H9ZLXnhO25C3USaSqkALLHYPAB+Pmk2oHdVT94djejkgMVxvp8H46F660gsFGMCc0guHwPvGn8VYlCB95gJ4Gto1KAxKQTFtV2LBcu2XZowjgjDUjvcLxOXv+utCLRCIb/3A/Wz2jd8EncIyENLmEVJokx2UyyB/YMqZSBpslPkFXkJ5BbRr4Rsk7qcmkDouxnTpEJwjXrjHqccFiN3O5nJgnYdpNQRQ3ySKwyzUalq9IJEKk9kVi5ps5Yq85MlRq2VXcbJO8bpaNFahmlizUIzcH7H0+oeSYSSnAlVGp26YzCAyWzJtSwuACVIz5rkTjw6iaDMhJ+fCQoQlxaHWVUWdhtlOVRo2JMh6qtYnBJ4kCDSNBiU3BSZqwKsCi6ESJyIaHjhZZkbH72EY5TkI0x3FkoPlhBumHnAweQTfIGH/CNqBLkkTmHIAKBZaTUDsoqWSatBJKQh3hIdjm5ohausbbVhWHu4ctmSAPGJEPnsyGg7oyA7WvJDLITAkWW9Wx7DaZZMUsSSVT0cnEKiWug+iHYPuLkjtb3B6WHTVr4jxSC0MKL9kTq1hs7fYE1ynzUKkAp3AI9QTMqRKZepf/wvY+u7XnUpKJ3Q6/RgP22HuLrS2uDHZLKyb4BNMEh0wSWG75C1tX3TZ08Wib1wEq6YOFqK6Dv+W7JbXUHQmryZL73AyfPdv7NcIZD6ZnHZuLA98zGchnwTYo+2W7kHD3M2ArSB/luQNfCy+LbaIo2F+c/rbUvvXpPC9PUGJ62E/JifDmw/vBlTyBTks8t3IxatrnBB13lG80yJjYvEgVFYo8/xMFk1w2YY+EbYVqMFEZdmkOV6ynHaG9qveXXS2kcKsVX7Fa8eKSergIe61WpSJQ+4opbBrQ3AqhcK4P1y3c0lA8kagWK+HWYO6lYKNvEM55jYTElpL/LInQzF6xcv6DJYWxt7WJlYpG+t/Gg8H+HunHGN+r7psALhE3++kcsK8O4reQuGpWyKZEUNOCwoLUftFqNqlsjLwMk73MUrEm1YyRfgCFg8jNyFtAwhUiQcyZZjrYF0KCkCsWNdKlLlitpHMhodiIGwO2VKPSD4fEVjVerfSDH+m01kKvj6mjR4X6o8vsozP2eoM6vS70Is3LyNZW5PYlSQkhHdwj/W9Fu/8tJRb3c2nCNrFXDW+SvotFx24TohgKBtObULhVW/2g8DDdnH8ZqtfJ2KLsVZa9alL1S+qyzjYPCiQyujHyYtdEKJy2+oeLOaFC+oYK2qaQCzXiwUq/3yBPLzbjQYttaK8Sj+9pwQT420YlmAutKGLzC1L2fOKNYoncbf9bUtsq9qHsyqXDghAmBZYobjoPMEU7xAsFXrjSWn4I91PQ3a5XohOOTdglZI6wTNgxcmtDPjdIlyOTYiWsZ3EPHsL9RDTR3zYfSowHae9iFPOffrPwiz5p/T9KwZGjiJ+bLQAAAABJRU5ErkJggg==">



하드웨어는 중앙처리장치(CPU), 기억장치, 입출력장치로 구성되어 있다.

이들은 시스템 버스로 연결되어 있으며, 시스템 버스는 데이터와 명령 제어 신호를 각 장치로 실어나르는 역할을 한다.

<br>

##### 중앙처리장치(CPU)

인간으로 따지면 두뇌에 해당하는 부분

주기억장치에서 프로그램 명령어와 데이터를 읽어와 처리하고 명령어의 수행 순서를 제어함
중앙처리장치는 비교와 연산을 담당하는 <strong>산술논리연산장치(ALU)</strong>와 명령어의 해석과 실행을 담당하는 **제어장치**, 속도가 빠른 데이터 기억장소인 **레지스터**로 구성되어있음

개인용 컴퓨터와 같은 소형 컴퓨터에서는 CPU를 마이크로프로세서라고도 부름

<br>

##### 기억장치

프로그램, 데이터, 연산의 중간 결과를 저장하는 장치

주기억장치와 보조기억장치로 나누어지며, RAM과 ROM도 이곳에 해당함. 실행중인 프로그램과 같은 프로그램에 필요한 데이터를 일시적으로 저장한다.

보조기억장치는 하드디스크 등을 말하며, 주기억장치에 비해 속도는 느리지만 많은 자료를 영구적으로 보관할 수 있는 장점이 있다.

<br>

##### 입출력장치

입력과 출력 장치로 나누어짐. 

입력 장치는 컴퓨터 내부로 자료를 입력하는 장치 (키보드, 마우스 등)

출력 장치는 컴퓨터에서 외부로 표현하는 장치 (프린터, 모니터, 스피커 등)

<br>

<br>

#### 시스템 버스

> 하드웨어 구성 요소를 물리적으로 연결하는 선

각 구성요소가 다른 구성요소로 데이터를 보낼 수 있도록 통로가 되어줌

용도에 따라 데이터 버스, 주소 버스, 제어 버스로 나누어짐

<br>

##### 데이터 버스

중앙처리장치와 기타 장치 사이에서 데이터를 전달하는 통로

기억장치와 입출력장치의 명령어와 데이터를 중앙처리장치로 보내거나, 중앙처리장치의 연산 결과를 기억장치와 입출력장치로 보내는 '양방향' 버스임

##### 주소 버스

데이터를 정확히 실어나르기 위해서는 기억장치 '주소'를 정해주어야 함.

주소버스는 중앙처리장치가 주기억장치나 입출력장치로 기억장치 주소를 전달하는 통로이기 때문에 '단방향' 버스임

##### 제어 버스

주소 버스와 데이터 버스는 모든 장치에 공유되기 때문에 이를 제어할 수단이 필요함

제어 버스는 중앙처리장치가 기억장치나 입출력장치에 제어 신호를 전달하는 통로임

제어 신호 종류 : 기억장치 읽기 및 쓰기, 버스 요청 및 승인, 인터럽트 요청 및 승인, 클락, 리셋 등

제어 버스는 읽기 동작과 쓰기 동작을 모두 수행하기 때문에 '양방향' 버스임

<br>

컴퓨터는 기본적으로 **읽고 처리한 뒤 저장**하는 과정으로 이루어짐

(READ → PROCESS → WRITE)

이 과정을 진행하면서 끊임없이 주기억장치(RAM)과 소통한다. 이때 운영체제가 64bit라면, CPU는 RAM으로부터 데이터를 한번에 64비트씩 읽어온다.

<br>

================================================
FILE: Computer Science/Computer Architecture/패리티 비트 & 해밍 코드.md
================================================
## 패리티 비트 & 해밍 코드

<br>

### 패리티 비트

> 정보 전달 과정에서 오류가 생겼는 지 검사하기 위해 추가하는 비트를 말한다.
>
> 전송하고자 하는 데이터의 각 문자에 1비트를 더하여 전송한다.

<br>

**종류** : 짝수, 홀수

전체 비트에서 (짝수, 홀수)에 맞도록 비트를 정하는 것

<br>

***짝수 패리티일 때 7비트 데이터가 1010001라면?***

> 1이 총 3개이므로, 짝수로 맞춰주기 위해 1을 더해야 함
>
> 답 : 11010001 (맨앞이 패리티비트)

<br>

<br>

### 해밍 코드

> 데이터 전송 시 1비트의 에러를 정정할 수 있는 자기 오류정정 코드를 말한다.
>
> 패리티비트를 보고, 1비트에 대한 오류를 정정할 곳을 찾아 수정할 수 있다.
> (패리티 비트는 오류를 검출하기만 할 뿐 수정하지는 않기 때문에 해밍 코드를 활용)

<br>

##### 방법

2의 n승 번째 자리인 1,2,4번째 자릿수가 패리티 비트라는 것으로 부터 시작한다. 이 숫자로부터 시작하는 세개의 패리티 비트가 짝수인지, 홀수인지 기준으로 판별한다.

<br>

***짝수 패리티의 해밍 코드가 0011011일때 오류가 수정된 코드는?***

1) 1, 3, 5, 7번째 비트 확인 : 0101로 짝수이므로 '0'

2) 2, 3, 6, 7번째 비트 확인 : 0111로 홀수이므로 '1'

3) 4, 5, 6, 7번째 비트 확인 : 1011로 홀수이므로 '1'

<br>

역순으로 패리티비트 '110'을 도출했다. 10진법으로 바꾸면 '6'으로, 6번째 비트를 수정하면 된다.

따라서 **정답은 00110'0'1**이다.

================================================
FILE: Computer Science/Data Structure/Array vs ArrayList vs LinkedList.md
================================================
## Array vs ArrayList vs LinkedList

<br>

세 자료구조를 한 문장으로 정의하면 아래와 같이 말할 수 있다.



<img src="https://t1.daumcdn.net/cfile/tistory/995E66395B1CFD7D10">

<img src="https://t1.daumcdn.net/cfile/tistory/99250A345B1CFD690C">

<br>

- **Array**는 index로 빠르게 값을 찾는 것이 가능함
- **LinkedList**는 데이터의 삽입 및 삭제가 빠름
- **ArrayList**는 데이터를 찾는데 빠르지만, 삽입 및 삭제가 느림

<br>

좀 더 자세히 비교하면?

<br>

우선 배열(Array)는 **선언할 때 크기와 데이터 타입을 지정**해야 한다.

```java
int arr[10];
String arr[5];
```

이처럼, **array**은 메모리 공간에 할당할 사이즈를 미리 정해놓고 사용하는 자료구조다.

따라서 계속 데이터가 늘어날 때, 최대 사이즈를 알 수 없을 때는 사용하기에 부적합하다.

또한 중간에 데이터를 삽입하거나 삭제할 때도 매우 비효율적이다.

4번째 index 값에 새로운 값을 넣어야 한다면? 원래값을 뒤로 밀어내고 해당 index에 덮어씌워야 한다. 기본적으로 사이즈를 정해놓은 배열에서는 해결하기엔 부적합한 점이 많다.

대신, 배열을 사용하면 index가 존재하기 때문에 위치를 바로 알 수 있어 검색에 편한 장점이 있다.

<br>

이를 해결하기 위해 나온 것이 **List**다.

List는 array처럼 **크기를 정해주지 않아도 된다**. 대신 array에서 index가 중요했다면, List에서는 순서가 중요하다.

크기가 정해져있지 않기 때문에, 중간에 데이터를 추가하거나 삭제하더라도 array에서 갖고 있던 문제점을 해결 가능하다. index를 가지고 있으므로 검색도 빠르다.

하지만, 중간에 데이터를 추가 및 삭제할 때 시간이 오래걸리는 단점이 존재한다. (더하거나 뺄때마다 줄줄이 당겨지거나 밀려날 때 진행되는 연산이 추가, 메모리도 낭비..)

<br>

그렇다면 **LinkedList**는?

연결리스트에는 단일, 다중 등 여러가지가 존재한다.

종류가 무엇이든, **한 노드에 연결될 노드의 포인터 위치를 가리키는 방식**으로 되어있다.

> 단일은 뒤에 노드만 가리키고, 다중은 앞뒤 노드를 모두 가리키는 차이

<br>

이런 방식을 활용하면서, 데이터의 중간에 삽입 및 삭제를 하더라도 전체를 돌지 않아도 이전 값과 다음값이 가르켰던 주소값만 수정하여 연결시켜주면 되기 때문에 빠르게 진행할 수 있다.

이렇게만 보면 가장 좋은 방법 같아보이지만, `List의 k번째 값을 찾아라`에서는 비효율적이다.

<br>

array나 arrayList에서 index를 갖고 있기 때문에 검색이 빠르지만, LinkedList는 처음부터 살펴봐야하므로(순차) 검색에 있어서는 시간이 더 걸린다는 단점이 존재한다. 

<br>

따라서 상황에 맞게 자료구조를 잘 선택해서 사용하는 것이 중요하다.

================================================
FILE: Computer Science/Data Structure/Array.md
================================================
### 배열 (Array)

---

- C++에서 사이즈 구하기 

```
int arr[] = { 1, 2, 3, 4, 5, 6, 7 }; 
int n = sizeof(arr) / sizeof(arr[0]); // 7
```

<br/>

<br/>

1. #### 배열 회전 프로그램



![img](https://t1.daumcdn.net/cfile/tistory/99AFA23F5BE8F31B0C)



*전체 코드는 각 하이퍼링크를 눌러주시면 이동됩니다.*

<br/>

- [기본적인 회전 알고리즘 구현](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/code/rotate_array.cpp)

  > temp를 활용해서 첫번째 인덱스 값을 저장 후
  > arr[0]~arr[n-1]을 각각 arr[1]~arr[n]의 값을 주고, arr[n]에 temp를 넣어준다.
  >
  > ```
  > void leftRotatebyOne(int arr[], int n){
  >     int temp = arr[0], i;
  >     for(i = 0; i < n-1; i++){
  >         arr[i] = arr[i+1];
  >     }
  >     arr[i] = temp;
  > }
  > ```
  >
  > 이 함수를 활용해 원하는 회전 수 만큼 for문을 돌려 구현이 가능

  <br/>

- [저글링 알고리즘 구현](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/code/juggling_array.cpp)

  > ![ArrayRotation](https://cdncontribute.geeksforgeeks.org/wp-content/uploads/arra.jpg)
  >
  > 최대공약수 gcd를 이용해 집합을 나누어 여러 요소를 한꺼번에 이동시키는 것
  >
  > 위 그림처럼 배열이 아래와 같다면
  >
  > arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}
  >
  > 1,2,3을 뒤로 옮길 때, 인덱스를 3개씩 묶고 회전시키는 방법이다.
  >
  > a) arr [] -> { **4** 2 3 **7** 5 6 **10** 8 9 **1** 11 12}
  >
  > b) arr [] -> {4 **5** 3 7 **8** 6 10 **11** 9 1 **2** 12}
  >
  > c) arr [] -> {4 5 **6**  7 8 **9** 10 11 **12** 1 2 **3** }

  <br/>

- [역전 알고리즘 구현](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/code/reversal_array.cpp)

  > 회전시키는 수에 대해 구간을 나누어 reverse로 구현하는 방법
  >
  > d = 2이면
  >
  > 1,2 / 3,4,5,6,7로 구간을 나눈다.
  >
  > 첫번째 구간 reverse -> 2,1
  >
  > 두번째 구간 reverse -> 7,6,5,4,3
  >
  > 합치기 -> 2,1,7,6,5,4,3
  >
  > 합친 배열을 reverse -> **3,4,5,6,7,1,2**
  >
  >
  >
  > - swap을 통한 reverse
  >
  > ```
  > void reverseArr(int arr[], int start, int end){
  >     
  >     while (start < end){
  >         int temp = arr[start];
  >         arr[start] = arr[end];
  >         arr[end] = temp;
  >         
  >         start++;
  >         end--;
  >     }
  > }
  > ```
  >
  >
  >
  > - 구간을 d로 나누었을 때 역전 알고리즘 구현
  >
  > ```
  > void rotateLeft(int arr[], int d, int n){
  >     reverseArr(arr, 0, d-1);
  >     reverseArr(arr, d, n-1);
  >     reverseArr(arr, 0, n-1);
  > }
  > ```

<br/>

<br/>

2. #### 배열의 특정 최대 합 구하기



**예시)** arr[i]가 있을 때, i*arr[i]의 Sum이 가장 클 때 그 값을 출력하기 

(회전하면서 최대값을 찾아야한다.)

```
Input: arr[] = {1, 20, 2, 10}
Output: 72

2번 회전했을 때 아래와 같이 최대값이 나오게 된다.
{2, 10, 1, 20}
20*3 + 1*2 + 10*1 + 2*0 = 72

Input: arr[] = {10, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Output: 330

9번 회전했을 때 아래와 같이 최대값이 나오게 된다.
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
0*1 + 1*2 + 2*3 ... 9*10 = 330
```

<br/>

##### 접근 방법

arr[i]의 전체 합과 i*arr[i]의 전체 합을 저장할 변수 선언

최종 가장 큰 sum 값을 저장할 변수 선언

배열을 회전시키면서 i*arr[i]의 합의 값을 저장하고, 가장 큰 값을 저장해서 출력하면 된다.

<br/>

##### 해결법

```
회전 없이 i*arr[i]의 sum을 저장한 값
R0 = 0*arr[0] + 1*arr[1] +...+ (n-1)*arr[n-1]


1번 회전하고 i*arr[i]의 sum을 저장한 값
R1 = 0*arr[n-1] + 1*arr[0] +...+ (n-1)*arr[n-2]

이 두개를 빼면?
R1 - R0 = arr[0] + arr[1] + ... + arr[n-2] - (n-1)*arr[n-1]

2번 회전하고 i*arr[i]의 sum을 저장한 값
R2 = 0*arr[n-2] + 1*arr[n-1] +...+ (n-1)*arr[n-3]

1번 회전한 값과 빼면?
R2 - R1 = arr[0] + arr[1] + ... + arr[n-3] - (n-1)*arr[n-2] + arr[n-1]


여기서 규칙을 찾을 수 있음.

Rj - Rj-1 = arrSum - n * arr[n-j]

이를 활용해서 몇번 회전했을 때 최대값이 나오는 지 구할 수 있다.
```

[구현 소스 코드 링크](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/code/maxvalue_array.cpp)

<br/>

<br/>

3. #### 특정 배열을 arr[i] = i로 재배열 하기

**예시)** 주어진 배열에서 arr[i] = i이 가능한 것만 재배열 시키기

```
Input : arr = {-1, -1, 6, 1, 9, 3, 2, -1, 4, -1}
Output : [-1, 1, 2, 3, 4, -1, 6, -1, -1, 9]

Input : arr = {19, 7, 0, 3, 18, 15, 12, 6, 1, 8,
              11, 10, 9, 5, 13, 16, 2, 14, 17, 4}
Output : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 
         11, 12, 13, 14, 15, 16, 17, 18, 19]
```

arr[i] = i가 없으면 -1로 채운다.



##### 접근 방법

arr[i]가 -1이 아니고, arr[i]이 i가 아닐 때가 우선 조건

해당 arr[i] 값을 저장(x)해두고, 이 값이 x일 때 arr[x]를 탐색

arr[x] 값을 저장(y)해두고, arr[x]가 -1이 아니면서 arr[x]가 x가 아닌 동안을 탐색

arr[x]를 x값으로 저장해주고, 기존의 x를 y로 수정

```
int fix(int A[], int len){
    
    for(int i = 0; i < len; i++) {
        
        
        if (A[i] != -1 && A[i] != i){ // A[i]가 -1이 아니고, i도 아닐 때
            
            int x = A[i]; // 해당 값을 x에 저장
            
            while(A[x] != -1 && A[x] != x){ // A[x]가 -1이 아니고, x도 아닐 때
                
                int y = A[x]; // 해당 값을 y에 저장
                A[x] = x; 
                
                x = y;
            }
            
            A[x] = x;
            
            if (A[i] != i){
                A[i] = -1;
            }
        }
    }
    
}
```

[구현 소스 코드 링크](https://github.com/gyoogle/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/code/rearrange_array.cpp)

<br/>

<br/>


================================================
FILE: Computer Science/Data Structure/B Tree & B+ Tree.md
================================================
## B Tree & B+ Tree

<br>

> **이진 트리**는 하나의 부모가 두 개의 자식밖에 가지질 못하고, 균형이 맞지 않으면 검색 효율이 선형검색 급으로 떨어진다. 하지만 이진 트리 구조의 간결함과 균형만 맞다면 검색, 삽입, 삭제 모두 O(logN)의 성능을 보이는 장점이 있기 때문에 계속 개선시키기 위한 노력이 이루어지고 있다.

<br>

#### B Tree

---

데이터베이스, 파일 시스템에서 널리 사용되는 트리 자료구조의 일종이다.

이진 트리를 확장해서, 더 많은 수의 자식을 가질 수 있게 일반화 시킨 것이 B-Tree

<br>

자식 수에 대한 일반화를 진행하면서, 하나의 레벨에 더 저장되는 것 뿐만 아니라 트리의 균형을 자동으로 맞춰주는 로직까지 갖추었다. 단순하고 효율적이며, 레벨로만 따지면 완전히 균형을 맞춘 트리다.

```
대량의 데이터를 처리해야 할 때, 검색 구조의 경우 하나의 노드에 많은 데이터를 가질 수 있다는 점은 상당히 큰 장점이다.

대량의 데이터는 메모리보다 블럭 단위로 입출력하는 하드디스크 or SSD에 저장해야하기 때문!

ex) 한 블럭이 1024 바이트면, 2바이트를 읽으나 1024바이트를 읽으나 똑같은 입출력 비용 발생. 따라서 하나의 노드를 모두 1024바이트로 꽉 채워서 조절할 수 있으면 입출력에 있어서 효율적인 구성을 갖출 수 있다.

→ B-Tree는 이러한 장점을 토대로 많은 데이터베이스 시스템의 인덱스 저장 방법으로 애용하고 있음
```

<br>

##### 규칙

- 노드의 자료수가 N이면, 자식 수는 N+1이어야 함
- 각 노드의 자료는 정렬된 상태여야함
- 루트 노드는 적어도 2개 이상의 자식을 가져야함
- 루트 노드를 제외한 모든 노드는 적어도 M/2개의 자료를 가지고 있어야함
- 외부 노드로 가는 경로의 길이는 모두 같음.
- 입력 자료는 중복 될 수 없음

<br>

<br>

#### B+ Tree

---

데이터의 빠른 접근을 위한 인덱스 역할만 하는 비단말 노드(not Leaf)가 추가로 있음

(기존의 B-Tree와 데이터의 연결리스트로 구현된 색인구조)

<br>

B-Tree의 변형 구조로, index 부분과 leaf 노드로 구성된 순차 데이터 부분으로 이루어진다. 인덱스 부분의 key 값은 leaf에 있는 key 값을 직접 찾아가는데 사용함.

<br>

##### 장점

> 블럭 사이즈를 더 많이 이용할 수 있음 (key 값에 대한 하드디스크 액세스 주소가 없기 때문)
>
> leaf 노드끼리 연결 리스트로 연결되어 있어서 범위 탐색에 매우 유리함

##### 단점

> B-tree의 경우 최상 케이스에서는 루트에서 끝날 수 있지만, B+tree는 무조건 leaf 노드까지 내려가봐야 함

<br>

<br>

<br>

##### B-Tree & B+ Tree

> B-tree는 각 노드에 데이터가 저장됨
>
> B+tree는 index 노드와 leaf 노드로 분리되어 저장됨
>
> (또한, leaf 노드는 서로 연결되어 있어서 임의접근이나 순차접근 모두 성능이 우수함)

<br>

B-tree는 각 노드에서 key와 data 모두 들어갈 수 있고, data는 disk block으로 포인터가 될 수 있음

B+tree는 각 노드에서 key만 들어감. 따라서 data는 모두 leaf 노드에만 존재

B+tree는 add와 delete가 모두 leaf 노드에서만 이루어짐

<br>

**참고자료** : [링크](<https://wangin9.tistory.com/entry/B-tree-B-tree>)

================================================
FILE: Computer Science/Data Structure/Binary Search Tree.md
================================================
## [자료구조] 이진탐색트리 (Binary Search Tree)

<br>

***이진탐색트리의 목적은?***

> 이진탐색 + 연결리스트

이진탐색 : **탐색에 소요되는 시간복잡도는 O(logN)**, but 삽입,삭제가 불가능

연결리스트 : **삽입, 삭제의 시간복잡도는 O(1)**, but 탐색하는 시간복잡도가 O(N)

이 두가지를 합하여 장점을 모두 얻는 것이 **'이진탐색트리'**

즉, 효율적인 탐색 능력을 가지고, 자료의 삽입 삭제도 가능하게 만들자

<br>

<img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fk.kakaocdn.net%2Fdn%2Fk074C%2FbtqwZZvI1D3%2FeVUanrpKdIRKnZpkKiQMe0%2Fimg.png">

<br>

#### 특징

- 각 노드의 자식이 2개 이하
- 각 노드의 왼쪽 자식은 부모보다 작고, 오른쪽 자식은 부모보다 큼
- 중복된 노드가 없어야 함

***중복이 없어야 하는 이유는?***

검색 목적 자료구조인데, 굳이 중복이 많은 경우에 트리를 사용하여 검색 속도를 느리게 할 필요가 없음. (트리에 삽입하는 것보다, 노드에 count 값을 가지게 하여 처리하는 것이 훨씬 효율적)

<br>

이진탐색트리의 순회는 **'중위순회(inorder)' 방식 (왼쪽 - 루트 - 오른쪽)**

중위 순회로 **정렬된 순서**를 읽을 수 있음

<br>

#### BST 핵심연산

- 검색
- 삽입
- 삭제
- 트리 생성
- 트리 삭제

<br>

#### 시간 복잡도

- 균등 트리 : 노드 개수가 N개일 때 O(logN)
- 편향 트리 : 노드 개수가 N개일 때 O(N)

> 삽입, 검색, 삭제 시간복잡도는 **트리의 Depth**에 비례

<br>

#### 삭제의 3가지 Case

1) 자식이 없는 leaf 노드일 때 → 그냥 삭제

2) 자식이 1개인 노드일 때 → 지워진 노드에 자식을 올리기

3) 자식이 2개인 노드일 때 → 오른쪽 자식 노드에서 가장 작은 값 or 왼쪽 자식 노드에서 가장 큰 값 올리기

<br>

편향된 트리(정렬된 상태 값을 트리로 만들면 한쪽으로만 뻗음)는 시간복잡도가 O(N)이므로 트리를 사용할 이유가 사라짐 → 이를 바로 잡도록 도와주는 개선된 트리가 AVL Tree, RedBlack Tree

<br>

[소스 코드(java)](<https://github.com/kim6394/tech-interview-for-developer/blob/master/Computer%20Science/Data%20Structure/code/binarySearchTree.java>)

================================================
FILE: Computer Science/Data Structure/Hash.md
================================================
## 해시(Hash)

데이터를 효율적으로 관리하기 위해, 임의의 길이 데이터를 고정된 길이의 데이터로 매핑하는 것

해시 함수를 구현하여 데이터 값을 해시 값으로 매핑한다.

<br>

```
Lee → 해싱함수 → 5
Kim → 해싱함수 → 3
Park → 해싱함수 → 2
...
Chun → 해싱함수 → 5 // Lee와 해싱값 충돌
```

결국 데이터가 많아지면, 다른 데이터가 같은 해시 값으로 충돌나는 현상이 발생함 **'collision' 현상**

**_그래도 해시 테이블을 쓰는 이유는?_**

> 적은 자원으로 많은 데이터를 효율적으로 관리하기 위해
>
> 하드디스크나, 클라우드에 존재하는 무한한 데이터들을 유한한 개수의 해시값으로 매핑하면 작은 메모리로도 프로세스 관리가 가능해짐!

- 언제나 동일한 해시값 리턴, index를 알면 빠른 데이터 검색이 가능해짐
- 해시테이블의 시간복잡도 O(1) - (이진탐색트리는 O(logN))

<br>

##### 충돌 문제 해결

1. **체이닝** : 연결리스트로 노드를 계속 추가해나가는 방식
   (제한 없이 계속 연결 가능, but 메모리 문제)

2. **Open Addressing** : 해시 함수로 얻은 주소가 아닌 다른 주소에 데이터를 저장할 수 있도록 허용 (해당 키 값에 저장되어있으면 다음 주소에 저장)

3. **선형 탐사** : 정해진 고정 폭으로 옮겨 해시값의 중복을 피함
4. **제곱 탐사** : 정해진 고정 폭을 제곱수로 옮겨 해시값의 중복을 피함

<br>

## 해시 버킷 동적 확장

해시 버킷의 크기가 충분히 크다면 해시 충돌 빈도를 낮출 수 있다

하지만 메모리는 한정된 자원이기 때문에 무작정 큰 공간을 할당해 줄 수 없다

때문에 `load factor`가 일정 수준 이상 이라면 (보편적으로는 0.7 ~ 0.8) 해시 버킷의 크기를 확장하는 동적 확장 방식을 사용한다

- **load factor** : 할당된 키의 개수 / 해시 버킷의 크기

해시 버킷이 동적 확장 될 때 `리해싱` 과정을 거치게 된다

- **리해싱(Rehashing)** : 기존 저장되어 있는 값들을 다시 해싱하여 새로운 키를 부여하는 것을 말한다

<br>

<br>

참고자료 : [링크](https://ratsgo.github.io/data%20structure&algorithm/2017/10/25/hash/)


================================================
FILE: Computer Science/Data Structure/Heap.md
================================================
## [자료구조] 힙(Heap)

<br>

##### 알아야할 것

> 1.힙의 개념
>
> 2.힙의 삽입 및 삭제

<br>

힙은, 우선순위 큐를 위해 만들어진 자료구조다.

먼저 **우선순위 큐**에 대해서 간략히 알아보자 

<br>

**우선순위 큐** : 우선순위의 개념을 큐에 도입한 자료구조

> 데이터들이 우선순위를 가지고 있음. 우선순위가 높은 데이터가 먼저 나감

스택은 LIFO, 큐는 FIFO

<br>

##### 언제 사용?

> 시뮬레이션 시스템, 작업 스케줄링, 수치해석 계산

우선순위 큐는 배열, 연결리스트, 힙으로 구현 (힙으로 구현이 가장 효율적!)

힙 → 삽입 : O(logn) , 삭제 : O(logn)

<br>

<br>

### 힙(Heap)

---

완전 이진 트리의 일종

> 여러 값 중, 최대값과 최소값을 빠르게 찾아내도록 만들어진 자료구조

반정렬 상태

힙 트리는 중복된 값 허용 (이진 탐색 트리는 중복값 허용X)

<br>

#### 힙 종류

###### 최대 힙(max heap)

  부모 노드의 키 값이 자식 노드의 키 값보다 크거나 같은 완전 이진 트리

###### 최소 힙(min heap)

  부모 노드의 키 값이 자식 노드의 키 값보다 작거나 같은 완전 이진 트리

 <img src="https://t1.daumcdn.net/cfile/tistory/17084F504DA9895214">

<br>

#### 구현

---

힙을 저장하는 표준적인 자료구조는 `배열`

구현을 쉽게 하기 위해 배열의 첫번째 인덱스인 0은 사용되지 않음

특정 위치의 노드 번호는 새로운 노드가 추가되어도 변하지 않음

(ex. 루트 노드(1)의 오른쪽 노드 번호는 항상 3)

 <br>

##### 부모 노드와 자식 노드 관계

```
왼쪽 자식 index = (부모 index) * 2

오른쪽 자식 index = (부모 index) * 2 + 1

부모 index = (자식 index) / 2
```

<br>

#### 힙의 삽입

1.힙에 새로운 요소가 들어오면, 일단 새로운 노드를 힙의 마지막 노드에 삽입

2.새로운 노드를 부모 노드들과 교환

<br>

###### 최대 힙 삽입 구현

```java
void insert_max_heap(int x) {
    
    maxHeap[++heapSize] = x; 
    // 힙 크기를 하나 증가하고, 마지막 노드에 x를 넣음
    
    for( int i = heapSize; i > 1; i /= 2) {
        
        // 마지막 노드가 자신의 부모 노드보다 크면 swap
        if(maxHeap[i/2] < maxHeap[i]) {
            swap(i/2, i);
        } else {
            break;
        }
        
    }
}
```

부모 노드는 자신의 인덱스의 /2 이므로, 비교하고 자신이 더 크면 swap하는 방식

<br>

#### 힙의 삭제

1.최대 힙에서 최대값은 루트 노드이므로 루트 노드가 삭제됨
(최대 힙에서 삭제 연산은 최대값 요소를 삭제하는 것)

2.삭제된 루트 노드에는 힙의 마지막 노드를 가져옴

3.힙을 재구성

<br>

###### 최대 힙 삭제 구현

```java
int delete_max_heap() {
    
    if(heapSize == 0) // 배열이 비어있으면 리턴
        return 0;
    
    int item = maxHeap[1]; // 루트 노드의 값을 저장
    maxHeap[1] = maxHeap[heapSize]; // 마지막 노드 값을 루트로 이동
    maxHeap[heapSize--] = 0; // 힙 크기를 하나 줄이고 마지막 노드 0 초기화
    
    for(int i = 1; i*2 <= heapSize;) {
        
        // 마지막 노드가 왼쪽 노드와 오른쪽 노드보다 크면 끝
        if(maxHeap[i] > maxHeap[i*2] && maxHeap[i] > maxHeap[i*2+1]) {
            break;
        }
        
        // 왼쪽 노드가 더 큰 경우, swap
        else if (maxHeap[i*2] > maxHeap[i*2+1]) {
            swap(i, i*2);
            i = i*2;
        }
        
        // 오른쪽 노드가 더 큰 경우
        else {
            swap(i, i*2+1);
            i = i*2+1;
        }
    }
    
    return item;
    
}
```

<br>

<br>

**[참고 자료]** [링크](<https://gmlwjd9405.github.io/2018/05/10/data-structure-heap.html>)

================================================
FILE: Computer Science/Data Structure/Linked List.md
================================================
### Linked List

---

![img](https://www.geeksforgeeks.org/wp-content/uploads/gq/2013/03/Linkedlist.png)

연속적인 메모리 위치에 저장되지 않는 선형 데이터 구조

(포인터를 사용해서 연결된다)

각 노드는 **데이터 필드**와 **다음 노드에 대한 참조**를 포함하는 노드로 구성

<br/>

**왜 Linked List를 사용하나?**

> 배열은 비슷한 유형의 선형 데이터를 저장하는데 사용할 수 있지만 제한 사항이 있음
>
> 1) 배열의 크기가 고정되어 있어 미리 요소의 수에 대해 할당을 받아야 함
>
> 2) 새로운 요소를 삽입하는 것은 비용이 많이 듬 (공간을 만들고, 기존 요소 전부 이동)

**장점**

> 1) 동적 크기
>
> 2) 삽입/삭제 용이

**단점**

> 1) 임의로 액세스를 허용할 수 없음. 즉, 첫 번째 노드부터 순차적으로 요소에 액세스 해야함 (이진 검색 수행 불가능)
>
> 2) 포인터의 여분의 메모리 공간이 목록의 각 요소에 필요



노드 구현은 아래와 같이 데이터와 다음 노드에 대한 참조로 나타낼 수 있다

```
// A linked list node 
struct Node 
{ 
  int data; 
  struct Node *next; 
}; 
```



**Single Linked List**

노드 3개를 잇는 코드를 만들어보자

```
      head         second         third 
        |             |             | 
        |             |             | 
    +---+---+     +---+---+     +----+----+ 
    | 1  | o----->| 2 | o-----> |  3 |  # | 
    +---+---+     +---+---+     +----+----+
```

[소스 코드]()



<br/>

<br/>

**노드 추가**

- 앞쪽에 노드 추가

```
void push(struct Node** head_ref, int new_data){
    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));

    new_node->data = new_data;

    new_node->next = (*head_ref);

    (*head_ref) = new_node;
}
```

</br>

- 특정 노드 다음에 추가

```
void insertAfter(struct Node* prev_node, int new_data){
    if (prev_node == NULL){
        printf("이전 노드가 NULL이 아니어야 합니다.");
        return;
    }

    struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));

    new_node->data = new_data;
    new_node->next = prev_node->next;

    prev_node->next = new_node;
    
}
```

</br>

- 끝쪽에 노드 추가

```
void append(struct Node** head_ref, int new_data){
    struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));

    struct Node *last = *head_ref;

    new_node->data = new_data;

    new_node->next = NULL;

    if (*head_ref == NULL){
        *head_ref = new_node;
        return;
    }

    while(last->next != NULL){
        last = last->next;
    }

    last->next = new_node;
    return;

}
```



================================================
FILE: Computer Science/Data Structure/README.md
================================================
## 자료구조

<br>

#### 배열(Array)

---

<u>정적으로 필요한만큼만 원소를 저장</u>할 수 있는 공간이 할당

이때 각 원소의 주소는 연속적으로 할당됨

index를 통해 O(1)에 접근이 가능함

삽입 및 삭제는 O(N)

지정된 개수가 초과되면? → **배열 크기를 재할당한 후 복사**해야함

<br>

#### 리스트(List)

---

<u>노드(Node)들의 연결</u>로 이루어짐

크기 제한이 없음 ( heap 용량만 충분하면! )

다음 노드에 대한 **참조를 통해 접근** ( O(N) )

삽입과 삭제가 편함 O(1)

<br>

#### ArrayList

---

동적으로 크기가 조정되는 배열

배열이 가득 차면? → 알아서 그 크기를 2배로 할당하고 복사 수행

재할당에 걸리는 시간은 O(N)이지만, 자주 일어나는 일이 아니므로 접근시간은 O(1)

<br>

#### 스택(Stack)

---

LIFO 방식 (나중에 들어온게 먼저 나감)

원소의 삽입 및 삭제가 한쪽 끝에서만 이루어짐 (이 부분을 top이라고 칭함)

함수 호출 시 지역변수, 매개변수 정보를 저장하기 위한 공간을 스택으로 사용함

<br>

#### 큐(Queue)

---

FIFO 방식 (먼저 들어온게 먼저 나감)

원소의 삽입 및 삭제가 양쪽 끝에서 일어남 (front, rear)

FIFO 운영체제, 은행 대기열 등에 해당

<br>

#### 우선순위 큐(Priority Queue)

---

FIFO 방식이 아닌 <u>데이터를 근거로 한 우선순위를 판단하고, 우선순위가 높은 것부터</u> 나감

구현 방법 3가지 (배열, 연결리스트, 힙)

##### 1.배열

간단하게 구현이 가능

데이터 삽입 및 삭제 과정을 진행 시, O(N)으로 비효율 발생 (**한 칸씩 당기거나 밀어야하기 때문**)

삽입 위치를 찾기 위해 배열의 모든 데이터를 탐색해야 함 (우선순위가 가장 낮을 경우)

##### 2.연결리스트

삽입 및 삭제 O(1)

하지만 삽입 위치를 찾을 때는 배열과 마찬가지로 비효율 발생

##### 3.힙

힙은 위 2가지를 모두 효율적으로 처리가 가능함 (따라서 우선순위 큐는 대부분 힙으로 구현)

힙은 **완전이진트리의 성질을 만족하므로, 1차원 배열로 표현이 가능**함 ( O(1)에 접근이 가능 )

root index에 따라 child index를 계산할 수 있음

```
root index = 0

left index = index * 2 + 1
right index = index * 2 + 2
```

**데이터의 삽입**은 트리의 leaf node(자식이 없는 노드)부터 시작

삽입 후, heapify 과정을 통해 힙의 모든 부모-자식 노드의 우선순위에 맞게 설정됨
(이때, 부모의 우선순위는 자식의 우선순위보다 커야 함)

**데이터의 삭제**는 root node를 삭제함 (우선순위가 가장 큰 것)

삭제 후, 마지막 leaf node를 root node로 옮긴 뒤 heapify 과정 수행

<br>

#### 트리(Tree)

---

사이클이 없는 무방향 그래프

완전이진트리 기준 높이는 logN

트리를 순회하는 방법은 여러가지가 있음

1.**중위 순회** : left-root-right

2.**전위 순회** : root-left-right

3.**후위 순회** : left-right-root

4.**레벨 순서 순회** : 노드를 레벨 순서로 방문 (BFS와 동일해 큐로 구현 가능)

<br>

#### 이진탐색트리(BST)

---

노드의 왼쪽은 노드의 값보다 작은 값들, 오른쪽은 노드의 값보다 큰 값으로 구성

삽입 및 삭제, 탐색까지 이상적일 때는 모두 O(logN) 가능

만약 편향된 트리면 O(N)으로 최악의 경우가 발생

<br>

#### 해시 테이블(Hash Table)

---

효율적 탐색을 위한 자료구조

key - value 쌍으로 이루어짐

해시 함수를 통해 입력받은 key를 정수값(index)로 대응시킴

충돌(collision)에 대한 고려 필요

<br>

##### 충돌(collision) 해결방안

해시 테이블에서 중복된 값에 대한 충돌 가능성이 있기 때문에 해결방안을 세워야 함

##### 1.선형 조사법(linear probing)

충돌이 일어난 항목을 해시 테이블의 다른 위치에 저장

```
예시)
ht[k], ht[k+1], ht[k+2] ...

※ 삽입 상황
충돌이 ht[k]에서 일어났다면, ht[k+1]이 비어있는지 조사함. 차있으면 ht[k+2] 조사 ...
테이블 끝까지 도달하면 다시 처음으로 돌아옴. 시작 위치로 돌아온 경우는 테이블이 모두 가득 찬 경우임

※ 검색 상황
ht[k]에 있는 키가 다른 값이면, ht[k+1]에 같은 키가 있는지 조사함. 
비어있는 공간이 나오거나, 검색을 시작한 위치로 돌아오면 찾는 키가 없는 경우
```

##### 2.이차 조사법

선형 조사법에서 발생하는 **집적화 문제를 완화**시켜 줌

```
h(k), h(k)+1, h(k)+4, h(k)+9 ...
```

##### 3.이중 해시법

재해싱(rehasing)이라고도 함

충돌로 인해 비어있는 버킷을 찾을 때 추가적인 해시 함수 h'()를 사용하는 방식

```
h'(k) = C - (k mod C)

조사 위치
h(k), h(k)+h'(k), h(k) + 2h'(k) ...
```

##### 4.체이닝

각 버킷을 고정된 개수의 슬롯 대신, 유동적 크기를 갖는 **연결리스트로 구성**하는 방식

충돌 뿐만 아니라 오버플로우 문제도 해결 가능

버킷 내에서 항목을 찾을 때는 연결리스트 순차 탐색 활용

##### 5.해싱 성능 분석

```
a = n / M

a = 적재 비율
n = 저장되는 항목 개수
M = 해시테이블 크기
```

<br>

##### 맵(map)과 해시맵(hashMap)의 차이는?

map 컨테이너는 이진탐색트리(BST)를 사용하다가 최근에 레드블랙트리를 사용하는 중

key 값을 이용해 트리를 탐색하는 방식임 → 따라서 데이터 접근, 삽입, 삭제는 O( logN )

반면 해시맵은 해시함수를 활용해 O(1)에 접근 가능

하지만 C++에서는 해시맵을 STL로 지원해주지 않는데, 충돌 해결에 있어서 안정적인 방법이 아니기 때문 (해시 함수는 collision 정책에 따라 성능차이가 큼) 

================================================
FILE: Computer Science/Data Structure/Stack & Queue.md
================================================
## 스택(Stack)

입력과 출력이 한 곳(방향)으로 제한

##### LIFO (Last In First Out, 후입선출) : 가장 나중에 들어온 것이 가장 먼저 나옴

<br>

***언제 사용?***

함수의 콜스택, 문자열 역순 출력, 연산자 후위표기법

<br>

데이터 넣음 : push() 

데이터 최상위 값 뺌 : pop()

비어있는 지 확인 : isEmpty()

꽉차있는 지 확인 : isFull()

+SP

<br>

push와 pop할 때는 해당 위치를 알고 있어야 하므로 기억하고 있는 '스택 포인터(SP)'가 필요함

스택 포인터는 다음 값이 들어갈 위치를 가리키고 있음 (처음 기본값은 -1)

```java
private int sp = -1;
```

<br>

##### push

```java
public void push(Object o) {
    if(isFull(o)) {
        return;
    }
    
    stack[++sp] = o;
}
```

스택 포인터가 최대 크기와 같으면 return

아니면 스택의 최상위 위치에 값을 넣음

<br>

##### pop

```java
public Object pop() {
    
    if(isEmpty(sp)) {
        return null;
    }
    
    Object o = stack[sp--];
    return o;
    
}
```

스택 포인터가 0이 되면 null로 return;

아니면 스택의 최상위 위치 값을 꺼내옴

<br>

##### isEmpty

```java
private boolean isEmpty(int cnt) {
    return sp == -1 ? true : false;
}
```

입력 값이 최초 값과 같다면 true, 아니면 false

<br>

##### isFull

```java
private boolean isFull(int cnt) {
    return sp + 1 == MAX_SIZE ? true : false;
}
```

스택 포인터 값+1이 MAX_SIZE와 같으면 true, 아니면 false

<br>

<br>

#### 동적 배열 스택

위처럼 구현하면 스택에는 MAX_SIZE라는 최대 크기가 존재해야 한다

(스택 포인터와 MAX_SIZE를 비교해서 isFull 메소드로 비교해야되기 때문!)

<br>

최대 크기가 없는 스택을 만드려면?

> arraycopy를 활용한 동적배열 사용

<br>

```java
public void push(Object o) {
    
    if(isFull(sp)) {
        
        Object[] arr = new Object[MAX_SIZE * 2];
        System.arraycopy(stack, 0, arr, 0, MAX_SIZE);
        stack = arr;
        MAX_SIZE *= 2; // 2배로 증가
    }
    
    stack[sp++] = o;
}
```

기존 스택의 2배 크기만큼 임시 배열(arr)을 만들고

arraycopy를 통해 stack의 인덱스 0부터 MAX_SIZE만큼을 arr 배열의 0번째부터 복사한다

복사 후에 arr의 참조값을 stack에 덮어씌운다

마지막으로 MAX_SIZE의 값을 2배로 증가시켜주면 된다.

<br>

이러면, 스택이 가득찼을 때 자동으로 확장되는 스택을 구현할 수 있음

<br>

#### 스택을 연결리스트로 구현해도 해결 가능

```java
public class Node {

    public int data;
    public Node next;

    public Node() {
    }

    public Node(int data) {
        this.data = data;
        this.next = null;
    }
}
```

```java
public class Stack {
    private Node head;
    private Node top;

    public Stack() {
        head = top = null;
    }

    private Node createNode(int data) {
        return new Node(data);
    }

    private boolean isEmpty() {
        return top == null ? true : false;
    }

    public void push(int data) {
        if (isEmpty()) { // 스택이 비어있다면
            head = createNode(data);
            top = head;
        }
        else { //스택이 비어있지 않다면 마지막 위치를 찾아 새 노드를 연결시킨다.
            Node pointer = head;

            while (pointer.next != null)
                pointer = pointer.next;

            pointer.next = createNode(data);
            top = pointer.next;
        }
    }

    public int pop() {
        int popData;
        if (!isEmpty()) { // 스택이 비어있지 않다면!! => 데이터가 있다면!!
            popData = top.data; // pop될 데이터를 미리 받아놓는다.
            Node pointer = head; // 현재 위치를 확인할 임시 노드 포인터

            if (head == top) // 데이터가 하나라면
                head = top = null;
            else { // 데이터가 2개 이상이라면
                while (pointer.next != top) // top을 가리키는 노드를 찾는다.
                    pointer = pointer.next;

                pointer.next = null; // 마지막 노드의 연결을 끊는다.
                top = pointer; // top을 이동시킨다.
            }
            return popData;
        }
        return -1; // -1은 데이터가 없다는 의미로 지정해둠.

    }

}
```

<br>

<br>

<br>

## 큐(Queue)

입력과 출력을 한 쪽 끝(front, rear)으로 제한

##### FIFO (First In First Out, 선입선출) : 가장 먼저 들어온 것이 가장 먼저 나옴

<br>

***언제 사용?***

버퍼, 마구 입력된 것을 처리하지 못하고 있는 상황, BFS

<br>

큐의 가장 첫 원소를 front, 끝 원소를 rear라고 부름

큐는 **들어올 때 rear로 들어오지만, 나올 때는 front부터 빠지는 특성**을 가짐

접근방법은 가장 첫 원소와 끝 원소로만 가능

<br>

데이터 넣음 : enQueue()

데이터 뺌 : deQueue()

비어있는 지 확인 : isEmpty()

꽉차있는 지 확인 : isFull()

<br>

데이터를 넣고 뺄 때 해당 값의 위치를 기억해야 함. (스택에서 스택 포인터와 같은 역할)

이 위치를 기억하고 있는 게 front와 rear

front : deQueue 할 위치 기억

rear : enQueue 할 위치 기억

<br>

##### 기본값

```java
private int size = 0; 
private int rear = -1; 
private int front = -1;

Queue(int size) { 
    this.size = size;
    this.queue = new Object[size];
}
```

<br>

<br>

##### enQueue

```java
public void enQueue(Object o) {
    
    if(isFull()) {
        return;
    }
    
    queue[++rear] = o;
}
```

enQueue 시, 가득 찼다면 꽉 차 있는 상태에서 enQueue를 했기 때문에 overflow

아니면 rear에 값 넣고 1 증가

<br>

<br>

##### deQueue

```java
public Object deQueue(Object o) {
    
    if(isEmpty()) { 
        return null;
    }
    
    Object o = queue[front];
    queue[front++] = null;
    return o;
}
```

deQueue를 할 때 공백이면 underflow

front에 위치한 값을 object에 꺼낸 후, 꺼낸 위치는 null로 채워줌

<br>

#####  isEmpty

```java
public boolean isEmpty() {
    return front == rear;
}
```

front와 rear가 같아지면 비어진 것

<br>

##### isFull

```java
public boolean isFull() {
    return (rear == queueSize-1);
}
```

rear가 사이즈-1과 같아지면 가득찬 것

<br>

---

일반 큐의 단점 : 큐에 빈 메모리가 남아 있어도, 꽉 차있는것으로 판단할 수도 있음

(rear가 끝에 도달했을 때)

<br>

이를 개선한 것이 **'원형 큐'**

논리적으로 배열의 처음과 끝이 연결되어 있는 것으로 간주함!

<br>

원형 큐는 초기 공백 상태일 때 front와 rear가 0

공백, 포화 상태를 쉽게 구분하기 위해 **자리 하나를 항상 비워둠**

```
(index + 1) % size로 순환시킨다
```

<br>

##### 기본값

```java
private int size = 0; 
private int rear = 0; 
private int front = 0;

Queue(int size) { 
    this.size = size;
    this.queue = new Object[size];
}
```

<br>

##### enQueue

```java
public void enQueue(Object o) {
    
    if(isFull()) {
        return;
    }
    
    rear = (++rear) % size;
    queue[rear] = o;
}
```

enQueue 시, 가득 찼다면 꽉 차 있는 상태에서 enQueue를 했기 때문에 overflow

<br>

<br>

##### deQueue

```java
public Object deQueue(Object o) {
    
    if(isEmpty()) { 
        return null;
    }
    
    front = (++front) % size;
    Object o = queue[front];
    return o;
}
```

deQueue를 할 때 공백이면 underflow

<br>

#####  isEmpty

```java
public boolean isEmpty() {
    return front == rear;
}
```

front와 rear가 같아지면 비어진 것

<br>

##### isFull

```java
public boolean isFull() {
    return ((rear+1) % size == front);
}
```

rear+1%size가 front와 같으면 가득찬 것

<br>

원형 큐의 단점 : 메모리 공간은 잘 활용하지만, 배열로 구현되어 있기 때문에 큐의 크기가 제한

<br>

<br>

이를 개선한 것이 '연결리스트 큐'

##### 연결리스트 큐는 크기가 제한이 없고 삽입, 삭제가 편리

<br>

##### enqueue 구현

```java
public void enqueue(E item) {
    Node oldlast = tail; // 기존의 tail 임시 저장
    tail = new Node; // 새로운 tail 생성
    tail.item = item;
    tail.next = null;
    if(isEmpty()) head = tail; // 큐가 비어있으면 head와 tail 모두 같은 노드 가리킴
    else oldlast.next = tail; // 비어있지 않으면 기존 tail의 next = 새로운 tail로 설정
}
```

> - 데이터 추가는 끝 부분인 tail에 한다.
>
> - 기존의 tail는 보관하고, 새로운 tail 생성
>
> - 큐가 비었으면 head = tail를 통해 둘이 같은 노드를 가리키도록 한다.
> - 큐가 비어있지 않으면, 기존 tail의 next에 새로만든 tail를 설정해준다.

<br>

##### dequeue 구현

```java
public T dequeue() {
    // 비어있으면
    if(isEmpty()) {
        tail = head;
        return null;
    }
    // 비어있지 않으면
    else {
        T item = head.item; // 빼낼 현재 front 값 저장
        head = head.next; // front를 다음 노드로 설정
        return item;
    }
}
```

> - 데이터는 head로부터 꺼낸다. (가장 먼저 들어온 것부터 빼야하므로)
> - head의 데이터를 미리 저장해둔다.
> - 기존의 head를 그 다음 노드의 head로 설정한다.
> - 저장해둔 데이터를 return 해서 값을 빼온다.

<br>

이처럼 삽입은 tail, 제거는 head로 하면서 삽입/삭제를 스택처럼 O(1)에 가능하도록 구현이 가능하다.


================================================
FILE: Computer Science/Data Structure/Tree.md
================================================
# Tree

<br>

```
Node와 Edge로 이루어진 자료구조
Tree의 특성을 이해하자
```

<br>

<img src="https://www.geeksforgeeks.org/wp-content/uploads/binary-tree-to-DLL.png">

<br>

트리는 값을 가진 `노드(Node)`와 이 노드들을 연결해주는 `간선(Edge)`으로 이루어져있다.

그림 상 데이터 1을 가진 노드가 `루트(Root) 노드`다.

모든 노드들은 0개 이상의 자식(Child) 노드를 갖고 있으며 보통 부모-자식 관계로 부른다.

<br>

아래처럼 가족 관계도를 그릴 때 트리 형식으로 나타내는 경우도 많이 봤을 것이다. 자료구조의 트리도 이 방식을 그대로 구현한 것이다.

<img src="https://post-phinf.pstatic.net/MjAxOTA4MjZfMTg1/MDAxNTY2Nzc0Mzk2OTMw.k2EDmhB2y4O1MVrL-XqOXibXkSOBtGX8r86emCgUk9Eg.8C_5nfeIvIDSiLO8FL-i4e28h-8DmbQRS4r2CqSJ6TUg.JPEG/2216_nephew.jpg?type=w1200" width="500">

<br>

트리는 몇 가지 특징이 있다.

- 트리에는 사이클이 존재할 수 없다. (만약 사이클이 만들어진다면, 그것은 트리가 아니고 그래프다)
- 모든 노드는 자료형으로 표현이 가능하다.
- 루트에서 한 노드로 가는 경로는 유일한 경로 뿐이다.
- 노드의 개수가 N개면, 간선은 N-1개를 가진다.

<br>

가장 중요한 것은, `그래프`와 `트리`의 차이가 무엇인가인데, 이는 사이클의 유무로 설명할 수 있다.

사이클이 존재하지 않는 `그래프`라 하여 무조건 `트리`인 것은 아니다 사이클이 존재하지 않는 그래프는 `Forest`라 지칭하며 트리의 경우 싸이클이 존재하지 않고 모든 노드가 간선으로 이어져 있어야 한다

<br>

### 트리 순회 방식

트리를 순회하는 방식은 총 4가지가 있다. 위의 그림을 예시로 진행해보자

<br>

<img src="https://www.geeksforgeeks.org/wp-content/uploads/binary-tree-to-DLL.png">

<br>

1. #### 전위 순회(pre-order)

   각 부모 노드를 순차적으로 먼저 방문하는 방식이다.

   (부모 → 왼쪽 자식 → 오른쪽 자식)

   > 1 → 2 → 4 → 8 → 9 → 5 → 10 → 11 → 3 → 6 → 13 → 7 → 14

   <br>

2. #### 중위 순회(in-order)

   왼쪽 하위 트리를 방문 후 부모 노드를 방문하는 방식이다.

   (왼쪽 자식 → 부모 → 오른쪽 자식)

   > 8 → 4 → 9 → 2 → 10 → 5 → 11 → 1 → 6 → 13 → 3 →14 → 7

   <br>

3. #### 후위 순회(post-order)

   왼쪽 하위 트리부터 하위를 모두 방문 후 부모 노드를 방문하는 방식이다.

   (왼쪽 자식 → 오른쪽 자식 → 부모)

   > 8 → 9 → 4 → 10 → 11 → 5 → 2 → 13 → 6 → 14 → 7 → 3 → 1

   <br>

4. #### 레벨 순회(level-order)

   부모 노드부터 계층 별로 방문하는 방식이다.

   > 1 → 2 → 3 → 4 → 5 → 6 → 7 → 8 → 9 → 10 → 11 → 13 → 14

<br>

<br>

### Code

```java
public class Tree<T> {
    private Node<T> root;

    public Tree(T rootData) {
        root = new Node<T>();
        root.data = rootData;
        root.children = new ArrayList<Node<T>>();
    }

    public static class Node<T> {
        private T data;
        private Node<T> parent;
        private List<Node<T>> children;
    }
}
```

<br>

<br>

#### [참고 자료]

- [링크](https://www.geeksforgeeks.org/binary-tree-data-structure/)


================================================
FILE: Computer Science/Data Structure/Trie.md
================================================
## 트라이(Trie)

> 문자열에서 검색을 빠르게 도와주는 자료구조

```
정수형에서 이진탐색트리를 이용하면 시간복잡도 O(logN)
하지만 문자열에서 적용했을 때, 문자열 최대 길이가 M이면 O(M*logN)이 된다.

트라이를 활용하면? → O(M)으로 문자열 검색이 가능함!
```

<br>

<img src="https://t1.daumcdn.net/cfile/tistory/24354E335833A7CF17">

> 예시 그림에서 주어지는 배열의 총 문자열 개수는 8개인데, 트라이를 활용한 트리에서도 마지막 끝나는 노드마다 '네모' 모양으로 구성된 것을 확인하면 총 8개다.

<br>

해당 자료구조를 풀어보기 위해 좋은 문제 : [백준 5052(전화번호 목록)](<https://www.acmicpc.net/problem/5052>)

##### 문제에서 Trie를 java로 구현한 코드

```java
static class Trie {
    boolean end;
    boolean pass;
    Trie[] child;

    Trie() {
        end = false;
        pass = false;
        child = new Trie[10];
    }

    public boolean insert(String str, int idx) {

        //끝나는 단어 있으면 false 종료
        if(end) return false;

        //idx가 str만큼 왔을때
        if(idx == str.length()) {
            end = true;
            if(pass) return false; // 더 지나가는 단어 있으면 false 종료
            else return true;
        }
        //아직 안왔을 때
        else {
            int next = str.charAt(idx) - '0';
            if(child[next] == null) {
                child[next] = new Trie();
                pass = true;
            }
            return child[next].insert(str, idx+1);
        }

    }
}
```



================================================
FILE: Computer Science/Data Structure/code/MaxHeap.java
================================================
package practice;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class MaxHeap {
	
	public static class maxHeap {
		
		private ArrayList<Integer> heap;
		
		public maxHeap() {
			heap = new ArrayList<>();
			heap.add(1000000); // ε 1 ϱ 
		}
		
		public void insert(int val) {
			heap.add(val);
			int p = heap.size() - 1;
			// Ʈ ̵, ڽij尡  ũ swap
			while(p > 1 && heap.get(p / 2) < heap.get(p)) {
				int temp = heap.get(p / 2);
				heap.set(p/2, heap.get(p));
				heap.set(p, temp);
				
				p = p / 2;
			}
		}
		
		public int delete() {
			
			if(heap.size()-1 < 1) {
				return 0;
			}
			
			int deleteItem = heap.get(1);
			
			heap.set(1, heap.get(heap.size()-1));
			heap.remove(heap.size()-1);
			
			int pos = 1;
			while((pos*2) < heap.size()) {
				
				int max = heap.get(pos*2);
				int maxPos = pos * 2;
				
				if(((pos*2+1) < heap.size()) && max < heap.get(pos*2+1)) {
					max = heap.get(pos*2+1);
					maxPos = pos*2+1;
				}
				
				if(heap.get(pos) > max) {
					break;
				}
				
				int temp = heap.get(pos);
				heap.set(pos, heap.get(maxPos));
				heap.set(maxPos, temp);
				pos = maxPos;
			}
			
			return deleteItem;
		}
		
		
	}

	public static void main(String[] args) throws Exception {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int N = Integer.parseInt(br.readLine());
		
		maxHeap heap = new maxHeap();
		
		for (int i = 0; i < N; i++) {
			int val = Integer.parseInt(br.readLine());
			
			if(val == 0) {
				System.out.println(heap.delete());
			} else {
				heap.insert(val);
			}
		}
	}

}


================================================
FILE: Computer Science/Data Structure/code/MinHeap.java
================================================
package practice;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.ArrayList;

public class MinHeap {
	
	public static class minHeap {
		
		private ArrayList<Integer> heap;
		
		//  
		public minHeap() {
			heap = new ArrayList<>();
			heap.add(0); // ε 0 ä (1 ϱ )
		}
		
		// 
		public void insert(int val) {
			heap.add(val);
			int p = heap.size() - 1;
			
			//   - 1 1 ۾   -> root ̵
			while(p > 1 && heap.get(p / 2) > heap.get(p)) {
				System.out.println("swap");
				// θ𺸴 ڽ 尡   ٲ  (ּ)
				int tmp = heap.get(p/2);
				heap.set(p/2, heap.get(p));
				heap.set(p, tmp);
				
				p = p / 2; // p θ   (θ  ε ̵)
			}
		}
		
		// 
		public int delete() {
			
			//   - 1 1  0 
			if(heap.size()-1 < 1) {
				return 0;
			}
			
			//   Ʈ 
			int deleteItem = heap.get(1);
			
			// root    ְ   
			heap.set(1, heap.get(heap.size() - 1));
			heap.remove(heap.size()-1);
			
			int pos = 1;
			while((pos * 2) < heap.size()) {
				
				int min = heap.get(pos * 2);
				int minPos = pos * 2;
				
				if (((pos*2 + 1) < heap.size()) && min > heap.get(pos*2 + 1)) {
					min = heap.get(pos*2 + 1);
					minPos = pos * 2 + 1;
				}
				
				if(heap.get(pos) < min)
					break;
				
				// θ ڽ  ȯ
				int tmp = heap.get(pos);
				heap.set(pos, heap.get(minPos));
				heap.set(minPos, tmp);
				pos = minPos;
			}
			
			return deleteItem;
		}
	}
	
	public static void main(String[] args) throws Exception {
		
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		int N = Integer.parseInt(br.readLine());
		
		minHeap heap = new minHeap();
		
		for (int i = 0; i < N; i++) {
			int val = Integer.parseInt(br.readLine());
			
			if(val == 0) {
				System.out.println(heap.delete());
			} else {
				heap.insert(val);
			}
		}
		
	}

}


================================================
FILE: Computer Science/Data Structure/code/binarySearchTree.java
================================================
public class binarySearchTree {
	
	public class Node {
		private int data;
		private Node left;
		private Node right;
		
		public Node(int data) {
			this.setData(data);
			setLeft(null);
			setRight(null);
		}

		public int getData() {
			return data;
		}

		public void setData(int data) {
			this.data = data;
		}

		public Node getLeft() {
			return left;
		}

		public void setLeft(Node left) {
			this.left = left;
		}

		public Node getRight() {
			return right;
		}

		public void setRight(Node right) {
			this.right = right;
		}
	}
	
	public Node root;
	public binarySearchTree() {
		this.root = null;
	}
	
	//Ž 
	public boolean find(int id){
		Node current = root;
		while(current!=null){
			//  ã  
			if(current.getData()==id){
				return true;
				//ã   庸 
			} else if(current.getData()>id){
				current = current.getLeft();
				//ã   庸 ũ
			} else{
				current = current.getRight();
			}
		}
		return false;
	}
	// 
	public boolean delete(int id){
		Node parent = root;
		Node current = root;
		boolean isLeftChild = false;
		while(current.getData()!=id){
			parent = current;
			if(current.getData()>id){
				isLeftChild = true;
				current = current.getLeft();
			}else{
				isLeftChild = false;
				current = current.getRight();
			}
			if(current==null){
				return false;
			}
		}
		//Case 1: ڽij尡  
		if(current.getLeft()==null && current.getRight()==null){
			if(current==root){
				root = null;
			}
			if(isLeftChild==true){
				parent.setLeft(null);
			}else{
				parent.setRight(null);
			}
		}
		//Case 2 : ϳ ڽ  
		else if(current.getRight()==null){
			if(current==root){
				root = current.getLeft();
			}else if(isLeftChild){
				parent.setLeft(current.getLeft());
			}else{
				parent.setRight(current.getLeft());
			}
		} else if(current.getLeft()==null){
			if(current==root){
				root = current.getRight();
			}else if(isLeftChild){
				parent.setLeft(current.getRight());
			}else{
				parent.setRight(current.getRight());
			}
		}
		//Case 3 : ΰ ڽ  
		else if(current.getLeft()!=null && current.getRight()!=null){
			//  Ʈ ּҰ ã
			Node successor = getSuccessor(current);
			if(current==root){
				root = successor;
			}else if(isLeftChild){
				parent.setLeft(successor);
			}else{
				parent.setRight(successor);
			}			
			successor.setLeft(current.getLeft());
		}		
		return true;		
	}

	public Node getSuccessor(Node deleleNode){
		Node successsor =null;
		Node successsorParent =null;
		Node current = deleleNode.getRight();
		while(current!=null){
			successsorParent = successsor;
			successsor = current;
			current = current.getLeft();
		}
		if(successsor!=deleleNode.getRight()){
			successsorParent.setLeft(successsor.getRight());
			successsor.setRight(deleleNode.getRight());
		}
		return successsor;
	}

	// 
	public void insert(int id){
		Node newNode = new Node(id);
		if(root==null){
			root = newNode;
			return;
		}
		Node current = root;
		Node parent = null;
		while(true){
			parent = current;
			if(id < current.getData()){				
				current = current.getLeft();
				if(current==null){
					parent.setLeft(newNode);
					return;
				}
			}else{
				current = current.getRight();
				if(current==null){
					parent.setRight(newNode);
					return;
				}
			}
		}
	}
	
	public void display(Node root){
		if(root!=null){
			display(root.getLeft());
			System.out.print(" " + root.getData());
			display(root.getRight());
		}
	}

	public static void main(String[] args) {
		
		binarySearchTree b = new binarySearchTree();
		//Ʈ 带 
		b.insert(3);b.insert(8);
		b.insert(1);b.insert(4);b.insert(6);b.insert(2);b.insert(10);b.insert(9);
		b.insert(20);b.insert(25);b.insert(15);b.insert(16);
		
		System.out.println("Ʈ  : ");
		b.display(b.root);
		System.out.println("");
		System.out.println("Ʈ 4 Ž : " + b.find(4));
		System.out.println("Ʈ 2  : " + b.delete(2));		
		b.display(b.root);
		System.out.println("\nƮ 4  : " + b.delete(4));		
		b.display(b.root);
		System.out.println("\nƮ 10  : " + b.delete(10));		
		b.display(b.root);
	}

}


================================================
FILE: Computer Science/Data Structure/code/juggling_array.cpp
================================================
#include  
using namespace std; 

// 최대공약수 gcd 활용
int gcd(int a, int b) 
{ 
    if (b == 0) 
        return a; 
  
    else
        return gcd(b, a % b); 
} 


void leftRotate(int arr[], int d, int n) 
{ 
    for (int i = 0; i < gcd(d, n); i++) { 
       
        int temp = arr[i]; 
        int j = i; 
  
        while (1) { 
            int k = j + d; 
            if (k >= n) 
                k = k - n; 
  
            if (k == i) 
                break; 
  
            arr[j] = arr[k]; 
            j = k; 
        } 
        arr[j] = temp; 
    } 
} 
  
void printArray(int arr[], int size) 
{ 
    for (int i = 0; i < size; i++) 
        cout << arr[i] << " "; 
} 
  
int main() 
{ 
    int arr[] = { 1, 2, 3, 4, 5, 6, 7 }; 
    int n = sizeof(arr) / sizeof(arr[0]); 
  
    // Function calling 
    leftRotate(arr, 2, n); 
    printArray(arr, n); 
  
    return 0; 
} 


================================================
FILE: Computer Science/Data Structure/code/linked_list.java
================================================
class LinkedList{
    
    Node head;

    static class Node {
        int data;
        Node next;
        Node(int d) { // 생성자
            data = d; next = null;
        }
    }

    public void printList() 
    { 
        Node n = head; 
        while (n != null) 
        { 
            System.out.print(n.data+" "); 
            n = n.next; 
        } 
    }

    public static void main(String[] args){

        LinkedList llist = new LinkedList();

        llist.head = new Node(1);
        Node second = new Node(2);
        Node third = new Node(3);

        /*
          llist.head        second              third 
             |                |                  | 
             |                |                  | 
         +----+------+     +----+------+     +----+------+ 
         | 1  | null |     | 2  | null |     |  3 | null | 
         +----+------+     +----+------+     +----+------+ 
        */
    
        llist.head.next = second; // 첫번째 노드에 두번째 노드 연결
        second.next = third; // 두번째 노드에 세번째 노드 연결
        
        /*
  
         llist.head        second              third 
            |                |                  | 
            |                |                  | 
        +----+------+     +----+------+     +----+------+ 
        | 1  |  o-------->| 2  |  o-------->|  3 | null | 
        +----+------+     +----+------+     +----+------+ 
        
        */
        llist.printList(); 
    }
}

================================================
FILE: Computer Science/Data Structure/code/linked_list_push.java
================================================
class LinkedList 
{ 
    Node head;
  
    class Node 
    { 
        int data; 
        Node next; 
        Node(int d) {data = d; next = null; } 
    } 
  
    public void push(int new_data) 
    { 
        Node new_node = new Node(new_data); 
  
        new_node.next = head; 
  
        head = new_node; 
    } 
  
    public void insertAfter(Node prev_node, int new_data) 
    { 
        if (prev_node == null) 
        { 
            System.out.println("The given previous node cannot be null"); 
            return; 
        } 
  
        Node new_node = new Node(new_data); 
  
        new_node.next = prev_node.next; 
  
        prev_node.next = new_node; 
    } 
     
    public void append(int new_data) 
    { 
        Node new_node = new Node(new_data); 
  
        if (head == null) 
        { 
            head = new Node(new_data); 
            return; 
        } 

        new_node.next = null; 
  
        Node last = head;  
        while (last.next != null) 
            last = last.next; 
  
        last.next = new_node; 
        return; 
    } 
  
    public void printList() 
    { 
        Node tnode = head; 
        while (tnode != null) 
        { 
            System.out.print(tnode.data+" "); 
            tnode = tnode.next; 
        } 
    } 
  
    public static void main(String[] args) 
    { 
        LinkedList llist = new LinkedList(); 
  
        //6->NUllist 
        llist.append(6); 
        
        // 7->6->NUllist 
        llist.push(7); 
     
        // 1->7->6->NUllist 
        llist.push(1); 

        // 1->7->6->4->NUllist 
        llist.append(4); 

        // 1->7->8->6->4->NUllist 
        llist.insertAfter(llist.head.next, 8); 
  
        System.out.println("\nCreated Linked list is: "); 
        llist.printList(); 
    } 
}

================================================
FILE: Computer Science/Data Structure/code/maxvalue_array.cpp
================================================
// 지정된 배열에서 하나씩 회전을 해서 i*arr[i]의 합이 가장 컸을 때 값을 출력하는 문제

#include <iostream>
using namespace std;

int maxVal(int arr[], int n){
    
    int arrSum = 0; // arr[i]의 전체 합
    int curSum = 0; // i*arr[i]의 전체 합
    
    for(int i = 0; i < n; i++){
        arrSum = arrSum + arr[i];
        curSum = curSum + (i*arr[i]);
    }
    
    int maxSum = curSum;
    
    for (int j = 1; j < n; j++){
        curSum = curSum + arrSum - n*arr[n-j];
        
        if ( curSum > maxSum )
            maxSum = curSum;
    }
    
    return maxSum;
    
}


int main(void){
    
    int arr[] = {1,20,2,10};
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << maxVal(arr, n);
    
    return 0;
}


================================================
FILE: Computer Science/Data Structure/code/rearrange_array.cpp
================================================
#include <iostream>
using namespace std;

int fix(int A[], int len){
    
    for(int i = 0; i < len; i++) {
        
        
        if (A[i] != -1 && A[i] != i){ // A[i]가 -1이 아니고, i도 아닐 때
            
            int x = A[i]; // 해당 값을 x에 저장
            
            while(A[x] != -1 && A[x] != x){ // A[x]가 -1이 아니고, x도 아닐 때
                
                int y = A[x]; // 해당 값을 y에 저장
                A[x] = x; 
                
                x = y;
            }
            
            A[x] = x;
            
            if (A[i] != i){
                A[i] = -1;
            }
        }
    }
    
}

void printArray(int A[], int len){
    for(int i = 0; i < len; i++){
        cout << A[i] << " ";
    }
}

int main() {
    
    int A[] = { -1, -1, 6, 1, 9, 
                3, 2, -1, 4, -1 };
                
    int len = sizeof(A) / sizeof(A[0]);
    fix(A, len);
    printArray(A, len);
    
    return 0;
}

================================================
FILE: Computer Science/Data Structure/code/reversal_array.cpp
================================================
#include <iostream>
using namespace std;

// swap을 활용한 reverse 구현
void reverseArr(int arr[], int start, int end){
    
    while (start < end){
        int temp = arr[start];
        arr[start] = arr[end];
        arr[end] = temp;
        
        start++;
        end--;
    }
}


// d로 나눠서 역전 알고리즘 수행
void rotateLeft(int arr[], int d, int n){
    reverseArr(arr, 0, d-1);
    reverseArr(arr, d, n-1);
    reverseArr(arr, 0, n-1);
}

void printArray(int arr[], int n){
    for(int i = 0; i < n; i++){
        cout << arr[i] << " ";
    }
}


int main(void){
    
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int n = sizeof(arr) / sizeof(arr[0]);
    int d = 3;
    
    rotateLeft(arr, d, n);
    printArray(arr, n);
    
    return 0;
}


================================================
FILE: Computer Science/Data Structure/code/rotate_array.cpp
================================================
#include  
using namespace std; 

//왼쪽으로 한번 회전
void leftRotatebyOne(int arr[], int n){
    int temp = arr[0], i;
    for(i = 0; i < n-1; i++){
        arr[i] = arr[i+1];
    }
    arr[i] = temp;
}

// d만큼 회전
void leftRotate(int arr[], int d, int n){
    for(int i = 0; i < d; i++)
        leftRotatebyOne(arr, n);
}

void printArray(int arr[], int n){
    for(int i = 0; i < n; i++)
        cout << arr[i] << " ";
}


int main(){
    int arr[] = { 1, 2, 3, 4, 5, 6, 7 };
    int n = sizeof(arr) / sizeof(arr[0]);
    
    leftRotate(arr, 2, n);
    printArray(arr, n);
    
    return 0;
}


================================================
FILE: Computer Science/Database/Redis.md
================================================
## Redis

> 빠른 오픈 소스 인 메모리 키 값 데이터 구조 스토어

보통 데이터베이스는 하드 디스크나 SSD에 저장한다. 하지만 Redis는 메모리(RAM)에 저장해서 디스크 스캐닝이 필요없어 매우 빠른 장점이 존재함

캐싱도 가능해 실시간 채팅에 적합하며 세션 공유를 위해 세션 클러스터링에도 활용된다.`

***RAM은 휘발성 아닌가요? 껐다키면 다 날아가는데..***

이를 막기위한 백업 과정이 존재한다.

- snapshot : 특정 지점을 설정하고 디스크에 백업
- AOF(Append Only File) : 명령(쿼리)들을 저장해두고, 서버가 셧다운되면 재실행해서 다시 만들어 놓는 것

데이터 구조는 key/value 값으로 이루어져 있다. (따라서 Redis는 비정형 데이터를 저장하는 비관계형 데이터베이스 관리 시스템이다)

##### value 5가지

1. String (text, binary data) - 512MB까지 저장이 가능함
2. set (String 집합)
3. sorted set (set을 정렬해둔 상태)
4. Hash
5. List (양방향 연결리스트도 가능)

================================================
FILE: Computer Science/Database/SQL Injection.md
================================================
## SQL Injection

> 해커에 의해 조작된 SQL 쿼리문이 데이터베이스에 그대로 전달되어 비정상적 명령을 실행시키는 공격 기법

<br>

#### 공격 방법

##### 1) 인증 우회

보통 로그인을 할 때, 아이디와 비밀번호를 input 창에 입력하게 된다. 쉽게 이해하기 위해 가벼운 예를 들어보자. 아이디가 abc, 비밀번호가 만약 1234일 때 쿼리는 아래와 같은 방식으로 전송될 것이다.

```
SELECT * FROM USER WHERE ID = "abc" AND PASSWORD = "1234";
```

SQL Injection으로 공격할 때, input 창에 비밀번호를 입력함과 동시에 다른 쿼리문을 함께 입력하는 것이다.

```
1234; DELETE * USER FROM ID = "1";
```

보안이 완벽하지 않은 경우, 이처럼 비밀번호가 아이디와 일치해서 True가 되고 뒤에 작성한 DELETE 문도 데이터베이스에 영향을 줄 수도 있게 되는 치명적인 상황이다.

이 밖에도 기본 쿼리문의 WHERE 절에 OR문을 추가하여 `'1' = '1'`과 같은 true문을 작성하여 무조건 적용되도록 수정한 뒤 DB를 마음대로 조작할 수도 있다. 

<br>

##### 2) 데이터 노출

시스템에서 발생하는 에러 메시지를 이용해 공격하는 방법이다. 보통 에러는 개발자가 버그를 수정하는 면에서 도움을 받을 수 있는 존재다. 해커들은 이를 역이용해 악의적인 구문을 삽입하여 에러를 유발시킨다.

즉 예를 들면, 해커는 **GET 방식으로 동작하는 URL 쿼리 스트링을 추가하여 에러를 발생**시킨다. 이에 해당하는 오류가 발생하면, 이를 통해 해당 웹앱의 데이터베이스 구조를 유추할 수 있고 해킹에 활용한다.

<br>

<br>

#### 방어 방법

##### 1) input 값을 받을 때, 특수문자 여부 검사하기

> 로그인 전, 검증 로직을 추가하여 미리 설정한 특수문자들이 들어왔을 때 요청을 막아낸다.

##### 2) SQL 서버 오류 발생 시, 해당하는 에러 메시지 감추기

> view를 활용하여 원본 데이터베이스 테이블에는 접근 권한을 높인다. 일반 사용자는 view로만 접근하여 에러를 볼 수 없도록 만든다.

##### 3) preparestatement 사용하기

> preparestatement를 사용하면, 특수문자를 자동으로 escaping 해준다. (statement와는 다르게 쿼리문에서 전달인자 값을 `?`로 받는 것) 이를 활용해 서버 측에서 필터링 과정을 통해서 공격을 방어한다.



================================================
FILE: Computer Science/Database/SQL과 NOSQL의 차이.md
================================================
## SQL과 NOSQL의 차이

<br>

웹 앱을 개발할 때, 데이터베이스를 선택할 때 고민하게 된다.

<br>

```
MySQL과 같은 SQL을 사용할까? 아니면 MongoDB와 같은 NoSQL을 사용할까?
```

<br>

보통 Spring에서 개발할 때는 MySQL을, Node.js에서는 MongoDB를 주로 사용했을 것이다.

하지만 그냥 단순히 프레임워크에 따라 결정하는 것이 아니다. 프로젝트를 진행하기에 앞서 적합한 데이터베이스를 택해야 한다. 차이점을 알아보자

<br>

#### SQL (관계형 DB)

---

 SQL을 사용하면 RDBMS에서 데이터를 저장, 수정, 삭제 및 검색 할 수 있음

관계형 데이터베이스에는 핵심적인 두 가지 특징이 있다.

- 데이터는 **정해진 데이터 스키마에 따라 테이블에 저장**된다.
- 데이터는 **관계를 통해 여러 테이블에 분산**된다.

<br>

데이터는 테이블에 레코드로 저장되는데, 각 테이블마다 명확하게 정의된 구조가 있다.
해당 구조는 필드의 이름과 데이터 유형으로 정의된다.

따라서 **스키마를 준수하지 않은 레코드는 테이블에 추가할 수 없다.** 즉, 스키마를 수정하지 않는 이상은 정해진 구조에 맞는 레코드만 추가가 가능한 것이 관계형 데이터베이스의 특징 중 하나다.

<br>

또한, 데이터의 중복을 피하기 위해 '관계'를 이용한다.

<img src="https://t1.daumcdn.net/cfile/tistory/994D09355C937ECD2D">

하나의 테이블에서 중복 없이 하나의 데이터만을 관리하기 때문에 다른 테이블에서 부정확한 데이터를 다룰 위험이 없어지는 장점이 있다.

<br>

<br>

#### NoSQL (비관계형 DB)

---

말그대로 관계형 DB의 반대다.

**스키마도 없고, 관계도 없다!**

<br>

NoSQL에서는 레코드를 문서(documents)라고 부른다.

여기서 SQL과 핵심적인 차이가 있는데, SQL은 정해진 스키마를 따르지 않으면 데이터 추가가 불가능했다. 하지만 NoSQL에서는 다른 구조의 데이터를 같은 컬렉션에 추가가 가능하다.

<br>

문서(documents)는 Json과 비슷한 형태로 가지고 있다. 관계형 데이터베이스처럼 여러 테이블에 나누어담지 않고, 관련 데이터를 동일한 '컬렉션'에 넣는다.

따라서 위 사진에 SQL에서 진행한 Orders, Users, Products 테이블로 나눈 것을 NoSQL에서는 Orders에 한꺼번에 포함해서 저장하게 된다.

따라서 여러 테이블에 조인할 필요없이 이미 필요한 모든 것을 갖춘 문서를 작성하는 것이 NoSQL이다. (NoSQL에는 조인이라는 개념이 존재하지 않음)

<br>

그러면 조인하고 싶을 때 NoSQL은 어떻게 할까? 

> 컬렉션을 통해 데이터를 복제하여 각 컬렉션 일부분에 속하는 데이터를 정확하게 산출하도록 한다.

하지만 이러면 데이터가 중복되어 서로 영향을 줄 위험이 있다. 따라서 조인을 잘 사용하지 않고 자주 변경되지 않는 데이터일 때 NoSQL을 쓰면 상당히 효율적이다.

<br>

<br>

#### 확장 개념

두 데이터베이스를 비교할 때 중요한 Scaling 개념도 존재한다.

데이터베이스 서버의 확장성은 '수직적' 확장과 '수평적' 확장으로 나누어진다.

- 수직적 확장 : 단순히 데이터베이스 서버의 성능을 향상시키는 것 (ex. CPU 업그레이드)
- 수평적 확장 : 더 많은 서버가 추가되고 데이터베이스가 전체적으로 분산됨을 의미 (하나의 데이터베이스에서 작동하지만 여러 호스트에서 작동)

<br>

데이터 저장 방식으로 인해 SQL 데이터베이스는 일반적으로 수직적 확장만 지원함

> 수평적 확장은 NoSQL 데이터베이스에서만 가능

<br>

<br>

#### 그럼 둘 중에 뭘 선택?

정답은 없다. 둘다 훌륭한 솔루션이고 어떤 데이터를 다루느냐에 따라 선택을 고려해야한다.

<br>

##### SQL 장점

- 명확하게 정의된 스키마, 데이터 무결성 보장
- 관계는 각 데이터를 중복없이 한번만 저장

##### SQL 단점

- 덜 유연함. 데이터 스키마를 사전에 계획하고 알려야 함. (나중에 수정하기 힘듬)
- 관계를 맺고 있어서 조인문이 많은 복잡한 쿼리가 만들어질 수 있음
- 대체로 수직적 확장만 가능함

<br>

##### NoSQL 장점

- 스키마가 없어서 유연함. 언제든지 저장된 데이터를 조정하고 새로운 필드 추가 가능
- 데이터는 애플리케이션이 필요로 하는 형식으로 저장됨. 데이터 읽어오는 속도 빨라짐
- 수직 및 수평 확장이 가능해서 애플리케이션이 발생시키는 모든 읽기/쓰기 요청 처리 가능

##### NoSQL 단점

- 유연성으로 인해 데이터 구조 결정을 미루게 될 수 있음
- 데이터 중복을 계속 업데이트 해야 함
- 데이터가 여러 컬렉션에 중복되어 있기 때문에 수정 시 모든 컬렉션에서 수행해야 함
  (SQL에서는 중복 데이터가 없으므로 한번만 수행이 가능)

<br>

<br>

#### SQL 데이터베이스 사용이 더 좋을 때

- 관계를 맺고 있는 데이터가 자주 변경되는 애플리케이션의 경우

  > NoSQL에서는 여러 컬렉션을 모두 수정해야 하기 때문에 비효율적

- 변경될 여지가 없고, 명확한 스키마가 사용자와 데이터에게 중요한 경우

<br>

#### NoSQL 데이터베이스 사용이 더 좋을 때

- 정확한 데이터 구조를 알 수 없거나 변경/확장 될 수 있는 경우
- 읽기를 자주 하지만, 데이터 변경은 자주 없는 경우
- 데이터베이스를 수평으로 확장해야 하는 경우 (막대한 양의 데이터를 다뤄야 하는 경우)

<br>

<br>

하나의 제시 방법이지 완전한 정답이 정해져 있는 것은 아니다.

SQL을 선택해서 복잡한 JOIN문을 만들지 않도록 설계하여 단점을 없앨 수도 있고

NoSQL을 선택해서 중복 데이터를 줄이는 방법으로 설계해서 단점을 없앨 수도 있다.



================================================
FILE: Computer Science/Database/Transaction Isolation Level.md
================================================
## 트랜잭션 격리 수준(Transaction Isolation Level)

<br>

#### **Isolation level** 

---

트랜잭션에서 일관성 없는 데이터를 허용하도록 하는 수준

<br>

#### Isolation level의 필요성

----

데이터베이스는 ACID 특징과 같이 트랜잭션이 독립적인 수행을 하도록 한다.

따라서 Locking을 통해, 트랜잭션이 DB를 다루는 동안 다른 트랜잭션이 관여하지 못하도록 막는 것이 필요하다.

하지만 무조건 Locking으로 동시에 수행되는 수많은 트랜잭션들을 순서대로 처리하는 방식으로 구현하게 되면 데이터베이스의 성능은 떨어지게 될 것이다.

그렇다고 해서, 성능을 높이기 위해 Locking의 범위를 줄인다면, 잘못된 값이 처리될 문제가 발생하게 된다.

- 따라서 최대한 효율적인 Locking 방법이 필요함!

<br>

#### Isolation level 종류

----

1. ##### Read Uncommitted (레벨 0)

   > SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리지 않는 계층

   트랜잭션에 처리중이거나, 아직 Commit되지 않은 데이터를 다른 트랜잭션이 읽는 것을 허용함

   ```
   사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 아직 완료되지 않은(Uncommitted) 트랜잭션이지만 데이터B를 읽을 수 있다
   ```

   데이터베이스의 일관성을 유지하는 것이 불가능함

   <br>

2. ##### Read Committed (레벨 1)

   > SELECT 문장이 수행되는 동안 해당 데이터에 Shared Lock이 걸리는 계층

   트랜잭션이 수행되는 동안 다른 트랜잭션이 접근할 수 없어 대기하게 됨

   Commit이 이루어진 트랜잭션만 조회 가능

   대부분의 SQL 서버가 Default로 사용하는 Isolation Level임

   ```
   사용자1이 A라는 데이터를 B라는 데이터로 변경하는 동안 사용자2는 해당 데이터에 접근이 불가능함
   ```

   <br>

3. ##### Repeatable Read (레벨 2)

   > 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리는 계층

   트랜잭션이 범위 내에서 조회한 데이터 내용이 항상 동일함을 보장함

   다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 불가능
  
   MySQL에서 Default로 사용하는 Isolation Level

   <br>

4. ##### Serializable (레벨 3)

   > 트랜잭션이 완료될 때까지 SELECT 문장이 사용하는 모든 데이터에 Shared Lock이 걸리는 계층

   완벽한 읽기 일관성 모드를 제공함

   다른 사용자는 트랜잭션 영역에 해당되는 데이터에 대한 수정 및 입력 불가능

   <br>

<br>

***선택 시 고려사항***

Isolation Level에 대한 조정은, 동시성과 데이터 무결성에 연관되어 있음

동시성을 증가시키면 데이터 무결성에 문제가 발생하고, 데이터 무결성을 유지하면 동시성이 떨어지게 됨

레벨을 높게 조정할 수록 발생하는 비용이 증가함

<br>

##### 낮은 단계 Isolation Level을 활용할 때 발생하는 현상들

- Dirty Read

  > 커밋되지 않은 수정중인 데이터를 다른 트랜잭션에서 읽을 수 있도록 허용할 때 발생하는 현상
  >
  > 어떤 트랜잭션에서 아직 실행이 끝나지 않은 다른 트랜잭션에 의한 변경사항을 보게되는 경우  
  - 발생 Level: Read Uncommitted

- Non-Repeatable Read

  > 한 트랜잭션에서 같은 쿼리를 두 번 수행할 때 그 사이에 다른 트랜잭션 값을 수정 또는 삭제하면서 두 쿼리의 결과가 상이하게 나타나는 일관성이 깨진 현상
  - 발생 Level: Read Committed, Read Uncommitted

- Phantom Read

  > 한 트랜잭션 안에서 일정 범위의 레코드를 두 번 이상 읽었을 때, 첫번째 쿼리에서 없던 레코드가 두번째 쿼리에서 나타나는 현상
  >
  > 트랜잭션 도중 새로운 레코드 삽입을 허용하기 때문에 나타나는 현상임
  - 발생 Level: Repeatable Read, Read Committed, Read Uncommitted





================================================
FILE: Computer Science/Database/Transaction.md
================================================
# DB 트랜잭션(Transaction)

<br>

#### 트렌잭션이란?

> 데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위

<br>

상태를 변화시킨다는 것 → **SQL 질의어를 통해 DB에 접근하는 것**

```
- SELECT
- INSERT
- DELETE
- UPDATE
```

<br>

작업 단위 → **많은 SQL 명령문들을 사람이 정하는 기준에 따라 정하는 것**

```
예시) 사용자 A가 사용자 B에게 만원을 송금한다.

* 이때 DB 작업
- 1. 사용자 A의 계좌에서 만원을 차감한다 : UPDATE 문을 사용해 사용자 A의 잔고를 변경
- 2. 사용자 B의 계좌에 만원을 추가한다 : UPDATE 문을 사용해 사용자 B의 잔고를 변경

현재 작업 단위 : 출금 UPDATE문 + 입금 UPDATE문
→ 이를 통틀어 하나의 트랜잭션이라고 한다.
- 위 두 쿼리문 모두 성공적으로 완료되어야만 "하나의 작업(트랜잭션)"이 완료되는 것이다. `Commit`
- 작업 단위에 속하는 쿼리 중 하나라도 실패하면 모든 쿼리문을 취소하고 이전 상태로 돌려놓아야한다. `Rollback`

```

<br>

**즉, 하나의 트랜잭션 설계를 잘 만드는 것이 데이터를 다룰 때 많은 이점을 가져다준다.**

<br>

#### 트랜잭션 특징

---

- 원자성(Atomicity)

  > 트랜잭션이 DB에 모두 반영되거나, 혹은 전혀 반영되지 않아야 된다.

- 일관성(Consistency)

  > 트랜잭션의 작업 처리 결과는 항상 일관성 있어야 한다.

- 독립성(Isolation)

  > 둘 이상의 트랜잭션이 동시에 병행 실행되고 있을 때, 어떤 트랜잭션도 다른 트랜잭션 연산에 끼어들 수 없다.

- 지속성(Durability)

  > 트랜잭션이 성공적으로 완료되었으면, 결과는 영구적으로 반영되어야 한다.

<br>

##### Commit

하나의 트랜잭션이 성공적으로 끝났고,  DB가 일관성있는 상태일 때 이를 알려주기 위해 사용하는 연산

<br>

##### Rollback

하나의 트랜잭션 처리가 비정상적으로 종료되어 트랜잭션 원자성이 깨진 경우

transaction이 정상적으로 종료되지 않았을 때, last consistent state (예) Transaction의 시작 상태) 로 roll back 할 수 있음. 

<br>

*상황이 주어지면 DB 측면에서 어떻게 해결할 수 있을지 대답할 수 있어야 함*

<br>

---

<br>

#### Transaction 관리를 위한 DBMS의 전략

이해를 위한 2가지 개념 : DBMS의 구조 / Buffer 관리 정책

<br>

1) DBMS의 구조

> 크게 2가지 : Query Processor (질의 처리기), Storage System (저장 시스템)
>
> 입출력 단위 : 고정 길이의 page 단위로 disk에 읽거나 쓴다.
>
> 저장 공간 : 비휘발성 저장 장치인 disk에 저장, 일부분을 Main Memory에 저장

<img src="https://d2.naver.com/content/images/2015/06/helloworld-407507-1.png">

<br>

2) Page Buffer Manager or Buffer Manager

DBMS의 Storage System에 속하는 모듈 중 하나로, Main Memory에 유지하는 페이지를 관리하는 모듈

> Buffer 관리 정책에 따라, UNDO 복구와 REDO 복구가 요구되거나 그렇지 않게 되므로, transaction 관리에 매우 중요한 결정을 가져온다.

<br>

3) UNDO

필요한 이유 : 수정된 Page들이 **<u>Buffer 교체 알고리즘에 따라서 디스크에 출력</u>**될 수 있음. Buffer 교체는 **<u>transaction과는 무관하게 buffer의 상태에 따라서, 결정됨</u>**. 이로 인해, 정상적으로 종료되지 않은 transaction이 변경한 page들은 원상 복구 되어야 하는데,  이 복구를 undo라고 함.

- 2개의 정책 (수정된 페이지를 디스크에 쓰는 시점으로 분류)

  steal : 수정된 페이지를 언제든지 디스크에 쓸 수 있는 정책

  - 대부분의 DBMS가 채택하는 Buffer 관리 정책
  - UNDO logging과 복구를 필요로 함.

  <br>

  ¬steal : 수정된 페이지들을 EOT (End Of Transaction)까지는 버퍼에 유지하는 정책

  - UNDO 작업이 필요하지 않지만, 매우 큰 메모리 버퍼가 필요함.

<br>

4) REDO

이미 commit한 transaction의 수정을 재반영하는 복구 작업

Buffer 관리 정책에 영향을 받음

- Transaction이 종료되는 시점에 해당 transaction이 수정한 page를 디스크에 쓸 것인가 아닌가로 기준.

  <br>

  FORCE : 수정했던 모든 페이지를 Transaction commit 시점에 disk에 반영

  transaction이 commit 되었을 때 수정된 페이지들이 disk 상에 반영되므로 redo 필요 없음.

  <br>

  ¬FORCE : commit 시점에 반영하지 않는 정책

  transaction이 disk 상의 db에 반영되지 않을 수 있기에 redo 복구가 필요. (대부분의 DBMS 정책)

  <br>
  
  <br>

#### [참고사항]

- [링크](https://d2.naver.com/helloworld/407507)

================================================
FILE: Computer Science/Database/[DB] Anomaly.md
================================================
#### [DB] Anomaly

---

> 정규화를 해야하는 이유는 잘못된 테이블 설계로 인해 Anomaly (이상 현상)가 나타나기 때문이다.
>
> 이 페이지에서는 Anomaly가 무엇인지 살펴본다.

예) {Student ID, Course ID, Department, Course ID, Grade}

1. 삽입 이상 (Insertion Anomaly)

   기본키가 {Student ID, Course ID} 인 경우 -> Course를 수강하지 않은 학생은 Course ID가 없는 현상이 발생함. 결국 Course ID를 Null로 할 수밖에 없는데, 기본키는 Null이 될 수 없으므로, Table에 추가될 수 없음.

   굳이 삽입하기 위해서는 '미수강'과 같은 Course ID를 만들어야 함.

   > 불필요한 데이터를 추가해야지, 삽입할 수 있는 상황 = Insertion Anomaly

   

2. 갱신 이상 (Update Anomaly)

   만약 어떤 학생의 전공 (Department) 이 "컴퓨터에서 음악"으로 바뀌는 경우.

   모든 Department를 "음악"으로 바꾸어야 함. 그러나 일부를 깜빡하고 바꾸지 못하는 경우, 제대로 파악 못함.

   > 일부만 변경하여, 데이터가 불일치 하는 모순의 문제 = Update Anomaly

   

3. 삭제 이상 (Deletion Anomaly)

   만약 어떤 학생이 수강을 철회하는 경우, {Student ID, Department, Course ID, Grade}의 정보 중

   Student ID, Department 와 같은 학생에 대한 정보도 함께 삭제됨.

   > 튜플 삭제로 인해 꼭 필요한 데이터까지 함께 삭제되는 문제 = Deletion Anomaly





================================================
FILE: Computer Science/Database/[DB] Index.md
================================================
# Index(인덱스)

<br>

#### 목적

```
추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조
```

테이블의 칼럼을 색인화한다.

> 마치, 두꺼운 책의 목차와 같다고 생각하면 편하다.

데이터베이스 안의 레코드를 처음부터 풀스캔하지 않고, B+ Tree로 구성된 구조에서 Index 파일 검색으로 속도를 향상시키는 기술이다.

<br>

<br>

#### 파일 구성

테이블 생성 시, 3가지 파일이 생성된다.

- FRM : 테이블 구조 저장 파일
- MYD : 실제 데이터 파일
- MYI : Index 정보 파일 (Index 사용 시 생성)

<br>

사용자가 쿼리를 통해 Index를 사용하는 칼럼을 검색하게 되면, 이때 MYI 파일의 내용을 활용한다.

<BR>

#### 단점

- Index 생성시, .mdb 파일 크기가 증가한다.
- **한 페이지를 동시에 수정할 수 있는 병행성**이 줄어든다.
- 인덱스 된 Field에서 Data를 업데이트하거나, **Record를 추가 또는 삭제시 성능이 떨어진다.**
- 데이터 변경 작업이 자주 일어나는 경우, **Index를 재작성**해야 하므로 성능에 영향을 미친다.

<br>

#### 상황 분석

- ##### 사용하면 좋은 경우

  (1) Where 절에서 자주 사용되는 Column

  (2) 외래키가 사용되는 Column

  (3) Join에 자주 사용되는 Column

  <br>

- ##### Index 사용을 피해야 하는 경우

  (1) Data 중복도가 높은 Column

  (2) DML이 자주 일어나는 Column

<br>

#### DML이 일어났을 때의 상황

- ##### INSERT

  기존 Block에 여유가 없을 때, 새로운 Data가 입력된다.

  → 새로운 Block을 할당 받은 후, Key를 옮기는 작업을 수행한다.

  → Index split 작업 동안, 해당 Block의 Key 값에 대해서 DML이 블로킹 된다. (대기 이벤트 발생)

  → 이때 Block의 논리적인 순서와 물리적인 순서가 달라질 수 있다. (인덱스 조각화)

- ##### DELETE

  <Table과 Index 상황 비교>

  Table에서 data가 delete 되는 경우 : Data가 지워지고, 다른 Data가 그 공간을 사용 가능하다.

  Index에서 Data가 delete 되는 경우 : Data가 지워지지 않고, 사용 안 됨 표시만 해둔다.

  → **Table의 Data 수와 Index의 Data 수가 다를 수 있음**

- ##### UPDATE

  Table에서 update가 발생하면 → Index는 Update 할 수 없다.

  Index에서는 **Delete가 발생한 후, 새로운 작업의 Insert 작업** / 2배의 작업이 소요되어 힘들다.

<br>

<br>

#### 인덱스 관리 방식

- ##### B-Tree 자료구조

  이진 탐색트리와 유사한 자료구조

  자식 노드를 둘이상 가질 수 있고 Balanced Tree 라는 특징이 있다 → 즉 탐색 연산에 있어 O(log N)의 시간복잡도를 갖는다.

  모든 노드들에 대해 값을 저장하고 있으며 포인터 역할을 동반한다.

- ##### B+Tree 자료구조

  B-Tree를 개선한 형태의 자료구조

  값을 리프노드에만 저장하며 리프노드들 끼리는 링크드 리스트로 연결되어 있다 → 때문에 부등호문 연산에 대해 효과적이다.

  리프 노드를 제외한 노드들은 포인터의 역할만을 수행한다.

- ##### HashTable 자료구조

  해시 함수를 이용해서 값을 인덱스로 변경 하여 관리하는 자료구조

  일반적인 경우 탐색, 삽입, 삭제 연산에 대해 O(1)의 시간 복잡도를 갖는다.

  다른 관리 방식에 비해 빠른 성능을 갖는다.

  최악의 경우 해시 충돌이 발생하는 것으로 탐색, 삽입, 삭제 연산에 대해 O(N)의 시간복잡도를 갖는다.

  값 자체를 변경하기 때문에 부등호문, 포함문등의 연산에 사용할 수 없다.

##### [참고사항]

- [링크](https://lalwr.blogspot.com/2016/02/db-index.html)


================================================
FILE: Computer Science/Database/[DB] Key.md
================================================
### [DB] Key

---

> Key란? : 검색, 정렬시 Tuple을 구분할 수 있는 기준이 되는 Attribute.

<br>

#### 1. Candidate Key (후보키)

> Tuple을 유일하게 식별하기 위해 사용하는 속성들의 부분 집합. (기본키로 사용할 수 있는 속성들)

2가지 조건 만족

* 유일성 : Key로 하나의 Tuple을 유일하게 식별할 수 있음
* 최소성 : 꼭 필요한 속성으로만 구성

<br>

#### 2. Primary Key (기본키)

> 후보키 중 선택한 Main Key

특징 

* Null 값을 가질 수 없음
* 동일한 값이 중복될 수 없음

<br>

#### 3. Alternate Key (대체키)

> 후보키 중 기본키를 제외한 나머지 키 = 보조키

<br>

#### 4. Super Key (슈퍼키)

> 유일성은 만족하지만, 최소성은 만족하지 못하는 키

<br>

#### 5. Foreign Key (외래키)

> 다른 릴레이션의 기본키를 그대로 참조하는 속성의 집합

<br>


================================================
FILE: Computer Science/Database/[Database SQL] JOIN.md
================================================
## [Database SQL] JOIN

##### 조인이란?

> 두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색하는 방법

테이블을 연결하려면, 적어도 하나의 칼럼을 서로 공유하고 있어야 하므로 이를 이용하여 데이터 검색에 활용한다.

<br>

#### JOIN 종류

---

- INNER JOIN
- LEFT OUTER JOIN
- RIGHT OUTER JOIN
- FULL OUTER JOIN
- CROSS JOIN
- SELF JOIN

<br>

<br>

- #### INNER JOIN

  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile9.uf.tistory.com%2Fimage%2F99799F3E5A8148D7036659">

  교집합으로, 기준 테이블과 join 테이블의 중복된 값을 보여준다.

  ```sql
  SELECT
  A.NAME, B.AGE
  FROM EX_TABLE A
  INNER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
  ```

  <br>

- #### LEFT OUTER JOIN

  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile6.uf.tistory.com%2Fimage%2F997E7F415A81490507F027">

  기준테이블값과 조인테이블과 중복된 값을 보여준다.

  왼쪽테이블 기준으로 JOIN을 한다고 생각하면 편하다.

  ```SQL
  SELECT
  A.NAME, B.AGE
  FROM EX_TABLE A
  LEFT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
  ```

  <br>

- #### RIGHT OUTER JOIN

  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile25.uf.tistory.com%2Fimage%2F9984CE355A8149180ABD1D">

  LEFT OUTER JOIN과는 반대로 오른쪽 테이블 기준으로 JOIN하는 것이다.

  ```SQL
  SELECT
  A.NAME, B.AGE
  FROM EX_TABLE A
  RIGHT OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
  ```

  <br>

- #### FULL OUTER JOIN

  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile24.uf.tistory.com%2Fimage%2F99195F345A8149391BE0C3">

  합집합을 말한다. A와 B 테이블의 모든 데이터가 검색된다.

  ```sql
  SELECT
  A.NAME, B.AGE
  FROM EX_TABLE A
  FULL OUTER JOIN JOIN_TABLE B ON A.NO_EMP = B.NO_EMP
  ```

  <br>

- #### CROSS JOIN

  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile10.uf.tistory.com%2Fimage%2F993F4E445A8A2D281AC66B">

  모든 경우의 수를 전부 표현해주는 방식이다.

  A가 3개, B가 4개면 총 3*4 = 12개의 데이터가 검색된다.

  ```sql
  SELECT
  A.NAME, B.AGE
  FROM EX_TABLE A
  CROSS JOIN JOIN_TABLE B
  ```

  <br>

- #### SELF JOIN

  <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=http%3A%2F%2Fcfile25.uf.tistory.com%2Fimage%2F99341D335A8A363D0614E8">

  자기자신과 자기자신을 조인하는 것이다.

  하나의 테이블을 여러번 복사해서 조인한다고 생각하면 편하다.

  자신이 갖고 있는 칼럼을 다양하게 변형시켜 활용할 때 자주 사용한다.

  ``` sql
  SELECT
  A.NAME, B.AGE
  FROM EX_TABLE A, EX_TABLE B
  ```

  

<br>

<br>

##### [참고]

[링크](<https://coding-factory.tistory.com/87>)

================================================
FILE: Computer Science/Database/저장 프로시저(Stored PROCEDURE).md
================================================
# 저장 프로시저(Stored PROCEDURE)

<br>

```
일련의 쿼리를 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합
```

<br>

데이터베이스에서 SQL을 통해 작업을 하다 보면, 하나의 쿼리문으로 원하는 결과를 얻을 수 없을 때가 생긴다. 원하는 결과물을 얻기 위해 사용할 여러줄의 쿼리문을 한 번의 요청으로 실행하면 좋지 않을까? 또한, 인자 값만 상황에 따라 바뀌고 동일한 로직의 복잡한 쿼리문을 필요할 때마다 작성한다면 비효율적이지 않을까?

이럴 때 사용할 수 있는 것이 바로 프로시저다.

<br>



<img src="https://docs.oracle.com/cd/B13789_01/java.101/b12021/img/call_sto.gif">

<br>

프로시저를 만들어두면, 애플리케이션에서 여러 상황에 따라 해당 쿼리문이 필요할 때 인자 값만 전달하여 쉽게 원하는 결과물을 받아낼 수 있다.

<br>

#### 프로시저 생성 및 호출

```plsql
CREATE OR REPLACE PROCEDURE 프로시저명(변수명1 IN 데이터타입, 변수명2 OUT 데이터타입) -- 인자 값은 필수 아님
IS
[
변수명1 데이터타입;
변수명2 데이터타입;
..
]
BEGIN
 필요한 기능; -- 인자값 활용 가능
END;

EXEC 프로시저명; -- 호출
```

<br>

#### 예시1 (IN)

```plsql
CREATE OR REPLACE PROCEDURE test( name IN VARCHAR2 ) 
IS
	msg VARCHAR2(5) := '내 이름은';
BEGIN 
	dbms_output.put_line(msg||' '||name); 
END;

EXEC test('규글');
```

```
내 이름은 규글
```

<br>

#### 예시2 (OUT)

```plsql
CREATE OR REPLACE PROCEDURE test( name OUT VARCHAR2 ) 
IS
BEGIN 
	name := 'Gyoogle'
END;

DECLARE
out_name VARCHAR2(100);

BEGIN
test(out_name);
dbms_output.put_line('내 이름은 '||out_name);
END;
```

```
내 이름은 Gyoogle
```

<br>

<br>

### 프로시저 장점

---

1. #### 최적화 & 캐시

   프로시저의 최초 실행 시 최적화 상태로 컴파일이 되며, 그 이후 프로시저 캐시에 저장된다.

   만약 해당 프로세스가 여러번 사용될 때, 다시 컴파일 작업을 거치지 않고 캐시에서 가져오게 된다.

2. #### 유지 보수

   작업이 변경될 때, 다른 작업은 건드리지 않고 프로시저 내부에서 수정만 하면 된다.
   (But, 장점이 단점이 될 수도 있는 부분이기도.. )

3. #### 트래픽 감소

   클라이언트가 직접 SQL문을 작성하지 않고, 프로시저명에 매개변수만 담아 전달하면 된다. 즉, SQL문이 서버에 이미 저장되어 있기 때문에 클라이언트와 서버 간 네트워크 상 트래픽이 감소된다.

4. #### 보안

   프로시저 내에서 참조 중인 테이블의 접근을 막을 수 있다.

<br>

### 프로시저 단점

---

1. #### 호환성

   구문 규칙이 SQL / PSM 표준과의 호환성이 낮기 때문에 코드 자산으로의 재사용성이 나쁘다.

2. #### 성능

   문자 또는 숫자 연산에서 프로그래밍 언어인 C나 Java보다 성능이 느리다.

3. #### 디버깅

   에러가 발생했을 때, 어디서 잘못됐는지 디버깅하는 것이 힘들 수 있다.

<br>

<br>

#### [참고 자료]

- [링크](https://ko.wikipedia.org/wiki/%EC%A0%80%EC%9E%A5_%ED%94%84%EB%A1%9C%EC%8B%9C%EC%A0%80)
- [링크](https://itability.tistory.com/51)

================================================
FILE: Computer Science/Database/정규화(Normalization).md
================================================
# 정규화(Normalization)

<br>

```
데이터의 중복을 줄이고, 무결성을 향상시킬 수 있는 정규화에 대해 알아보자
```

<br>

### Normalization

가장 큰 목표는 테이블 간 **중복된 데이터를 허용하지 않는 것**이다.

중복된 데이터를 만들지 않으면, 무결성을 유지할 수 있고, DB 저장 용량 또한 효율적으로 관리할 수 있다.

<br>

### 목적

- 데이터의 중복을 없애면서 불필요한 데이터를 최소화시킨다.
- 무결성을 지키고, 이상 현상을 방지한다.
- 테이블 구성을 논리적이고 직관적으로 할 수 있다.
- 데이터베이스 구조 확장이 용이해진다.

<br>

정규화에는 여러가지 단계가 있지만, 대체적으로 1~3단계 정규화까지의 과정을 거친다.

<br>

### 제 1정규화(1NF)

테이블 컬럼이 원자값(하나의 값)을 갖도록 테이블을 분리시키는 것을 말한다.

만족해야 할 조건은 아래와 같다.

- 어떤 릴레이션에 속한 모든 도메인이 원자값만으로 되어 있어야한다.
- 모든 속성에 반복되는 그룹이 나타나지 않는다.
- 기본키를 사용하여 관련 데이터의 각 집합을 고유하게 식별할 수 있어야 한다.

<br>

<img src="http://dl.dropbox.com/s/9s8vowdzs3t66uw/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202018-12-02%2017.50.02.png">

<br>

현재 테이블은 전화번호를 여러개 가지고 있어 원자값이 아니다. 따라서 1NF에 맞추기 위해서는 아래와 같이 분리할 수 있다.

<br>

<img src="http://dl.dropbox.com/s/1rr8ofxuy46i61b/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202018-12-02%2018.00.52.png">

<br>

<br>

### 제 2정규화(2NF)

테이블의 모든 컬럼이 완전 함수적 종속을 만족해야 한다.

조금 쉽게 말하면, 테이블에서 기본키가 복합키(키1, 키2)로 묶여있을 때, 두 키 중 하나의 키만으로 다른 컬럼을 결정지을 수 있으면 안된다.

> 기본키의 부분집합 키가 결정자가 되어선 안된다는 것

<br>

<img src="http://dl.dropbox.com/s/c2xfxdanbuiaw1l/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202018-12-03%2006.58.17.png">

<br>

`Manufacture`과 `Model`이 키가 되어 `Model Full Name`을 알 수 있다.

`Manufacturer Country`는 `Manufacturer`로 인해 결정된다. (부분 함수 종속)

따라서, `Model`과 `Manufacturer Country`는 아무런 연관관계가 없는 상황이다.

<br>

결국 완전 함수적 종속을 충족시키지 못하고 있는 테이블이다. 부분 함수 종속을 해결하기 위해 테이블을 아래와 같이 나눠서 2NF를 만족할 수 있다.

<br>

<img src="http://dl.dropbox.com/s/x8481598dhnpzeg/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202018-12-03%2010.58.15.png">

<br>

<br>

### 제 3정규화(3NF)

2NF가 진행된 테이블에서 이행적 종속을 없애기 위해 테이블을 분리하는 것이다.

> 이행적 종속 : A → B, B → C면 A → C가 성립된다

아래 두가지 조건을 만족시켜야 한다.

- 릴레이션이 2NF에 만족한다.
- 기본키가 아닌 속성들은 기본키에 의존한다.

<br>

<img src="http://dl.dropbox.com/s/xtfoetv8hg6jn3f/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202018-12-03%2012.59.46.png">

<br>

현재 테이블에서는 `Tournament`와 `Year`이 기본키다.

`Winner`는 이 두 복합키를 통해 결정된다.

하지만 `Winner Date of Birth`는 기본키가 아닌 `Winner`에 의해 결정되고 있다. 

따라서 이는 3NF를 위반하고 있으므로 아래와 같이 분리해야 한다.

<br>

<img src="http://dl.dropbox.com/s/ks03nkc26nsffin/%EC%8A%A4%ED%81%AC%EB%A6%B0%EC%83%B7%202018-12-04%2014.51.39.png">

<br>

<br>

#### [참고 사항]

- [링크](https://wkdtjsgur100.github.io/database-normalization/)


================================================
FILE: Computer Science/Network/DNS.md
================================================
# DNS (Domain Name Server)

모든 통신은 IP를 기반으로 연결된다. 하지만 사용자에게 일일히 IP 주소를 입력하기란 UX적으로 좋지 않다

때문에 DNS 가 등장 했으며 DNS 는 IP 주소와 도메인 주소를 매핑하는 역할을 수행한다

## 도메인 주소가 IP로 변환되는 과정

1. 디바이스는 hosts 파일을 열어 봅니다
   - hosts 파일에는 로컬에서 직접 설정한 호스트 이름과 IP 주소를 매핑 하고 있습니다
2. DNS는 캐시를 확인 합니다
   - 기존에 접속했던 사이트의 경우 캐시에 남아 있을 수 있습니다
   - DNS는 브라우저 캐시, 로컬 캐시(OS 캐시), 라우터 캐시, ISP(Internet Service Provider)캐시 순으로 확인 합니다
3. DNS는 Root DNS에 요청을 보냅니다
   - 모든 DNS에는 Root DNS의 주소가 포함 되어 있습니다
   - 이를 통해 Root DNS에게 질의를 보내게 됩니다
   - Root DNS는 도메인 주소의 최상위 계층을 확인하여 TLD(Top Level DNS)의 주소를 반환 합니다
4. DNS는 TLD에 요청을 보냅니다
   - Root DNS로 부터 반환받은 주소를 통해 요청을 보냅니다
   - TLD는 도메인에 권한이 있는 Authoritative DNS의 주소를 반환 합니다
5. DNS는 Authoritative DNS에 요청을 보냅니다
   - 도메인 이름에 대한 IP 주소를 반환 합니다

- 이때 요청을 보내는 DNS의 경우 재귀적으로 요청을 보내기 때문에 `DNS 리쿼서`라 지칭 하고 요청을 받는 DNS를 `네임서버`라 지칭 합니다


================================================
FILE: Computer Science/Network/HTTP & HTTPS.md
================================================
## HTTP & HTTPS

<br>

- ##### HTTP(HyperText Transfer Protocol)

  인터넷 상에서 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신 규약

<br>

HTTP는 텍스트 교환이므로, 누군가 네트워크에서 신호를 가로채면 내용이 노출되는 보안 이슈가 존재한다.

이런 보안 문제를 해결해주는 프로토콜이 **'HTTPS'**

<br>

#### HTTP의 보안 취약점

1. **도청이 가능하다**

- 평문으로 통신하기 때문에 도청이 가능하다
- 이를 해결하기 위해서 통신자체를암호화(HTTPS)하거나 데이터를 암호화 하는 방법등이 있다
- 데이터를 암호화 하는 경우 수신측에서는 보호화 과정이 필요하다

2. **위장이 가능하다**

- 통신 상대를 확인하지 않기 깨문에 위장된 상대와 통신할 수 있다
- HTTPS는 CA 인증서를 통해 인증된 상대와 통신이 가능하다

3. **변조가 가능하다**

- 완전성을 보장하지 않기 때문에 변조가 가능하다
- HTTPS는 메세지 인증 코드(MAC), 전자 서명등을 통해 변조를 방지 한다

<br>

- ##### HTTPS(HyperText Transfer Protocol Secure)

  인터넷 상에서 정보를 암호화하는 SSL 프로토콜을 사용해 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신 규약

HTTPS는 텍스트를 암호화한다. (공개키 암호화 방식으로!) : [공개키 설명](https://github.com/kim6394/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)

<br>

<br>

#### HTTPS 통신 흐름

1. 애플리케이션 서버(A)를 만드는 기업은 HTTPS를 적용하기 위해 공개키와 개인키를 만든다.

2. 신뢰할 수 있는 CA 기업을 선택하고, 그 기업에게 내 공개키 관리를 부탁하며 계약을 한다.

**_CA란?_** : Certificate Authority로, 공개키를 저장해주는 신뢰성이 검증된 민간기업

3. 계약 완료된 CA 기업은 해당 기업의 이름, A서버 공개키, 공개키 암호화 방법을 담은 인증서를 만들고, 해당 인증서를 CA 기업의 개인키로 암호화해서 A서버에게 제공한다.

4. A서버는 암호화된 인증서를 갖게 되었다. 이제 A서버는 A서버의 공개키로 암호화된 HTTPS 요청이 아닌 요청이 오면, 이 암호화된 인증서를 클라이언트에게 건내준다.

5. 클라이언트가 `main.html` 파일을 달라고 A서버에 요청했다고 가정하자. HTTPS 요청이 아니기 때문에 CA기업이 A서버의 정보를 CA 기업의 개인키로 암호화한 인증서를 받게 된다.

CA 기업의 공개키는 브라우저가 이미 알고있다. (세계적으로 신뢰할 수 있는 기업으로 등록되어 있기 때문에, 브라우저가 인증서를 탐색하여 해독이 가능한 것)

6. 브라우저는 해독한 뒤 A서버의 공개키를 얻게 되었다.

7. 클라이언트가 A서버와 HandShaking 과정에서 주고받은 난수를 조합하여 pre-master-secret-key 를 생성한 뒤, A서버의 공개키로 해당 대칭키를 암호화하여 서버로 보냅니다.

8. A서버는 암호화된 대칭키를 자신의 개인키로 복호화 하여 클라이언트와 동일한 대칭키를 획득합니다.

9. 클라이언트, 서버는 각각 pre-master-secret-key를 master-secret-key으로 만듭니다.

10. master-secret-key 를 통해 session-key를 생성하고 이를 이용하여 대칭키 방식으로 통신합니다.

11. 각 통신이 종료될 때마다 session-key를 파기합니다.

<br>

HTTPS도 무조건 안전한 것은 아니다. (신뢰받는 CA 기업이 아닌 자체 인증서 발급한 경우 등)

이때는 HTTPS지만 브라우저에서 `주의 요함`, `안전하지 않은 사이트`와 같은 알림으로 주의 받게 된다.

<br>

##### [참고사항]

[링크](https://jeong-pro.tistory.com/89)


================================================
FILE: Computer Science/Network/OSI 7 계층.md
================================================
## OSI 7 계층

<br>

<img src="https://s7280.pcdn.co/wp-content/uploads/2018/06/osi-model-7-layers-1.png">

<br>

#### 7계층은 왜 나눌까?

통신이 일어나는 과정을 단계별로 알 수 있고, 특정한 곳에 이상이 생기면 그 단계만 수정할 수 있기 때문이다.

<br>

##### 1) 물리(Physical)

> 리피터, 케이블, 허브 등

단지 데이터를 전기적인 신호로 변환해서 주고받는 기능을 진행하는 공간

즉, 데이터를 전송하는 역할만 진행한다.

<br>

##### 2) 데이터 링크(Data Link)

> 브릿지, 스위치 등

물리 계층으로 송수신되는 정보를 관리하여 안전하게 전달되도록 도와주는 역할

Mac 주소를 통해 통신한다. 프레임에 Mac 주소를 부여하고 에러검출, 재전송, 흐름제어를 진행한다.

<br>

##### 3) 네트워크(Network)

> 라우터, IP

데이터를 목적지까지 가장 안전하고 빠르게 전달하는 기능을 담당한다.

라우터를 통해 이동할 경로를 선택하여 IP 주소를 지정하고, 해당 경로에 따라 패킷을 전달해준다.

라우팅, 흐름 제어, 오류 제어, 세그먼테이션 등을 수행한다.

<br>

##### 4) 전송(Transport)

> TCP, UDP

TCP와 UDP 프로토콜을 통해 통신을 활성화한다. 포트를 열어두고, 프로그램들이 전송을 할 수 있도록 제공해준다.

- TCP : 신뢰성, 연결지향적

- UDP : 비신뢰성, 비연결성, 실시간

<br>

##### 5) 세션(Session)

> API, Socket

데이터가 통신하기 위한 논리적 연결을 담당한다. TCP/IP 세션을 만들고 없애는 책임을 지니고 있다.

<br>

##### 6) 표현(Presentation)

> JPEG, MPEG 등

데이터 표현에 대한 독립성을 제공하고 암호화하는 역할을 담당한다.

파일 인코딩, 명령어를 포장, 압축, 암호화한다.

<br>

##### 7) 응용(Application)

> HTTP, FTP, DNS 등

최종 목적지로, 응용 프로세스와 직접 관계하여 일반적인 응용 서비스를 수행한다.

사용자 인터페이스, 전자우편, 데이터베이스 관리 등의 서비스를 제공한다.


================================================
FILE: Computer Science/Network/TCP (흐름제어혼잡제어).md
================================================




### TCP (흐름제어/혼잡제어)

---

#### 들어가기 전

- TCP 통신이란?
  - 네트워크 통신에서 신뢰적인 연결방식
  - TCP는 기본적으로 unreliable network에서, reliable network를 보장할 수 있도록 하는 프로토콜
  - TCP는 network congestion avoidance algorithm을 사용
- reliable network를 보장한다는 것은 4가지 문제점 존재
  - 손실 : packet이 손실될 수 있는 문제
  - 순서 바뀜 : packet의 순서가 바뀌는 문제
  - Congestion : 네트워크가 혼잡한 문제
  - Overload : receiver가 overload 되는 문제
- 흐름제어/혼잡제어란?
  - 흐름제어 (endsystem 대 endsystem)
    - 송신측과 수신측의 데이터 처리 속도 차이를 해결하기 위한 기법
    - Flow Control은 receiver가 packet을 지나치게 많이 받지 않도록 조절하는 것
    - 기본 개념은 receiver가 sender에게 현재 자신의 상태를 feedback 한다는 점
  - 혼잡제어 : 송신측의 데이터 전달과 네트워크의 데이터 처리 속도 차이를 해결하기 위한 기법
- 전송의 전체 과정
  - 응용 계층(Application Layer)에서 데이터를 전송할 때, 보내는 쪽(sender)의 애플리케이션(Application)은 소켓(Socket)에 데이터를 쓰게 됩니다. 
  - 이 데이터는 전송 계층(Transport Layer)으로 전달되어 세그먼트(Segment)라는 작은 단위로 나누어집니다. 
  - 전송 계층은 이 세그먼트를 네트워크 계층(Network Layer)에 넘겨줍니다.
  - 전송된 데이터는 수신자(receiver) 쪽으로 전달되어, 수신자 쪽에서는 수신 버퍼(Receive Buffer)에 저장됩니다. 
  - 이때, 수신자 쪽에서는 수신 버퍼의 용량을 넘치게 하지 않도록 조절해야 합니다. 
  - 수신자 쪽에서는 자신의 수신 버퍼의 남은 용량을 상대방(sender)에게 알려주는데, 이를 "수신 윈도우(Receive Window)"라고 합니다.
  - 송신자(sender)는 수신자의 수신 윈도우를 확인하여 수신자의 수신 버퍼 용량을 초과하지 않도록 데이터를 전송합니다. 
  - 이를 통해 데이터 전송 중에 수신 버퍼가 넘치는 현상을 방지하면서, 안정적인 데이터 전송을 보장합니다. 이를 "플로우 컨트롤(Flow Control)"이라고 합니다.

따라서, 플로우 컨트롤은 전송 중에 발생하는 수신 버퍼의 오버플로우를 방지하면서, 안정적인 데이터 전송을 위해 중요한 기술입니다.

#### 1. 흐름제어 (Flow Control)

- 수신측이 송신측보다 데이터 처리 속도가 빠르면 문제없지만, 송신측의 속도가 빠를 경우 문제가 생긴다.

- 수신측에서 제한된 저장 용량을 초과한 이후에 도착하는 데이터는 손실 될 수 있으며, 만약 손실 된다면 불필요하게 응답과 데이터 전송이 송/수신 측 간에 빈번히 발생한다.

- 이러한 위험을 줄이기 위해 송신 측의 데이터 전송량을 수신측에 따라 조절해야한다.

- 해결방법

  - Stop and Wait : 매번 전송한 패킷에 대해 확인 응답을 받아야만 그 다음 패킷을 전송하는 방법

    - <img src='https://t1.daumcdn.net/cfile/tistory/263B7D4E5715ECEB32'>

  - Sliding Window (Go Back N ARQ) 

    - 수신측에서 설정한 윈도우 크기만큼 송신측에서 확인응답없이 세그먼트를 전송할 수 있게 하여 데이터 흐름을 동적으로 조절하는 제어기법

    - 목적 : 전송은 되었지만, acked를 받지 못한 byte의 숫자를 파악하기 위해 사용하는 protocol

      LastByteSent - LastByteAcked <= ReceivecWindowAdvertised

      (마지막에 보내진 바이트 - 마지막에 확인된 바이트 <= 남아있는 공간) ==

      (현재 공중에 떠있는 패킷 수 <= sliding window)

  - 동작방식 : 먼저 윈도우에 포함되는 모든 패킷을 전송하고, 그 패킷들의 전달이 확인되는대로 이 윈도우를 옆으로 옮김으로써 그 다음 패킷들을 전송

    - <img src='https://t1.daumcdn.net/cfile/tistory/253F7E485715ED5F27'>

  - Window : TCP/IP를 사용하는 모든 호스트들은 송신하기 위한 것과 수신하기 위한 2개의 Window를 가지고 있다. 호스트들은 실제 데이터를 보내기 전에 '3 way handshaking'을 통해 수신 호스트의 receive window size에 자신의 send window size를 맞추게 된다.

  - 세부구조

    1. 송신 버퍼
       - <img src='https://t1.daumcdn.net/cfile/tistory/22532F485715EDF218'>- 
       - 200 이전의 바이트는 이미 전송되었고, 확인응답을 받은 상태
       - 200 ~ 202 바이트는 전송되었으나 확인응답을 받지 못한 상태
       - 203 ~ 211 바이트는 아직 전송이 되지 않은 상태
    2. 수신 윈도우
       - <img src='https://t1.daumcdn.net/cfile/tistory/25403A485715EE362B'>
    3. 송신 윈도우
       - <img src='https://t1.daumcdn.net/cfile/tistory/2520244B5715EE6A14'>
       - 수신 윈도우보다 작거나 같은 크기로 송신 윈도우를 지정하게되면 흐름제어가 가능하다.
    4. 송신 윈도우 이동
       - <img src='https://t1.daumcdn.net/cfile/tistory/227DC8505715EEBA0A'>
       -  Before : 203 ~ 204를 전송하면 수신측에서는 확인 응답 203을 보내고, 송신측은 이를 받아 after 상태와 같이 수신 윈도우를 203 ~ 209 범위로 이동
       - after : 205 ~ 209가 전송 가능한 상태
    5. Selected Repeat

<br>

#### 2. 혼잡제어 (Congestion Control)

- 송신측의 데이터는 지역망이나 인터넷으로 연결된 대형 네트워크를 통해 전달된다. 만약 한 라우터에 데이터가 몰릴 경우, 자신에게 온 데이터를 모두 처리할 수 없게 된다. 이런 경우 호스트들은 또 다시 재전송을 하게되고 결국 혼잡만 가중시켜 오버플로우나 데이터 손실을 발생시키게 된다. 따라서 이러한 네트워크의 혼잡을 피하기 위해 송신측에서 보내는 데이터의 전송속도를 강제로 줄이게 되는데, 이러한 작업을 혼잡제어라고 한다.
- 또한 네트워크 내에 패킷의 수가 과도하게 증가하는 현상을 혼잡이라 하며, 혼잡 현상을 방지하거나 제거하는 기능을 혼잡제어라고 한다.
- 흐름제어가 송신측과 수신측 사이의 전송속도를 다루는데 반해, 혼잡제어는 호스트와 라우터를 포함한 보다 넓은 관점에서 전송 문제를 다루게 된다.
- 해결 방법
  - <img src='https://t1.daumcdn.net/cfile/tistory/256E39425715F10103'>
  - AIMD(Additive Increase / Multiplicative Decrease)
    - 처음에 패킷을 하나씩 보내고 이것이 문제없이 도착하면 window 크기(단위 시간 내에 보내는 패킷의 수)를 1씩 증가시켜가며 전송하는 방법
    - 패킷 전송에 실패하거나 일정 시간을 넘으면 패킷의 보내는 속도를 절반으로 줄인다.
    - 공평한 방식으로, 여러 호스트가 한 네트워크를 공유하고 있으면 나중에 진입하는 쪽이 처음에는 불리하지만, 시간이 흐르면 평형상태로 수렴하게 되는 특징이 있다.
    - 문제점은 초기에 네트워크의 높은 대역폭을 사용하지 못하여 오랜 시간이 걸리게 되고, 네트워크가 혼잡해지는 상황을 미리 감지하지 못한다. 즉, 네트워크가 혼잡해지고 나서야 대역폭을 줄이는 방식이다.
  - Slow Start (느린 시작)
    - AIMD 방식이 네트워크의 수용량 주변에서는 효율적으로 작동하지만, 처음에 전송 속도를 올리는데 시간이 오래 걸리는 단점이 존재했다.
    - Slow Start 방식은 AIMD와 마찬가지로 패킷을 하나씩 보내면서 시작하고, 패킷이 문제없이 도착하면 각각의 ACK 패킷마다 window size를 1씩 늘려준다. 즉, 한 주기가 지나면 window size가 2배로 된다. 
    - 전송속도는 AIMD에 반해 지수 함수 꼴로 증가한다. 대신에 혼잡 현상이 발생하면 window size를 1로 떨어뜨리게 된다.
    - 처음에는 네트워크의 수용량을 예상할 수 있는 정보가 없지만, 한번 혼잡 현상이 발생하고 나면 네트워크의 수용량을 어느 정도 예상할 수 있다. 
    - 그러므로 혼잡 현상이 발생하였던 window size의 절반까지는 이전처럼 지수 함수 꼴로 창 크기를 증가시키고 그 이후부터는 완만하게 1씩 증가시킨다.
  - Fast Retransmit (빠른 재전송)
    - 빠른 재전송은 TCP의 혼잡 조절에 추가된 정책이다. 
    - 패킷을 받는 쪽에서 먼저 도착해야할 패킷이 도착하지 않고 다음 패킷이 도착한 경우에도 ACK 패킷을 보내게 된다. 
    - 단, 순서대로 잘 도착한 마지막 패킷의 다음 패킷의 순번을 ACK 패킷에 실어서 보내게 되므로, 중간에 하나가 손실되게 되면 송신 측에서는 순번이 중복된 ACK 패킷을 받게 된다. 이것을 감지하는 순간 문제가 되는 순번의 패킷을 재전송 해줄 수 있다.
    - 중복된 순번의 패킷을 3개 받으면 재전송을 하게 된다. 약간 혼잡한 상황이 일어난 것이므로 혼잡을 감지하고 window size를 줄이게 된다.
  - Fast Recovery (빠른 회복)
    - 혼잡한 상태가 되면 window size를 1로 줄이지 않고 반으로 줄이고 선형증가시키는 방법이다. 이 정책까지 적용하면 혼잡 상황을 한번 겪고 나서부터는 순수한 AIMD 방식으로 동작하게 된다.

<br>

[ref]<br>

- <https://www.brianstorti.com/tcp-flow-control/>
- <https://www.brianstorti.com/tcp-flow-control/>



================================================
FILE: Computer Science/Network/TCP 3 way handshake & 4 way handshake.md
================================================
## [TCP] 3 way handshake & 4 way handshake

> 연결을 성립하고 해제하는 과정을 말한다

<br>

### 3 way handshake - 연결 성립

TCP는 정확한 전송을 보장해야 한다. 따라서 통신하기에 앞서, 논리적인 접속을 성립하기 위해 3 way handshake 과정을 진행한다.

<img src="https://media.geeksforgeeks.org/wp-content/uploads/TCP-connection-1.png">

1) 클라이언트가 서버에게 SYN 패킷을 보냄 (sequence : x)

2) 서버가 SYN(x)을 받고, 클라이언트로 받았다는 신호인 ACK와 SYN 패킷을 보냄 (sequence : y, ACK : x + 1)

3) 클라이언트는 서버의 응답은 ACK(x+1)와 SYN(y) 패킷을 받고, ACK(y+1)를 서버로 보냄

<br>

이렇게 3번의 통신이 완료되면 연결이 성립된다. (3번이라 3 way handshake인 것)

<br>

<br>

### 4 way handshake - 연결 해제

연결 성립 후, 모든 통신이 끝났다면 해제해야 한다.

<img src="https://media.geeksforgeeks.org/wp-content/uploads/CN.png">

1) 클라이언트는 서버에게 연결을 종료한다는 FIN 플래그를 보낸다.

2) 서버는 FIN을 받고, 확인했다는 ACK를 클라이언트에게 보낸다. (이때 모든 데이터를 보내기 위해 CLOSE_WAIT 상태가 된다)

3) 데이터를 모두 보냈다면, 연결이 종료되었다는 FIN 플래그를 클라이언트에게 보낸다.

4) 클라이언트는 FIN을 받고, 확인했다는 ACK를 서버에게 보낸다. (아직 서버로부터 받지 못한 데이터가 있을 수 있으므로 TIME_WAIT을 통해 기다린다.)

- 서버는 ACK를 받은 이후 소켓을 닫는다 (Closed)

- TIME_WAIT 시간이 끝나면 클라이언트도 닫는다 (Closed)

<br>

이렇게 4번의 통신이 완료되면 연결이 해제된다.

<br>

<br>

##### [참고 자료]

[링크](<https://www.geeksforgeeks.org/tcp-connection-termination/>)


================================================
FILE: Computer Science/Network/TLS HandShake.md
================================================
# TLS/SSL HandShake

<br>

```
HTTPS에서 클라이언트와 서버간 통신 전
SSL 인증서로 신뢰성 여부를 판단하기 위해 연결하는 방식
```

<br>

![image](https://user-images.githubusercontent.com/34904741/139517776-f2cac636-5ce5-4815-981d-33905283bf13.png)

<br>

### 진행 순서

1. 클라이언트는 서버에게 `client hello` 메시지를 담아 서버로 보낸다.
   이때 암호화된 정보를 함께 담는데, `버전`, `암호 알고리즘`, `압축 방식` 등을 담는다.

   <br>

2. 서버는 클라이언트가 보낸 암호 알고리즘과 압축 방식을 받고, `세션 ID`와 `CA 공개 인증서`를 `server hello` 메시지와 함께 담아 응답한다. 이 CA 인증서에는 앞으로 통신 이후 사용할 대칭키가 생성되기 전, 클라이언트에서 handshake 과정 속 암호화에 사용할 공개키를 담고 있다.

   <br>

3. 클라이언트 측은 서버에서 보낸 CA 인증서에 대해 유효한 지 CA 목록에서 확인하는 과정을 진행한다.

   <br>

4. CA 인증서에 대한 신뢰성이 확보되었다면, 클라이언트는 난수 바이트를 생성하여 서버의 공개키로 암호화한다. 이 난수 바이트는 대칭키를 정하는데 사용이 되고, 앞으로 서로 메시지를 통신할 때 암호화하는데 사용된다.

   <br>

5. 만약 2번 단계에서 서버가 클라이언트 인증서를 함께 요구했다면, 클라이언트의 인증서와 클라이언트의 개인키로 암호화된 임의의 바이트 문자열을 함께 보내준다.

   <br>

6. 서버는 클라이언트의 인증서를 확인 후, 난수 바이트를 자신의 개인키로 복호화 후 대칭 마스터 키 생성에 활용한다.

   <br>

7. 클라이언트는 handshake 과정이 완료되었다는 `finished` 메시지를 서버에 보내면서, 지금까지 보낸 교환 내역들을 해싱 후 그 값을 대칭키로 암호화하여 같이 담아 보내준다.

   <br>

8. 서버도 동일하게 교환 내용들을 해싱한 뒤 클라이언트에서 보내준 값과 일치하는 지 확인한다. 일치하면 서버도 마찬가지로  `finished` 메시지를 이번에 만든 대칭키로 암호화하여 보낸다.

   <br>

9. 클라이언트는 해당 메시지를 대칭키로 복호화하여 서로 통신이 가능한 신뢰받은 사용자란 걸 인지하고, 앞으로 클라이언트와 서버는 해당 대칭키로 데이터를 주고받을 수 있게 된다.

<br>

<br>

#### [참고 자료]

- [링크](https://wangin9.tistory.com/entry/%EB%B8%8C%EB%9D%BC%EC%9A%B0%EC%A0%80%EC%97%90-URL-%EC%9E%85%EB%A0%A5-%ED%9B%84-%EC%9D%BC%EC%96%B4%EB%82%98%EB%8A%94-%EC%9D%BC%EB%93%A4-5TLSSSL-Handshake)

================================================
FILE: Computer Science/Network/UDP.md
================================================
### 2019.08.26.(월) [BYM] UDP란? 

---

#### 들어가기 전

- UDP 통신이란?

  - User Datagram Protocol의 약자로 데이터를 데이터그램 단위로 처리하는 프로토콜이다. 
  - 비연결형, 신뢰성 없는 전송 프로토콜이다.
  - 데이터그램 단위로 쪼개면서 전송을 해야하기 때문에 전송 계층이다.
  - Transport layer에서 사용하는 프로토콜.

- TCP와 UDP는 왜 나오게 됐는가?

  1. IP의 역할은 Host to Host (장치 to 장치)만을 지원한다. 장치에서 장치로 이동은 IP로 해결되지만, 하나의 장비안에서 수많은 프로그램들이 통신을 할 경우에는 IP만으로는 한계가 있다.

  2. 또한, IP에서 오류가 발생한다면 ICMP에서 알려준다. 하지만 ICMP는 알려주기만 할 뿐 대처를 못하기 때문에 IP보다 위에서 처리를 해줘야 한다.

  - 1번을 해결하기 위하여 포트 번호가 나오게 됐고, 2번을 해결하기 위해 상위 프로토콜인 TCP와 UDP가 나오게 되었다.

  * *ICMP : 인터넷 제어 메시지 프로토콜로 네트워크 컴퓨터 위에서 돌아가는 운영체제에서 오류 메시지를 전송받는데 주로 쓰임

- 그렇다면 TCP와 UDP가 어떻게 오류를 해결하는가?

  - TCP : 데이터의 분실, 중복, 순서가 뒤바뀜 등을 자동으로 보정해줘서 송수신 데이터의 정확한 전달을 할 수 있도록 해준다.
  - UDP : IP가 제공하는 정도의 수준만을 제공하는 간단한 IP 상위 계층의 프로토콜이다. TCP와는 다르게 에러가 날 수도 있고, 재전송이나 순서가 뒤바뀔 수도 있어서 이 경우, 어플리케이션에서 처리하는 번거로움이 존재한다.

- UDP는 왜 사용할까?

  - UDP의 결정적인 장점은 데이터의 신속성이다. 데이터의 처리가 TCP보다 빠르다.
  - 주로 실시간 방송과 온라인 게임에서 사용된다. 네트워크 환경이 안 좋을때, 끊기는 현상을 생각하면 된다.

- DNS(Domain Name System)에서 UDP를 사용하는 이유

  - Request의 양이 작음 -> UDP Request에 담길 수 있다.
  - 3 way handshaking으로 연결을 유지할 필요가 없다. (오버헤드 발생)
  - Request에 대한 손실은 Application Layer에서 제어가 가능하다.
  - DNS : port 53번
  - But, TCP를 사용할 때가 있다! 크기가 512(UDP 제한)이 넘을 때, TCP를 사용해야한다. 

<br>

#### 1. UDP Header

- <img src='https://t1.daumcdn.net/cfile/tistory/272A5A385759267B36'>
  - Source port : 시작 포트
  - Destination port : 도착지 포트
  - Length : 길이
  - _Checksum_ : 오류 검출
    - 중복 검사의 한 형태로, 오류 정정을 통해 공간이나 시간 속에서 송신된 자료의 무결성을 보호하는 단순한 방법이다.

<br>

- 이렇게 간단하므로, TCP 보다 용량이 가볍고 송신 속도가 빠르게 작동됨. 

- 그러나 확인 응답을 못하므로, TCP보다 신뢰도가 떨어짐. 
- UDP는 비연결성, TCP는 연결성으로 정의할 수 있음.

<br>

#### DNS과 UDP 통신 프로토콜을 사용함.

DNS는 데이터를 교환하는 경우임

이때, TCP를 사용하게 되면, 데이터를 송신할 때까지 세션 확립을 위한 처리를 하고, 송신한 데이터가 수신되었는지 점검하는 과정이 필요하므로, Protocol overhead가 UDP에 비해서 큼.

------

DNS는 Application layer protocol임.

모든 Application layer protocol은 TCP, UDP 중 하나의 Transport layer protocol을 사용해야 함.

(TCP는 reliable, UDP는 not reliable임) / DNS는 reliable해야할 것 같은데 왜 UDP를 사용할까?



사용하는 이유 

1. TCP가 3-way handshake를 사용하는 반면, UDP는 connection 을 유지할 필요가 없음.

2. DNS request는 UDP segment에 꼭 들어갈 정도로 작음.

   DNS query는 single UDP request와 server로부터의 single UDP reply로 구성되어 있음.

3. UDP는 not reliable이나, reliability는 application layer에 추가될 수 있음.
   (Timeout 추가나, resend 작업을 통해)

DNS는 UDP를 53번 port에서 사용함.

------

그러나 TCP를 사용하는 경우가 있음.

Zone transfer 을 사용해야하는 경우에는 TCP를 사용해야 함.

(Zone Transfer : DNS 서버 간의 요청을 주고 받을 떄 사용하는 transfer)

만약에 데이터가 512 bytes를 넘거나, 응답을 못받은 경우 TCP로 함.

<br>

[ref]<br>

- <https://www.geeksforgeeks.org/why-does-dns-use-udp-and-not-tcp/>
- <https://support.microsoft.com/en-us/help/556000>
- <https://www.scaler.com/topics/domain-name-system/>


================================================
FILE: Computer Science/Network/[Network] Blocking Non-Blocking IO.md
================================================
#### Blocking I/O & Non-Blocking I/O

---

> I/O 작업은 Kernel level에서만 수행할 수 있다. 따라서, Process, Thread는 커널에게 I/O를 요청해야 한다.

<br>

1. #### Blocking I/O

   I/O Blocking 형태의 작업은 

   (1) Process(Thread)가 Kernel에게 I/O를 요청하는 함수를 호출

   (2) Kernel이 작업을 완료하면 작업 결과를 반환 받음.

   

   * 특징
     * I/O 작업이 진행되는 동안 user Process(Thread) 는 자신의 작업을 중단한 채 대기
     * Resource 낭비가 심함 <br>(I/O 작업이 CPU 자원을 거의 쓰지 않으므로)

   <br>

   `여러 Client 가 접속하는 서버를 Blocking 방식으로 구현하는 경우` -> I/O 작업을 진행하는 작업을 중지 -> 다른 Client가 진행중인 작업을 중지하면 안되므로, client 별로 별도의 Thread를 생성해야 함 -> 접속자 수가 매우 많아짐

   이로 인해, 많아진 Threads 로 *컨텍스트 스위칭 횟수가 증가함,,, 비효율적인 동작 방식*

   <br>

2. #### Non-Blocking I/O

   I/O 작업이 진행되는 동안 User Process의 작업을 중단하지 않음. 

   * 진행 순서

     1. User Process가 recvfrom 함수 호출 (커널에게 해당 Socket으로부터 data를 받고 싶다고 요청함)

     2. Kernel은 이 요청에 대해서, 곧바로 recvBuffer를 채워서 보내지 못하므로, "EWOULDBLOCK"을 return함.

     3. Blocking 방식과 달리, User Process는 다른 작업을 진행할 수 있음.

     4. recvBuffer에 user가 받을 수 있는 데이터가 있는 경우, Buffer로부터 데이터를 복사하여 받아옴.

        > 이때, recvBuffer는 Kernel이 가지고 있는 메모리에 적재되어 있으므로, Memory간 복사로 인해, I/O보다 훨씬 빠른 속도로 data를 받아올 수 있음.

     5. recvfrom 함수는 빠른 속도로 data를 복사한 후, 복사한 data의 길이와 함께 반환함.







================================================
FILE: Computer Science/Network/[Network] Blocking,Non-blocking & Synchronous,Asynchronous.md
================================================
# [Network] Blocking/Non-blocking & Synchronous/Asynchronous

<br>

```
동기/비동기는 우리가 일상 생활에서 많이 들을 수 있는 말이다.

Blocking과 Synchronous, 그리고 Non-blocking과 Asysnchronous를
서로 같은 개념이라고 착각하기 쉽다.

각자 어떤 의미를 가지는지 간단하게 살펴보자
```

<br>

<img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fda50Yz%2Fbtq0Dsje4ZV%2FlGe8H8nZgdBdgFvo7IczS0%2Fimg.png">

<br>

[homoefficio](http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/)님 블로그에 나온 2대2 매트릭스로 잘 정리된 사진이다. 이 사진만 보고 모두 이해가 된다면, 차이점에 대해 잘 알고 있는 것이다.

<br>

## Blocking/Non-blocking

블럭/논블럭은 간단히 말해서 `호출된 함수`가 `호출한 함수`에게 제어권을 건네주는 유무의 차이라고 볼 수 있다.

함수 A, B가 있고, A 안에서 B를 호출했다고 가정해보자. 이때 호출한 함수는 A고, 호출된 함수는 B가 된다. 현재 B가 호출되면서 B는 자신의 일을 진행해야 한다. (제어권이 B에게 주어진 상황)

- **Blocking** : 함수 B는 내 할 일을 다 마칠 때까지 제어권을 가지고 있는다. A는 B가 다 마칠 때까지 기다려야 한다.
- **Non-blocking** : 함수 B는 할 일을 마치지 않았어도 A에게 제어권을 바로 넘겨준다. A는 B를 기다리면서도 다른 일을 진행할 수 있다.

즉, 호출된 함수에서 일을 시작할 때 바로 제어권을 리턴해주느냐, 할 일을 마치고 리턴해주느냐에 따라 블럭과 논블럭으로 나누어진다고 볼 수 있다.

<br>

## Synchronous/Asynchronous

동기/비동기는 일을 수행 중인 `동시성`에 주목하자

아까처럼 함수 A와 B라고 똑같이 생각했을 때, B의 수행 결과나 종료 상태를 A가 신경쓰고 있는 유무의 차이라고 생각하면 된다.

- **Synchronous** : 함수 A는 함수 B가 일을 하는 중에 기다리면서, 현재 상태가 어떤지 계속 체크한다. 
- **Asynchronous** : 함수 B의 수행 상태를 B 혼자 직접 신경쓰면서 처리한다. (Callback)

즉, 호출된 함수(B)를 호출한 함수(A)가 신경쓰는지, 호출된 함수(B) 스스로 신경쓰는지를 동기/비동기라고 생각하면 된다.

비동기는 호출시 Callback을 전달하여 작업의 완료 여부를 호출한 함수에게 답하게 된다. (Callback이 오기 전까지 호출한 함수는 신경쓰지 않고 다른 일을 할 수 있음)

<br>

<br>

위 그림처럼 총 4가지의 경우가 나올 수 있다. 이걸 좀 더 이해하기 쉽게 Case 별로 예시를 통해 보면서 이해하고 넘어가보자

<br>

```
상황 : 치킨집에 직접 치킨을 사러감
```

<br>

### 1) Blocking & Synchronous

```
나 : 사장님 치킨 한마리만 포장해주세요
사장님 : 네 금방되니까 잠시만요!
나 : 넹
-- 사장님 치킨 튀기는 중--
나 : (아 언제 되지?..궁금한데 그냥 멀뚱히 서서 치킨 튀기는거 보면서 기다림)
```

<br>

### 2) Blocking & Asynchronous

```
나 : 사장님 치킨 한마리만 포장해주세요
사장님 : 네 금방되니까 잠시만요!
나 : 앗 넹
-- 사장님 치킨 튀기는 중--
나 : (언제 되는지 안 궁금함, 잠시만이래서 다 될때까지 서서 붙잡힌 상황)
```

<br>

### 3) Non-blocking & Synchronous

```
나 : 사장님 치킨 한마리만 포장해주세요
사장님 : 네~ 주문 밀려서 시간 좀 걸리니까 볼일 보시다 오세요
나 : 넹
-- 사장님 치킨 튀기는 중--
(5분뒤) 나 : 제꺼 나왔나요?
사장님 : 아직이요
(10분뒤) 나 : 제꺼 나왔나요?
사장님 : 아직이요ㅠ
(15분뒤) 나 : 제꺼 나왔나요?
사장님 : 아직이요ㅠㅠ
```

<br>

### 4) Non-blocking & Asynchronous

```
나 : 사장님 치킨 한마리만 포장해주세요
사장님 : 네~ 주문 밀려서 시간 좀 걸리니까 볼일 보시다 오세요
나 : 넹
-- 사장님 치킨 튀기는 중--
나 : (앉아서 다른 일 하는 중)
...
사장님 : 치킨 나왔습니다
나 : 잘먹겠습니다~
```

<br>

#### [참고 사항]

- [링크](http://homoefficio.github.io/2017/02/19/Blocking-NonBlocking-Synchronous-Asynchronous/)
- [링크](https://musma.github.io/2019/04/17/blocking-and-synchronous.html)



================================================
FILE: Computer Science/Network/대칭키 & 공개키.md
================================================
## 대칭키 & 공개키

<br>

#### 대칭키(Symmetric Key)

> 암호화와 복호화에 같은 암호키(대칭키)를 사용하는 알고리즘

동일한 키를 주고받기 때문에, 매우 빠르다는 장점이 있음

but, 대칭키 전달과정에서 해킹 위험에 노출

<br>

#### 공개키(Public Key)/비대칭키(Asymmetric Key)

> 암호화와 복호화에 사용하는 암호키를 분리한 알고리즘

대칭키의 키 분배 문제를 해결하기 위해 고안됨.(대칭키일 때는 송수신자 간만 키를 알아야하기 때문에 분배가 복잡하고 어렵지만 공개키와 비밀키로 분리할 경우, 남들이 알아도 되는 공개키만 공개하면 되므로)

자신이 가지고 있는 고유한 암호키(비밀키)로만 복호화할 수 있는 암호키(공개키)를 대중에 공개함

<br>

##### 공개키 암호화 방식 진행 과정

1) A가 웹 상에 공개된 'B의 공개키'를 이용해 평문을 암호화하여 B에게 보냄
2) B는 자신의 비밀키로 복호화한 평문을 확인, A의 공개키로 응답을 암호화하여 A에개 보냄
3) A는 자신의 비밀키로 암호화된 응답문을 복호화함

하지만 이 방식은 Confidentiallity만 보장해줄 뿐, Integrity나 Authenticity는 보장해주지 못함

-> 이는 MAC(Message Authentication Code)나 전자 서명(Digital Signature)으로 해결
(MAC은 공개키 방식이 아니라 대칭키 방식임을 유의! T=MAC(K,M) 형식)

대칭키에 비해 암호화 복호화가 매우 복잡함

(암호화하는 키가 복호화하는 키가 서로 다르기 때문)

<br>

<br>

##### 대칭키와 공개키 암호화 방식을 적절히 혼합해보면? (하이브리드 방식)

> SSL 탄생의 시초가 됨

```
1. A가 B의 공개키로 암호화 통신에 사용할 대칭키를 암호화하고 B에게 보냄
2. B는 암호문을 받고, 자신의 비밀키로 복호화함
3. B는 A로부터 얻은 대칭키로 A에게 보낼 평문을 암호화하여 A에게 보냄
4. A는 자신의 대칭키로 암호문을 복호화함
5. 앞으로 이 대칭키로 암호화를 통신함
```

즉, 대칭키를 주고받을 때만 공개키 암호화 방식을 사용하고 이후에는 계속 대칭키 암호화 방식으로 통신하는 것!

<BR>


================================================
FILE: Computer Science/Network/로드 밸런싱(Load Balancing).md
================================================
## 로드 밸런싱(Load Balancing)

> 둘 이상의 CPU or 저장장치와 같은 컴퓨터 자원들에게 작업을 나누는 것

<br>

<img src="https://www.educative.io/api/collection/5668639101419520/5649050225344512/page/5747976207073280/image/5696459148099584.png">

요즘 시대에는 웹사이트에 접속하는 인원이 급격히 늘어나게 되었다.

따라서 이 사람들에 대해 모든 트래픽을 감당하기엔 1대의 서버로는 부족하다. 대응 방안으로 하드웨어의 성능을 올리거나(Scale-up) 여러대의 서버가 나눠서 일하도록 만드는 것(Scale-out)이 있다. 하드웨어 향상 비용이 더욱 비싸기도 하고, 서버가 여러대면 무중단 서비스를 제공하는 환경 구성이 용이하므로 Scale-out이 효과적이다. 이때 여러 서버에게 균등하게 트래픽을 분산시켜주는 것이 바로 **로드 밸런싱**이다.

<br>

**로드 밸런싱**은 분산식 웹 서비스로, 여러 서버에 부하(Load)를 나누어주는 역할을 한다. Load Balancer를 클라이언트와 서버 사이에 두고, 부하가 일어나지 않도록 여러 서버에 분산시켜주는 방식이다. 서비스를 운영하는 사이트의 규모에 따라 웹 서버를 추가로 증설하면서 로드 밸런서로 관리해주면 웹 서버의 부하를 해결할 수 있다.

<br>

#### 로드 밸런서가 서버를 선택하는 방식

- 라운드 로빈(Round Robin) : CPU 스케줄링의 라운드 로빈 방식 활용
- Least Connections : 연결 개수가 가장 적은 서버 선택 (트래픽으로 인해 세션이 길어지는 경우 권장)
- Source : 사용자 IP를 해싱하여 분배 (특정 사용자가 항상 같은 서버로 연결되는 것 보장)

<br>

#### 로드 밸런서 장애 대비

서버를 분배하는 로드 밸런서에 문제가 생길 수 있기 때문에 로드 밸런서를 이중화하여 대비한다.

> Active 상태와 Passive 상태

<br>

##### [참고자료]

- [링크](<https://www.educative.io/courses/grokking-the-system-design-interview/3jEwl04BL7Q>)

- [링크](<https://nesoy.github.io/articles/2018-06/Load-Balancer>)



================================================
FILE: Computer Science/Operating System/CPU Scheduling.md
================================================
# CPU Scheduling

<br>

### 1. 스케줄링

> CPU 를 잘 사용하기 위해 프로세스를 잘 배정하기

- 조건 : 오버헤드 ↓ / 사용률 ↑ / 기아 현상 ↓
- 목표
    1. `Batch System`: 가능하면 많은 일을 수행. 시간(time) 보단 처리량(throughout)이 중요
    2. `Interactive System`: 빠른 응답 시간. 적은 대기 시간.
    3. `Real-time System`: 기한(deadline) 맞추기.

### 2. 선점 / 비선점 스케줄링

- 선점 (preemptive) : OS가 CPU의 사용권을 선점할 수 있는 경우, 강제 회수하는 경우 (처리시간 예측 어려움)
- 비선점 (nonpreemptive) : 프로세스 종료 or I/O 등의 이벤트가 있을 때까지 실행 보장 (처리시간 예측 용이함)

### 3. 프로세스 상태

![download (5)](https://user-images.githubusercontent.com/13609011/91695344-f2dfae80-eba8-11ea-9a9b-702192316170.jpeg)
- 선점 스케줄링 : `Interrupt`, `I/O or Event Completion`, `I/O or Event Wait`, `Exit`
- 비선점 스케줄링 : `I/O or Event Wait`, `Exit`

---

**프로세스의 상태 전이**

✓ **승인 (Admitted)** : 프로세스 생성이 가능하여 승인됨.

✓ **스케줄러 디스패치 (Scheduler Dispatch)** : 준비 상태에 있는 프로세스 중 하나를 선택하여 실행시키는 것.

✓ **인터럽트 (Interrupt)** : 예외, 입출력, 이벤트 등이 발생하여 현재 실행 중인 프로세스를 준비 상태로 바꾸고, 해당 작업을 먼저 처리하는 것.

✓ **입출력 또는 이벤트 대기 (I/O or Event wait)** : 실행 중인 프로세스가 입출력이나 이벤트를 처리해야 하는 경우, 입출력/이벤트가 모두 끝날 때까지 대기 상태로 만드는 것.

✓ **입출력 또는 이벤트 완료 (I/O or Event Completion)** : 입출력/이벤트가 끝난 프로세스를 준비 상태로 전환하여 스케줄러에 의해 선택될 수 있도록 만드는 것.

### 4. CPU 스케줄링의 종류

- 비선점 스케줄링
    1. FCFS (First Come First Served)
        - 큐에 도착한 순서대로 CPU 할당
        - 실행 시간이 짧은 게 뒤로 가면 평균 대기 시간이 길어짐
    2. SJF (Shortest Job First)
        - 수행시간이 가장 짧다고 판단되는 작업을 먼저 수행
        - FCFS 보다 평균 대기 시간 감소, 짧은 작업에 유리
    3. HRN (Hightest Response-ratio Next)
        - 우선순위를 계산하여 점유 불평등을 보완한 방법(SJF의 단점 보완)
        - 우선순위 = (대기시간 + 실행시간) / (실행시간)

- 선점 스케줄링
    1. Priority Scheduling
        - 정적/동적으로 우선순위를 부여하여 우선순위가 높은 순서대로 처리
        - 우선 순위가 낮은 프로세스가 무한정 기다리는 Starvation 이 생길 수 있음
        - Aging 방법으로 Starvation 문제 해결 가능
    2. Round Robin
        - FCFS에 의해 프로세스들이 보내지면 각 프로세스는 동일한 시간의 `Time Quantum` 만큼 CPU를 할당 받음
            - `Time Quantum` or `Time Slice` : 실행의 최소 단위 시간
        - 할당 시간(`Time Quantum`)이 크면 FCFS와 같게 되고, 작으면 문맥 교환 (Context Switching) 잦아져서 오버헤드 증가
    3. Multilevel-Queue (다단계 큐)
    
        ![Untitled1](https://user-images.githubusercontent.com/13609011/91695428-16a2f480-eba9-11ea-8d91-17d22bab01e5.png)
        - 작업들을 여러 종류의 그룹으로 나누어 여러 개의 큐를 이용하는 기법
        ![Untitled](https://user-images.githubusercontent.com/13609011/91695480-2a4e5b00-eba9-11ea-8dbf-390bf0a73c10.png)

        - 우선순위가 낮은 큐들이 실행 못하는 걸 방지하고자 각 큐마다 다른 `Time Quantum`을 설정 해주는 방식 사용
        - 우선순위가 높은 큐는 작은 `Time Quantum` 할당. 우선순위가 낮은 큐는 큰 `Time Quantum` 할당.
    4. Multilevel-Feedback-Queue (다단계 피드백 큐)

        ![Untitled2](https://user-images.githubusercontent.com/13609011/91695489-2cb0b500-eba9-11ea-8578-6602fee742ed.png)

        - 다단계 큐에서 자신의 `Time Quantum`을 다 채운 프로세스는 밑으로 내려가고 자신의 `Time Quantum`을 다 채우지 못한 프로세스는 원래 큐 그대로
            - Time Quantum을 다 채운 프로세스는 CPU burst 프로세스로 판단하기 때문
        - 짧은 작업에 유리, 입출력 위주(Interrupt가 잦은) 작업에 우선권을 줌
        - 처리 시간이 짧은 프로세스를 먼저 처리하기 때문에 Turnaround 평균 시간을 줄여줌

### 5. CPU 스케줄링 척도

1. Response Time
    - 작업이 처음 실행되기까지 걸린 시간
2. Turnaround Time
    - 실행 시간과 대기 시간을 모두 합한 시간으로 작업이 완료될 때 까지 걸린 시간

---

### 출처

- 스케줄링 목표 : [링크](https://jhnyang.tistory.com/29?category=815411)
- 프로세스 전이도 그림 출처 : [링크](https://rebas.kr/852)
- CPU 스케줄링 종류 및 정의 참고 : [링크](https://m.blog.naver.com/PostView.nhn?blogId=so_fragrant&logNo=80056608452&proxyReferer=https:%2F%2Fwww.google.com%2F)
- 다단계큐 참고 : [링크](https://jhnyang.tistory.com/28)
- 다단계 피드백 큐 참고 : [링크](https://jhnyang.tistory.com/156)


================================================
FILE: Computer Science/Operating System/DeadLock.md
================================================
## 데드락 (DeadLock, 교착 상태)

> 두 개 이상의 프로세스나 스레드가 서로 자원을 얻지 못해서 다음 처리를 하지 못하는 상태
>
> 무한히 다음 자원을 기다리게 되는 상태를 말한다.
>
> 시스템적으로 한정된 자원을 여러 곳에서 사용하려고 할 때 발생한다.

> _(마치, 외나무 다리의 양 끝에서 서로가 비켜주기를 기다리고만 있는 것과 같다.)_

<br>

- 데드락이 일어나는 경우

<img src="https://t1.daumcdn.net/cfile/tistory/243E89355714C26E28">

프로세스1과 2가 자원1, 2를 모두 얻어야 한다고 가정해보자

t1 : 프로세스1이 자원1을 얻음 / 프로세스2가 자원2를 얻음

t2 : 프로세스1은 자원2를 기다림 / 프로세스2는 자원1을 기다림

<br>

현재 서로 원하는 자원이 상대방에 할당되어 있어서 두 프로세스는 무한정 wait 상태에 빠짐

→ 이것이 바로 **DeadLock**!!!!!!

<br>

(주로 발생하는 경우)

> 멀티 프로그래밍 환경에서 한정된 자원을 얻기 위해 서로 경쟁하는 상황 발생
>
> 한 프로세스가 자원을 요청했을 때, 동시에 그 자원을 사용할 수 없는 상황이 발생할 수 있음. 이때 프로세스는 대기 상태로 들어감
>
> 대기 상태로 들어간 프로세스들이 실행 상태로 변경될 수 없을 때 '교착 상태' 발생

<br>

##### _데드락(DeadLock) 발생 조건_

> 4가지 모두 성립해야 데드락 발생
>
> (하나라도 성립하지 않으면 데드락 문제 해결 가능)

1. ##### 상호 배제(Mutual exclusion)

   > 자원은 한번에 한 프로세스만 사용할 수 있음

2. ##### 점유 대기(Hold and wait)

   > 최소한 하나의 자원을 점유하고 있으면서 다른 프로세스에 할당되어 사용하고 있는 자원을 추가로 점유하기 위해 대기하는 프로세스가 존재해야 함

3. ##### 비선점(No preemption)

   > 다른 프로세스에 할당된 자원은 사용이 끝날 때까지 강제로 빼앗을 수 없음

4. ##### 순환 대기(Circular wait)

   > 프로세스의 집합에서 순환 형태로 자원을 대기하고 있어야 함

<br>

##### _데드락(DeadLock) 처리_

---

##### 교착 상태를 예방 & 회피

1. ##### 예방(prevention)

   교착 상태 발생 조건 중 하나를 제거하면서 해결한다 (자원 낭비 엄청 심함)

   > - 상호배제 부정 : 여러 프로세스가 공유 자원 사용
   > - 점유대기 부정 : 프로세스 실행전 모든 자원을 할당
   > - 비선점 부정 : 자원 점유 중인 프로세스가 다른 자원을 요구할 때 가진 자원 반납
   > - 순환대기 부정 : 자원에 고유번호 할당 후 순서대로 자원 요구

2. ##### 회피(avoidance)

   교착 상태 발생 시 피해나가는 방법

   > 은행원 알고리즘(Banker's Algorithm)
   >
   > - 은행에서 모든 고객의 요구가 충족되도록 현금을 할당하는데서 유래함
   > - 프로세스가 자원을 요구할 때, 시스템은 자원을 할당한 후에도 안정 상태로 남아있게 되는지 사전에 검사하여 교착 상태 회피
   > - 안정 상태면 자원 할당, 아니면 다른 프로세스들이 자원 해지까지 대기

   > 자원 할당 그래프 알고리즘(Resource-Allocation Graph Algorithm)
   >
   > - 자원과 프로세스에 대해 요청 간선과 할당 간선을 적용하여 교착 상태를 회피하는 알고리즘
   > - 프로세스가 자원을 요구 시 요청 간선을 할당 간선으로 변경 했을 시 사이클이 생성 되는지 확인한다
   > - 사이클이 생성된다 하여 무조건 교착상태인 것은 아니다
   >   > - 자원에 하나의 인스턴스만 존재 시 **교착 상태**로 판별한다
   >   > - 자원에 여러 인스턴스가 존재 시 **교착 상태 가능성**으로 판별한다
   > - 사이클을 생성하지 않으면 자원을 할당한다

##### 교착 상태를 탐지 & 회복

교착 상태가 되도록 허용한 다음 회복시키는 방법

1. ##### 탐지(Detection)

   자원 할당 그래프를 통해 교착 상태를 탐지함

   자원 요청 시, 탐지 알고리즘을 실행시켜 그에 대한 오버헤드 발생함

2. ##### 회복(Recovery)

   교착 상태 일으킨 프로세스를 종료하거나, 할당된 자원을 해제시켜 회복시키는 방법

   > ##### 프로세스 종료 방법
   >
   > - 교착 상태의 프로세스를 모두 중지
   > - 교착 상태가 제거될 때까지 하나씩 프로세스 중지
   >
   > ##### 자원 선점 방법
   >
   > - 교착 상태의 프로세스가 점유하고 있는 자원을 선점해 다른 프로세스에게 할당 (해당 프로세스 일시정지 시킴)
   > - 우선 순위가 낮은 프로세스나 수행 횟수 적은 프로세스 위주로 프로세스 자원 선점

#### 주요 질문

1. 데드락(교착 상태)가 뭔가요? 발생 조건에 대해 말해보세요.

2. 회피 기법인 은행원 알고리즘이 뭔지 설명해보세요.

3. 기아상태를 설명하는 식사하는 철학자 문제에 대해 설명해보세요.

   > 교착 상태 해결책
   >
   > 1. n명이 앉을 수 있는 테이블에서 철학자를 n-1명만 앉힘
   > 2. 한 철학자가 젓가락 두개를 모두 집을 수 있는 상황에서만 젓가락 집도록 허용
   > 3. 누군가는 왼쪽 젓가락을 먼저 집지 않고 오른쪽 젓가락을 먼저 집도록 허용


================================================
FILE: Computer Science/Operating System/File System.md
================================================
## 파일 시스템(File System)

<br>

컴퓨터에서 파일이나 자료를 쉽게 발견할 수 있도록, 유지 및 관리하는 방법이다.

저장매체에는 수많은 파일이 있기 때문에, 이런 파일들을 관리하는 방법을 말한다.

##### <br>

##### 특징

- 커널 영역에서 동작
- 파일 CRUD 기능을 원활히 수행하기 위한 목적

- 계층적 디렉터리 구조를 가짐
- 디스크 파티션 별로 하나씩 둘 수 있음

##### 역할

- 파일 관리
- 보조 저장소 관리
- 파일 무결성 메커니즘
- 접근 방법 제공

##### 개발 목적

- 하드디스크와 메인 메모리 속도차를 줄이기 위함
- 파일 관리
- 하드디스크 용량 효율적 이용

##### 구조

- 메타 영역 : 데이터 영역에 기록된 파일의 이름, 위치, 크기, 시간정보, 삭제유무 등의 파일 정보
- 데이터 영역 : 파일의 데이터

<br>

<br>

#### 접근 방법

1. ##### 순차 접근(Sequential Access)

   > 가장 간단한 접근 방법으로, 대부분 연산은 read와 write

   <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.1.png">

   현재 위치를 가리키는 포인터에서 시스템 콜이 발생할 경우 포인터를 앞으로 보내면서 read와 write를 진행. 뒤로 돌아갈 땐 지정한 offset만큼 되감기를 해야 한다. (테이프 모델 기반)

2. ##### 직접 접근(Direct Access)

   > 특별한 순서없이, 빠르게 레코드를 read, write 가능

   <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.2.png">

   현재 위치를 가리키는 cp 변수만 유지하면 직접 접근 파일을 가지고 순차 파일 기능을 쉽게 구현이 가능하다.

   무작위 파일 블록에 대한 임의 접근을 허용한다. 따라서 순서의 제약이 없음

   대규모 정보를 접근할 때 유용하기 때문에 '데이터베이스'에 활용된다.

3. 기타 접근

   > 직접 접근 파일에 기반하여 색인 구축

   <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.3.png">

   크기가 큰 파일을 입출력 탐색할 수 있게 도와주는 방법임

<br>

<br>

### 디렉터리와 디스크 구조

---

- ##### 1단계 디렉터리

  > 가장 간단한 구조

  파일들은 서로 유일한 이름을 가짐. 서로 다른 사용자라도 같은 이름 사용 불가

  <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.5.png">

- ##### 2단계 디렉터리

  > 사용자에게 개별적인 디렉터리 만들어줌

  - UFD : 자신만의 사용자 파일 디렉터리
  - MFD : 사용자의 이름과 계정번호로 색인되어 있는 디렉터리

  <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.6.png">

- ##### 트리 구조 디렉터리

  > 2단계 구조 확장된 다단계 트리 구조

  한 비트를 활용하여, 일반 파일(0)인지 디렉터리 파일(1) 구분

  <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.7.png">

- 그래프 구조 디렉터리

  > 순환이 발생하지 않도록 하위 디렉터리가 아닌 파일에 대한 링크만 허용하거나, 가비지 컬렉션을 이용해 전체 파일 시스템을 순회하고 접근 가능한 모든 것을 표시

  링크가 있으면 우회하여 순환을 피할 수 있음

  <img src="https://noep.github.io/2016/02/23/10th-filesystem/10.9.png">













##### [참고 자료]

- [링크]( https://noep.github.io/2016/02/23/10th-filesystem/ )

================================================
FILE: Computer Science/Operating System/IPC(Inter Process Communication).md
================================================
### IPC(Inter Process Communication)

---

<img src="https://t1.daumcdn.net/cfile/tistory/99DB8C495C4C570417">

<br>

프로세스는 독립적으로 실행된다. 즉, 독립 되어있다는 것은 다른 프로세스에게 영향을 받지 않는다고 말할 수 있다. (스레드는 프로세스 안에서 자원을 공유하므로 영향을 받는다)

이런 독립적 구조를 가진 **프로세스 간의 통신**을 해야 하는 상황이 있을 것이다. 이를 가능하도록 해주는 것이 바로 IPC 통신이다.

<br>

프로세스는 커널이 제공하는 IPC 설비를 이용해 프로세스간 통신을 할 수 있게 된다.

***커널이란?***

> 운영체제의 핵심적인 부분으로, 다른 모든 부분에 여러 기본적인 서비스를 제공해줌

<br>

IPC 설비 종류도 여러가지가 있다. 필요에 따라 IPC 설비를 선택해서 사용해야 한다.

<br>

#### IPC 종류

1. ##### 익명 PIPE

   > 파이프는 두 개의 프로세스를 연결하는데 하나의 프로세스는 데이터를 쓰기만 하고, 다른 하나는 데이터를 읽기만 할 수 있다.
   >
   > **한쪽 방향으로만 통신이 가능한 반이중 통신**이라고도 부른다.
   >
   > 따라서 양쪽으로 모두 송/수신을 하고 싶으면 2개의 파이프를 만들어야 한다.
   >
   > 
   >
   >
   > 매우 간단하게 사용할 수 있는 장점이 있고, 단순한 데이터 흐름을 가질 땐 파이프를 사용하는 것이 효율적이다. 단점으로는 전이중 통신을 위해 2개를 만들어야 할 때는 구현이 복잡해지게 된다.

   <br>

2. ##### Named PIPE(FIFO)

   > 익명 파이프는 통신할 프로세스를 명확히 알 수 있는 경우에 사용한다. (부모-자식 프로세스 간 통신처럼)
   >
   > Named 파이프는 전혀 모르는 상태의 프로세스들 사이 통신에 사용한다.
   >
   > 즉, 익명 파이프의 확장된 상태로 **부모 프로세스와 무관한 다른 프로세스도 통신이 가능한 것** (통신을 위해 이름있는 파일을 사용)
   >
   > 
   >
   >
   > 하지만, Named 파이프 역시 읽기/쓰기 동시에 불가능함. 따라서 전이중 통신을 위해서는 익명 파이프처럼 2개를 만들어야 가능

   <br>

3. ##### Message Queue

   > 입출력 방식은 Named 파이프와 동일함
   >
   > 다른점은 메시지 큐는 파이프처럼 데이터의 흐름이 아니라 메모리 공간이다.
   >
   > 
   >
   >
   > 사용할 데이터에 번호를 붙이면서 여러 프로세스가 동시에 데이터를 쉽게 다룰 수 있다.

   <br>

4. ##### 공유 메모리

   > 파이프, 메시지 큐가 통신을 이용한 설비라면, **공유 메모리는 데이터 자체를 공유하도록 지원하는 설비**다.
   > 
   >
   > 프로세스의 메모리 영역은 독립적으로 가지며 다른 프로세스가 접근하지 못하도록 반드시 보호돼야한다. 하지만 다른 프로세스가 데이터를 사용하도록 해야하는 상황도 필요할 것이다. 파이프를 이용해 통신을 통해 데이터 전달도 가능하지만, 스레드처럼 메모리를 공유하도록 해준다면 더욱 편할 것이다.
   > 
   >
   > 공유 메모리는 **프로세스간 메모리 영역을 공유해서 사용할 수 있도록 허용**해준다.
   >
   > 프로세스가 공유 메모리 할당을 커널에 요청하면, 커널은 해당 프로세스에 메모리 공간을 할당해주고 이후 모든 프로세스는 해당 메모리 영역에 접근할 수 있게 된다.
   >
   > - **중개자 없이 곧바로 메모리에 접근할 수 있어서 IPC 중에 가장 빠르게 작동함**

   <br>

5. ##### 메모리 맵

   > 공유 메모리처럼 메모리를 공유해준다. 메모리 맵은 **열린 파일을 메모리에 맵핑시켜서 공유**하는 방식이다. (즉 공유 매개체가 파일+메모리)
   >
   > 주로 파일로 대용량 데이터를 공유해야 할 때 사용한다.

   <br>

6. ##### 소켓

   > 네트워크 소켓 통신을 통해 데이터를 공유한다.
   >
   > 클라이언트와 서버가 소켓을 통해서 통신하는 구조로, 원격에서 프로세스 간 데이터를 공유할 때 사용한다.
   >
   > 서버(bind, listen, accept), 클라이언트(connect)

   <br>



<br>

이러한 IPC 통신에서 프로세스 간 데이터를 동기화하고 보호하기 위해 세마포어와 뮤텍스를 사용한다. (공유된 자원에 한번에 하나의 프로세스만 접근시킬 때)


================================================
FILE: Computer Science/Operating System/Interrupt.md
================================================
## 인터럽트(Interrupt)

##### 정의

프로그램을 실행하는 도중에 예기치 않은 상황이 발생할 경우 현재 실행 중인 작업을 즉시 중단하고, 발생된 상황에 대한 우선 처리가 필요함을 CPU에게 알리는 것
<br>

지금 수행 중인 일보다 더 중요한 일(ex. 입출력, 우선 순위 연산 등)이 발생하면 그 일을 먼저 처리하고 나서 하던 일을 계속해야한다.

<br>

외부/내부 인터럽트는 `CPU의 하드웨어 신호에 의해 발생`

소프트웨어 인터럽트는 `명령어의 수행에 의해 발생`

- ##### 외부 인터럽트

  입출력 장치, 타이밍 장치, 전원 등 외부적인 요인으로 발생

  `전원 이상, 기계 착오, 외부 신호, 입출력`

  <br>

- ##### 내부 인터럽트

  Trap이라고 부르며, 잘못된 명령이나 데이터를 사용할 때 발생

  > 0으로 나누기가 발생, 오버플로우, 명령어를 잘못 사용한 경우 (Exception)

- ##### 소프트웨어 인터럽트

  프로그램 처리 중 명령의 요청에 의해 발생한 것 (SVC 인터럽트)

  > 사용자가 프로그램을 실행시킬 때 발생
  >
  > 소프트웨어 이용 중에 다른 프로세스를 실행시키면 시분할 처리를 위해 자원 할당 동작이 수행된다.

<br>

#### 인터럽트 발생 처리 과정

<img src=" https://mblogthumb-phinf.pstatic.net/20160310_124/scw0531_14575366291105WjS7_PNG/ERTRTETRE.png?type=w2 ">

주 프로그램이 실행되다가 인터럽트가 발생했다.

현재 수행 중인 프로그램을 멈추고, 상태 레지스터와 PC 등을 스택에 잠시 저장한 뒤에 인터럽트 서비스 루틴으로 간다. (잠시 저장하는 이유는, 인터럽트 서비스 루틴이 끝난 뒤 다시 원래 작업으로 돌아와야 하기 때문)

만약 **인터럽트 기능이 없었다면**, 컨트롤러는 특정한 어떤 일을 할 시기를 알기 위해 계속 체크를 해야 한다. (이를 **폴링(Polling)**이라고 한다)

폴링을 하는 시간에는 원래 하던 일에 집중할 수가 없게 되어 많은 기능을 제대로 수행하지 못하는 단점이 있었다.

<br>

즉, 컨트롤러가 입력을 받아들이는 방법(우선순위 판별방법)에는 두가지가 있다.

- ##### 폴링 방식

  사용자가 명령어를 사용해 입력 핀의 값을 계속 읽어 변화를 알아내는 방식

  인터럽트 요청 플래그를 차례로 비교하여 우선순위가 가장 높은 인터럽트 자원을 찾아 이에 맞는 인터럽트 서비스 루틴을 수행한다. (하드웨어에 비해 속도 느림)

- ##### 인터럽트 방식

  MCU 자체가 하드웨어적으로 변화를 체크하여 변화 시에만 일정한 동작을 하는 방식

  - Daisy Chain
  - 병렬 우선순위 부여 

<br>

인터럽트 방식은 하드웨어로 지원을 받아야 하는 제약이 있지만, 폴링에 비해 신속하게 대응하는 것이 가능하다. 따라서 **'실시간 대응'**이 필요할 때는 필수적인 기능이다.

<br>

즉, 인터럽트는 **발생시기를 예측하기 힘든 경우에 컨트롤러가 가장 빠르게 대응할 수 있는 방법**이다.



================================================
FILE: Computer Science/Operating System/Memory.md
================================================
#### 메인 메모리(main memory)

> 메인 메모리는 CPU가 직접 접근할 수 있는 기억 장치
>
> 프로세스가 실행되려면 프로그램이 메모리에 올라와야 함

주소가 할당된 일련의 바이트들로 구성되어 있음

<br>

CPU는 레지스터가 지시하는대로 메모리에 접근하여 다음에 수행할 명령어를 가져옴

명령어 수행 시 메모리에 필요한 데이터가 없으면 해당 데이터를 우선 가져와야 함

이 역할을 하는 것이 바로 **MMU**.

<br>

#### MMU (Memory Management Unit, 메모리 관리 장치)

- 논리 주소를 물리 주소로 변환해 준다.

- 메모리 보호나 캐시 관리 등 CPU가 메모리에 접근하는 것을 총 관리해 주는 하드웨어임

<br>

메모리의 공간이 한정적이기 때문에, 사용자에게 더 많은 메모리를 제공하기 위해 '가상 주소'라는 개념이 등장 (가상 주소는 프로그램 상에서 사용자가 보는 주소 공간이라고 보면 됨)

이 가상 주소에서 실제 데이터가 담겨 있는 곳에 접근하기 위해선 빠른 주소 변환이 필요한데, 이를 MMU가 도와주는 것

즉, MMU의 역할은 다음과 같다고 말할 수 있다.

> MMU가 지원되지 않으면, physical address를 직접 접근해야 하기 때문에 부담이 있다.
>
> MMU는 사용자가 기억장소를 일일이 할당해야 하는 불편을 없애준다.
>
> 프로세스의 크기가 실제 메모리의 용량을 초과해도 실행될 수 있게 해준다.

<br>

또한 메인 메모리의 직접 접근은 비효율적이므로, CPU와 메인 메모리 속도를 맞추기 위해 캐시가 존재함

<br>

##### MMU의 메모리 보호

프로세스는 독립적인 메모리 공간을 가져야 되고, 자신의 공간만 접근해야 함

따라서 한 프로세스에게 합법적인 주소 영역을 설정하고, 잘못된 접근이 오면 trap을 발생시키며 보호함

<img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory&fname=https%3A%2F%2Fk.kakaocdn.net%2Fdn%2F5Lgut%2FbtquNvKMRwH%2FJOqzcmz8wiXf0Kv7okfGzK%2Fimg.png">

base와 limit 레지스터를 활용한 메모리 보호 기법

base 레지스터는 메모리상의 프로세스 시작주소를 물리 주소로 저장
limit 레지스터는 프로세스의 사이즈를 저장

이로써 프로세스의 접근 가능한 합법적인 메모리 영역(x)은

```
base <= x < base+limit
```

이 영역 밖에서 접근을 요구하면 trap을 발생시키는 것

<br>

안전성을 위해 base와 limit 레지스터는 커널 모드에서만 수정 가능하도록 설계 (사용자 모드에서는 직접 변경할 수 없도록)

<br>

<br>

##### 메모리 과할당(over allocating)

> 실제 메모리의 사이즈보다 더 큰 사이즈의 메모리를 프로세스에 할당한 상황

<br>

페이지 기법과 같은 메모리 관리 기법은 사용자가 눈치채지 못하도록 눈속임을 통해 메모리를 할당해 줌 (가상 메모리를 이용해서)

<br>

과할당 상황에 대해서 사용자를 속인 것을 들킬만한 상황이 존재함

1. 프로세스 실행 도중 페이지 폴트 발생
2. 페이지 폴트를 발생시킨 페이지 위치를 디스크에서 찾음
3. 메모리의 빈 프레임에 페이지를 올려야 하는데, 모든 메모리가 사용 중이라 빈 프레임이 없음

<br>

이러한 과할당을 해결하기 위해선, 빈 프레임을 확보할 수 있어야 함

1. 메모리에 올라와 있는 한 프로세스를 종료시켜 빈 프레임을 얻음

2. 프로세스 하나를 swap out하고, 이 공간을 빈 프레임으로 활용

<br>

swapping 기법을 통해 공간을 바꿔치기하는 2번 방법과는 달리 1번은 사용자에게 페이징 시스템을 들킬 가능성이 매우 높아서 하면 안 됨

(페이징 기법은 사용자 모르게 시스템 능률을 높이기 위해 선택한 일이므로 들키지 않게 처리해야 한다)

<br>

따라서, 2번과 같은 해결책을 통해 페이지 교체가 이루어져야 함

<br>

<br>

#####  페이지 교체

> 메모리 과할당이 발생했을 때, 프로세스 하나를 swap out해서 빈 프레임을 확보하는 것

<br>

1. 프로세스 실행 도중 페이지 부재 발생

2. 페이지 폴트를 발생시킨 페이지 위치를 디스크에서 찾음

3. 메모리에 빈 프레임이 있는지 확인

   > 빈 프레임이 있으면 해당 프레임을 사용
   >
   > 빈 프레임이 없으면, victim 프레임을 선정해 디스크에 기록하고 페이지 테이블을 업데이트함

4. 빈 프레임에 페이지 폴트가 발생한 페이지를 올리고, 페이지 테이블 업데이트

<br>

페이지 교체가 이루어지면 아무 일이 없던 것 처럼 프로세스를 계속 수행시켜주면서 사용자가 알지 못하도록 해야 함

이때, 아무 일도 일어나지 않은 것처럼 하려면, 페이지 교체 당시 오버헤드를 최대한 줄여야 함

<br>

##### 오버헤드를 감소시키는 해결법

이처럼 빈 프레임이 없는 상황에서 victim 프레임을 비울 때와 원하는 페이지를 프레임으로 올릴 때 두 번의 디스크 접근이 이루어짐

페이지 교체가 많이 이루어지면, 이처럼 입출력 연산이 많이 발생하게 되면서 오버헤드 문제가 발생함

<br>

##### 방법1

변경비트를 모든 페이지마다 둬서, victim 페이지가 정해지면 해당 페이지의 비트를 확인

해당 비트가 set 상태면? → 해당 페이지 내용이 디스크 상의 페이지 내용과 달라졌다는 뜻
(즉, 페이지가 메모리 올라온 이후 한 번이라도 수정이 일어났던 것. 따라서 이건 디스크에 기록해야 함)

bit가 clear 상태라면? → 디스크 상의 페이지 내용과 메모리 상의 페이지가 정확히 일치하는 상황
(즉, 디스크와 내용이 같아서 기록할 필요가 없음)

비트를 활용해  디스크에 기록하는 횟수를 줄이면서 오버헤드에 대한 수를 최대 절반으로 감소시키는 방법임

<br>

##### 방법2

페이지 교체 알고리즘을 상황에 따라 잘 선택해야 함

현재 상황에서 페이지 폴트를 발생할 확률을 최대한 줄여줄 수 있는 교체 알고리즘을 사용

FIFO

OPT

LRU

<br>

<br>

#### 캐시 메모리

> 주기억장치에 저장된 내용의 일부를 임시로 저장해두는 기억장치
>
> CPU와 주기억장치의 속도 차이로 성능 저하를 방지하기 위한 방법

CPU가 이미 봤던걸 다시 재접근할 때, 메모리 참조 및 인출 과정에 대한 비용을 줄이기 위해 캐시에 저장해둔 데이터를 활용한다

캐시는 플리플롭 소자로 구성되어 SRAM으로 되어있어서 DRAM보다 빠른 장점을 지님

<br>

##### CPU와 기억장치의 상호작용

CPU에서 주소를 전달 → 캐시 기억장치에 명령이 존재하는지 확인

(존재) Hit

해당 명령어를 CPU로 전송 → 완료

(비존재) Miss

명령어를 갖고 주기억장치로 접근 → 해당 명령어를 가진 데이터 인출 → 해당 명령어 데이터를 캐시에 저장 → 해당 명령어를 CPU로 전송 → 완료

<br>

이처럼 캐시를 잘 활용한다면 비용을 많이 줄일 수 있음

따라서 CPU가 어떤 데이터를 원할지 어느 정도 예측할 수 있어야 함

(캐시에 많이 활용되는 쓸모 있는 정보가 들어있어야 성능이 높아짐)

<br>

적중률을 극대화시키기 위해 사용되는 것이 바로 `지역성의 원리`

##### 지역성

> 기억 장치 내의 정보를 균일하게 액세스 하는 것이 아니라 한 순간에 특정부분을 집중적으로 참조하는 특성

<br>

지역성의 종류는 시간과 공간으로 나누어짐

**시간 지역성** : 최근에 참조된 주소의 내용은 곧 다음에도 참조되는 특성

**공간 지역성** : 실제 프로그램이 참조된 주소와 인접한 주소의 내용이 다시 참조되는 특성

<br>

<br>

#### 캐싱 라인

빈번하게 사용되는 데이터들을 캐시에 저장했더라도, 내가 필요한 데이터를 캐시에서 찾을 때 모든 데이터를 순회하는 것은 시간 낭비다.

즉, 캐시에 목적 데이터가 저장되어 있을 때 바로 접근하여 출력할 수 있어야 캐시 활용이 의미 있어짐

따라서 캐시에 데이터를 저장할 시, 자료구조를 활용해 묶어서 저장하는데 이를 `캐싱 라인`이라고 부른다.

즉, 캐시에 저장하는 데이터에 데이터의 메모리 주소를 함께 저장하면서 빠르게 원하는 정보를 찾을 수 있음 (set이나 map 등을 활용)


================================================
FILE: Computer Science/Operating System/Operation System.md
================================================
## 운영 체제란 무엇인가?

> **운영 체제(OS, Operating System)**
>
> : 하드웨어를 관리하고, 컴퓨터 시스템의 자원들을 효율적으로 관리하며, 응용 프로그램과 하드웨어 간의 인터페이스로써 다른 응용 프로그램이 유용한 작업을 할 수 있도록 환경을 제공해준다.
>
> 즉, 운영 체제는 **사용자가 컴퓨터를 편리하고 효과적으로 사용할 수 있도록 환경을 제공하는 시스템 소프트웨어**라고 할 수 있다.
>
> (*종류로는 Windows, Linux, UNIX, MS-DOS 등이 있으며, 시스템의 역할 구분에 따라 각각 용이점이 있다.*)

<br>

---

### [ 운영체제의 역할 ]

<br>

##### 1. 프로세스 관리

- 프로세스, 스레드
- 스케줄링
- 동기화
- IPC 통신

##### 2. 저장장치 관리

- 메모리 관리
- 가상 메모리
- 파일 시스템

##### 3. 네트워킹

- TCP/IP
- 기타 프로토콜

##### 4. 사용자 관리

- 계정 관리
- 접근권한 관리

##### 5. 디바이스 드라이버

- 순차접근 장치
- 임의접근 장치
- 네트워크 장치

<br>

---

### [ 각 역할에 대한 자세한 설명 ]

<br>

### 1. 프로세스 관리

운영체제에서 작동하는 응용 프로그램을 관리하는 기능이다.

어떤 의미에서는 프로세서(CPU) 관리하는 것이라고 볼 수도 있다. 현재 CPU를 점유해야 할 프로세스를 결정하고, 실제로 CPU를 프로세스에 할당하며, 이 프로세스 간 공유 자원 접근과 통신 등을 관리하게 된다.

<br>

### 2. 저장장치 관리

1차 저장장치에 해당하는 메인 메모리와 2차 저장장치에 해당하는 하드디스크, NAND 등을 관리하는 기능이다.

- 1차 저장장치(Main Memory)
  - 프로세스에 할당하는 메모리 영역의 할당과 해제
  - 각 메모리 영역 간의 침범 방지
  - 메인 메모리의 효율적 활용을 위한 가상 메모리 기능
- 2차 저장장치(HDD, NAND Flash Memory 등)
  - 파일 형식의 데이터 저장
  - 이런 파일 데이터 관리를 위한 파일 시스템을 OS에서 관리
  - `FAT, NTFS, EXT2, JFS, XFS` 등 많은 파일 시스템들이 개발되어 사용 중
  <br>
### 3. 네트워킹

네트워킹은 컴퓨터 활용의 핵심과도 같아졌다.

TCP/IP 기반의 인터넷에 연결하거나, 응용 프로그램이 네트워크를 사용하려면 **운영체제에서 네트워크 프로토콜을 지원**해야 한다. 현재 상용 OS들은 다양하고 많은 네트워크 프로토콜을 지원한다.

이처럼 운영체제는 사용자와 컴퓨터 하드웨어 사이에 위치해서, 하드웨어를 운영 및 관리하고 명령어를 제어하여 응용 프로그램 및 하드웨어를 소프트웨어적으로 제어 및 관리를 해야한다.
<br>
### 4. 사용자 관리

우리가 사용하는 PC는 오직 한 사람만의 것일까? 아니다.

하나의 PC로도 여러 사람이 사용하는 경우가 많다. 그래서 운영체제는 한 컴퓨터를 여러 사람이 사용하는 환경도 지원해야 한다. 가족들이 각자의 계정을 만들어 PC를 사용한다면, 이는 하나의 컴퓨터를 여러 명이 사용한다고 말할 수 있다.

따라서, 운영체제는 각 계정을 관리할 수 있는 기능이 필요하다. 사용자 별로 프라이버시와 보안을 위해 개인 파일에 대해선 다른 사용자가 접근할 수 없도록 해야 한다. 이 밖에도 파일이나 시스템 자원에 접근 권한을 지정할 수 있도록 지원하는 것이 사용자 관리 기능이다.
<br>
### 5. 디바이스 드라이버

운영체제는 시스템의 자원, 하드웨어를 관리한다. 시스템에는 여러 하드웨어가 붙어있는데, 이들을 운영체제에서 인식하고 관리하게 만들어 응용 프로그램이 하드웨어를 사용할 수 있게 만들어야 한다.

따라서, 운영체제 안에 하드웨어를 추상화 해주는 계층이 필요하다. 이 계층이 바로 디바이스 드라이버라고 불린다. 하드웨어의 종류가 많은 만큼, 운영체제 내부의 디바이스 드라이버도 많이 존재한다.

이러한 수많은 디바이스 드라이버들을 관리하는 기능 또한 운영체제가 맡고 있다.

---

<br>

##### [참고 자료 및 주제와 관련하여 참고하면 좋은 곳 링크]

- 도서 - '도전 임베디드 OS 만들기' *( 이만우 저, 인사이트 출판 )*
- 글 - '운영체제란 무엇인가?' *( https://coding-factory.tistory.com/300 )*

================================================
FILE: Computer Science/Operating System/PCB & Context Switcing.md
================================================
## PCB & Context Switching

<br>

#### Process Management

> CPU가 프로세스가 여러개일 때, CPU 스케줄링을 통해 관리하는 것을 말함

이때, CPU는 각 프로세스들이 누군지 알아야 관리가 가능함

프로세스들의 특징을 갖고있는 것이 바로 `Process Metadata`

- Process Metadata
  - Process ID
  - Process State
  - Process Priority
  - CPU Registers
  - Owner
  - CPU Usage
  - Memeory Usage

이 메타데이터는 프로세스가 생성되면 `PCB(Process Control Block)`이라는 곳에 저장됨

<br>

#### PCB(Process Control Block)

> 프로세스 메타데이터들을 저장해 놓는 곳, 한 PCB 안에는 한 프로세스의 정보가 담김

<img src="https://t1.daumcdn.net/cfile/tistory/25673A5058F211C224" width="400">

##### 다시 정리해보면?

```
프로그램 실행 → 프로세스 생성 → 프로세스 주소 공간에 (코드, 데이터, 스택) 생성 
→ 이 프로세스의 메타데이터들이 PCB에 저장
```

<br>

##### PCB가 왜 필요한가요?

> CPU에서는 프로세스의 상태에 따라 교체작업이 이루어진다. (interrupt가 발생해서 할당받은 프로세스가 waiting 상태가 되고 다른 프로세스를 running으로 바꿔 올릴 때)
>
> 이때, **앞으로 다시 수행할 대기 중인 프로세스에 관한 저장 값을 PCB에 저장해두는 것**이다.

##### PCB는 어떻게 관리되나요?

> Linked List 방식으로 관리함
>
> PCB List Head에 PCB들이 생성될 때마다 붙게 된다. 주소값으로 연결이 이루어져 있는 연결리스트이기 때문에 삽입 삭제가 용이함.
>
> 즉, 프로세스가 생성되면 해당 PCB가 생성되고 프로세스 완료시 제거됨

<br>

<br>

이렇게 수행 중인 프로세스를 변경할 때, CPU의 레지스터 정보가 변경되는 것을 `Context Switching`이라고 한다.

#### Context Switching

> CPU가 이전의 프로세스 상태를 PCB에 보관하고, 또 다른 프로세스의 정보를 PCB에 읽어 레지스터에 적재하는 과정

보통 인터럽트가 발생하거나, 실행 중인 CPU 사용 허가시간을 모두 소모하거나, 입출력을 위해 대기해야 하는 경우에 Context Switching이 발생

`즉, 프로세스가 Ready → Running, Running → Ready, Running → Waiting처럼 상태 변경 시 발생!` 

<br>

##### Context Switching의 OverHead란?

overhead는 과부하라는 뜻으로 보통 안좋은 말로 많이 쓰인다.

하지만 프로세스 작업 중에는 OverHead를 감수해야 하는 상황이 있다.

```
프로세스를 수행하다가 입출력 이벤트가 발생해서 대기 상태로 전환시킴
이때, CPU를 그냥 놀게 놔두는 것보다 다른 프로세스를 수행시키는 것이 효율적
```

즉, CPU에 계속 프로세스를 수행시키도록 하기 위해서 다른 프로세스를 실행시키고 Context Switching 하는 것

CPU가 놀지 않도록 만들고, 사용자에게 빠르게 일처리를 제공해주기 위한 것이다.


================================================
FILE: Computer Science/Operating System/Page Replacement Algorithm.md
================================================
### 페이지 교체 알고리즘

---

> 페이지 부재 발생 → 새로운 페이지를 할당해야 함 → 현재 할당된 페이지 중 어떤 것 교체할 지 결정하는 방법

<br>

- 좀 더 자세하게 생각해보면?

가상 메모리는 `요구 페이지 기법`을 통해 필요한 페이지만 메모리에 적재하고 사용하지 않는 부분은 그대로 둠

하지만 필요한 페이지만 올려도 메모리는 결국 가득 차게 되고, 올라와있던 페이지가 사용이 다 된 후에도 자리만 차지하고 있을 수 있음

따라서 메모리가 가득 차면, 추가로 페이지를 가져오기 위해서 안쓰는 페이지는 out하고, 해당 공간에 현재 필요한 페이지를 in 시켜야 함

여기서 어떤 페이지를 out 시켜야할 지 정해야 함. (이때 out 되는 페이지를 victim page라고 부름) 

기왕이면 수정이 되지 않는 페이지를 선택해야 좋음
(Why? : 만약 수정되면 메인 메모리에서 내보낼 때, 하드디스크에서 또 수정을 진행해야 하므로 시간이 오래 걸림)

> 이와 같은 상황에서 상황에 맞는 페이지 교체를 진행하기 위해 페이지 교체 알고리즘이 존재하는 것!

<br>

##### Page Reference String

> CPU는 논리 주소를 통해 특정 주소를 요구함
>
> 메인 메모리에 올라와 있는 주소들은 페이지의 단위로 가져오기 때문에 페이지 번호가 연속되어 나타나게 되면 페이지 결함 발생 X
>
> 따라서 CPU의 주소 요구에 따라 페이지 결함이 일어나지 않는 부분은 생략하여 표시하는 방법이 바로 `Page Reference String`

<br>

1. ##### FIFO 알고리즘

   > First-in First-out, 메모리에 먼저 올라온 페이지를 먼저 내보내는 알고리즘

   victim page : out 되는 페이지는, 가장 먼저 메모리에 올라온 페이지

   가장 간단한 방법으로, 특히 초기화 코드에서 적절한 방법임

   `초기화 코드` : 처음 프로세스 실행될 때 최초 초기화를 시키는 역할만 진행하고 다른 역할은 수행하지 않으므로, 메인 메모리에서 빼도 괜찮음

   하지만 처음 프로세스 실행시에는 무조건 필요한 코드이므로, FIFO 알고리즘을 사용하면 초기화를 시켜준 후 가장 먼저 내보내는 것이 가능함

   

   <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory&fname=https%3A%2F%2Fk.kakaocdn.net%2Fdn%2FVQCGK%2FbtquJuqRkyS%2FLb3NgwHkBve08YhZpLkq31%2Fimg.png">

<br>

<br>

2. ##### OPT 알고리즘

   > Optimal Page Replacement 알고리즘, 앞으로 가장 사용하지 않을 페이지를 가장 우선적으로 내보냄

   FIFO에 비해 페이지 결함의 횟수를 많이 감소시킬 수 있음

   하지만, 실질적으로 페이지가 앞으로 잘 사용되지 않을 것이라는 보장이 없기 때문에 수행하기 어려운 알고리즘임

   <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory&fname=https%3A%2F%2Fk.kakaocdn.net%2Fdn%2FSvRs7%2FbtquHbeJLQX%2FWXmK7xdGUbIxl43t0JG6Qk%2Fimg.png">

<br>

3. ##### LRU 알고리즘

   > Least-Recently-Used, 최근에 사용하지 않은 페이지를 가장 먼저 내려보내는 알고리즘

   최근에 사용하지 않았으면, 나중에도 사용되지 않을 것이라는 아이디어에서 나옴

   OPT의 경우 미래 예측이지만, LRU의 경우는 과거를 보고 판단하므로 실질적으로 사용이 가능한 알고리즘

   (실제로도 최근에 사용하지 않은 페이지는 앞으로도 사용하지 않을 확률이 높다)

   OPT보다는 페이지 결함이 더 일어날 수 있지만, **실제로 사용할 수 있는 페이지 교체 알고리즘에서는 가장 좋은 방법 중 하나임**

   <img src="https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory&fname=https%3A%2F%2Fk.kakaocdn.net%2Fdn%2FnCgc3%2FbtquGW9VUrm%2FxTKnVKPOVQuSXmAuRehSw1%2Fimg.png">



##### 교체 방식

- Global 교체

  > 메모리 상의 모든 프로세스 페이지에 대해 교체하는 방식

- Local 교체

  > 메모리 상의 자기 프로세스 페이지에서만 교체하는 방식



다중 프로그래밍의 경우, 메인 메모리에 다양한 프로세스가 동시에 올라올 수 있음

따라서, 다양한 프로세스의 페이지가 메모리에 존재함

페이지 교체 시, 다양한 페이지 교체 알고리즘을 활용해 victim page를 선정하는데, 선정 기준을 Global로 하느냐, Local로 하느냐에 대한 차이

→ 실제로는 전체를 기준으로 페이지를 교체하는 것이 더 효율적이라고 함. 자기 프로세스 페이지에서만 교체를 하면, 교체를 해야할 때 각각 모두 교체를 진행해야 하므로 비효율적


================================================
FILE: Computer Science/Operating System/Paging and Segmentation.md
================================================
### 페이징과 세그먼테이션

---

##### 기법을 쓰는 이유

> 다중 프로그래밍 시스템에 여러 프로세스를 수용하기 위해 주기억장치를 동적 분할하는 메모리 관리 작업이 필요해서

<br>

#### 메모리 관리 기법

1. 연속 메모리 관리

   > 프로그램 전체가 하나의 커다란 공간에 연속적으로 할당되어야 함

   - 고정 분할 기법 : 주기억장치가 고정된 파티션으로 분할 (**내부 단편화 발생**)
   - 동적 분할 기법 : 파티션들이 동적 생성되며 자신의 크기와 같은 파티션에 적재 (**외부 단편화 발생**)

   <br>

2. 불연속 메모리 관리

   > 프로그램의 일부가 서로 다른 주소 공간에 할당될 수 있는 기법

   페이지 : 고정 사이즈의 작은 프로세스 조각

   프레임 : 페이지 크기와 같은 주기억장치 메모리 조각

   단편화 : 기억 장치의 빈 공간 or 자료가 여러 조각으로 나뉘는 현상

   세그먼트 : 서로 다른 크기를 가진 논리적 블록이 연속적 공간에 배치되는 것
   <br>

   **고정 크기** : 페이징(Paging)

   **가변 크기** : 세그먼테이션(Segmentation)
   <br>

   - 단순 페이징

     > 각 프로세스는 프레임들과 같은 길이를 가진 균등 페이지로 나뉨
     >
     > 외부 단편화 X
     >
     > 소량의 내부 단편화 존재

   - 단순 세그먼테이션

     > 각 프로세스는 여러 세그먼트들로 나뉨
     >
     > 내부 단편화 X, 메모리 사용 효율 개선, 동적 분할을 통한 오버헤드 감소
     >
     > 외부 단편화 존재

   - 가상 메모리 페이징

     > 단순 페이징과 비교해 프로세스 페이지 전부를 로드시킬 필요X
     >
     > 필요한 페이지가 있으면 나중에 자동으로 불러들어짐
     >
     > 외부 단편화 X
     >
     > 복잡한 메모리 관리로 오버헤드 발생

   - 가상 메모리 세그먼테이션

     > 필요하지 않은 세그먼트들은 로드되지 않음
     >
     > 필요한 세그먼트 있을때 나중에 자동으로 불러들어짐
     >
     > 내부 단편화X
     >
     > 복잡한 메모리 관리로 오버헤드 발생



================================================
FILE: Computer Science/Operating System/Process Address Space.md
================================================
## 프로세스의 주소 공간

> 프로그램이 CPU에 의해 실행됨 → 프로세스가 생성되고 메모리에 '**프로세스 주소 공간**'이 할당됨

프로세스 주소 공간에는 코드, 데이터, 스택으로 이루어져 있다.

- **코드 Segment** : 프로그램 소스 코드 저장
- **데이터 Segment** : 전역 변수 저장
- **스택 Segment** : 함수, 지역 변수 저장

<br>

***왜 이렇게 구역을 나눈건가요?***

최대한 데이터를 공유하여 메모리 사용량을 줄여야 합니다. 

Code는 같은 프로그램 자체에서는 모두 같은 내용이기 때문에 따로 관리하여 공유함

Stack과 데이터를 나눈 이유는, 스택 구조의 특성과 전역 변수의 활용성을 위한 것!

<br>

<img src="https://t1.daumcdn.net/cfile/tistory/2174013858F1BED70A">

```
프로그램의 함수와 지역 변수는, LIFO(가장 나중에 들어간게 먼저 나옴)특성을 가진 스택에서 실행된다. 
따라서 이 함수들 안에서 공통으로 사용하는 '전역 변수'는 따로 지정해주면 메모리를 아낄 수 있다.
```


================================================
FILE: Computer Science/Operating System/Process Management & PCB.md
================================================
## PCB & Context Switching

<br>

#### Process Management

> CPU가 프로세스가 여러개일 때, CPU 스케줄링을 통해 관리하는 것을 말함

이때, CPU는 각 프로세스들이 누군지 알아야 관리가 가능함

프로세스들의 특징을 갖고있는 것이 바로 `Process Metadata`

- Process Metadata
  - Process ID
  - Process State
  - Process Priority
  - CPU Registers
  - Owner
  - CPU Usage
  - Memeory Usage

이 메타데이터는 프로세스가 생성되면 `PCB(Process Control Block)`이라는 곳에 저장됨

<br>

#### PCB(Process Control Block)

> 프로세스 메타데이터들을 저장해 놓는 곳, 한 PCB 안에는 한 프로세스의 정보가 담김

<img src="https://t1.daumcdn.net/cfile/tistory/25673A5058F211C224" width="400">

##### 다시 정리해보면?

```
프로그램 실행 → 프로세스 생성 → 프로세스 주소 공간에 (코드, 데이터, 스택) 생성 
→ 이 프로세스의 메타데이터들이 PCB에 저장
```

<br>

##### PCB가 왜 필요한가요?

> CPU에서는 프로세스의 상태에 따라 교체작업이 이루어진다. (interrupt가 발생해서 할당받은 프로세스가 wating 상태가 되고 다른 프로세스를 running으로 바꿔 올릴 때)
>
> 이때, **앞으로 다시 수행할 대기 중인 프로세스에 관한 저장 값을 PCB에 저장해두는 것**이다.

##### PCB는 어떻게 관리되나요?

> Linked List 방식으로 관리함
>
> PCB List Head에 PCB들이 생성될 때마다 붙게 된다. 주소값으로 연결이 이루어져 있는 연결리스트이기 때문에 삽입 삭제가 용이함.
>
> 즉, 프로세스가 생성되면 해당 PCB가 생성되고 프로세스 완료시 제거됨

<br>

<br>

이렇게 수행 중인 프로세스를 변경할 때, CPU의 레지스터 정보가 변경되는 것을 `Context Switching`이라고 한다.

#### Context Switching

> CPU가 이전의 프로세스 상태를 PCB에 보관하고, 또 다른 프로세스의 정보를 PCB에 읽어 레지스터에 적재하는 과정

보통 인터럽트가 발생하거나, 실행 중인 CPU 사용 허가시간을 모두 소모하거나, 입출랙을 위해 대기해야 하는 경우에 Context Switching이 발생

`즉, 프로세스가 Ready → Running, Running → Ready, Running → Waiting처럼 상태 변경 시 발생!` 

<br>

##### Context Switching의 OverHead란?

overhead는 과부하라는 뜻으로 보통 안좋은 말로 많이 쓰인다.

하지만 프로세스 작업 중에는 OverHead를 감수해야 하는 상황이 있다.

```
프로세스를 수행하다가 입출력 이벤트가 발생해서 대기 상태로 전환시킴
이때, CPU를 그냥 놀게 놔두는 것보다 다른 프로세스를 수행시키는 것이 효율적
```

즉, CPU에 계속 프로세스를 수행시키도록 하기 위해서 다른 프로세스를 실행시키고 Context Switching 하는 것

CPU가 놀지 않도록 만들고, 사용자에게 빠르게 일처리를 제공해주기 위한 것이다.

================================================
FILE: Computer Science/Operating System/Process vs Thread.md
================================================
# 프로세스 & 스레드

<br>

> **프로세스** : 프로그램을 메모리 상에서 실행중인 작업
>
> **스레드** : 프로세스 안에서 실행되는 여러 흐름 단위

<br>

기본적으로 프로세스마다 최소 1개의 스레드 소유 (메인 스레드 포함)

<br>

![img](https://camo.githubusercontent.com/3dc4ad61f03160c310a855a4bd68a9f2a2c9a4c7/68747470733a2f2f74312e6461756d63646e2e6e65742f6366696c652f746973746f72792f393938383931343635433637433330363036)

프로세스는 각각 별도의 주소공간 할당 (독립적)

- Code : 코드 자체를 구성하는 메모리 영역(프로그램 명령)

- Data : 전역변수, 정적변수, 배열 등
  - 초기화 된 데이터는 data 영역에 저장
  - 초기화 되지 않은 데이터는 bss 영역에 저장
- Heap : 동적 할당 시 사용 (new(), malloc() 등)

- Stack : 지역변수, 매개변수, 리턴 값 (임시 메모리 영역)

<br>

스레드는 Stack만 따로 할당 받고 나머지 영역은 서로 공유

- Stack 영역만 따로 할당 받는 이유
  - 쓰레드는 독립적인 동작을 수행하기 위해 존재 한다
  - 즉 독립적으로 함수를 호출 할 수 있어야 한다
  - 때문에 함수의 매개변수, 지역변수등을 저장하는 스택 메모리 영역은 독립적으로 할당 받아야 한다

<br>

하나의 프로세스가 생성될 때, 기본적으로 하나의 스레드 같이 생성

<br>

**프로세스는 자신만의 고유 공간과 자원을 할당받아 사용**하는데 반해, **스레드는 다른 스레드와 공간, 자원을 공유하면서 사용**하는 차이가 존재함

<br>

<br>

##### 멀티프로세스

> 하나의 프로그램을 여러개의 프로세스로 구성하여 각 프로세스가 병렬적으로 작업을 수행하는 것

**장점** : 안전성 (메모리 침범 문제를 OS 차원에서 해결)

**단점** : 각각 독립된 메모리 영역을 갖고 있어, 작업량 많을 수록 오버헤드 발생. Context Switching으로 인한 성능 저하

<br>

***Context Switching*이란?**

> 프로세스의 상태 정보를 저장하고 복원하는 일련의 과정
>
> 즉, 동작 중인 프로세스가 대기하면서 해당 프로세스의 상태를 보관하고, 대기하고 있던 다음 순번의 프로세스가 동작하면서 이전에 보관했던 프로세스 상태를 복구하는 과정을 말함
>
> → 프로세스는 각 독립된 메모리 영역을 할당받아 사용되므로, 캐시 메모리 초기화와 같은 무거운 작업이 진행되었을 때 오버헤드가 발생할 문제가 존재함

<br>

<br>

##### 멀티 스레드

> 하나의 응용 프로그램에서 여러 스레드를 구성해 각 스레드가 하나의 작업을 처리하는 것

스레드들이 공유 메모리를 통해 다수의 작업을 동시에 처리하도록 해줌

<br>

**장점** : 독립적인 프로세스에 비해 공유 메모리만큼의 시간, 자원 손실이 감소
전역 변수와 정적 변수에 대한 자료 공유 가능

**단점** : 안전성 문제. 하나의 스레드가 데이터 공간 망가뜨리면, 모든 스레드가 작동 불능 상태 (공유 메모리를 갖기 때문)

- 멀티스레드의 안전성에 대한 단점은 Critical Section 기법을 통해 대비함

  > 하나의 스레드가 공유 데이터 값을 변경하는 시점에 다른 스레드가 그 값을 읽으려할 때 발생하는 문제를 해결하기 위한 동기화 과정
  >
  > ```
  > 상호 배제, 진행, 한정된 대기를 충족해야함
  > ```


================================================
FILE: Computer Science/Operating System/Race Condition.md
================================================
## [OS] Race Condition

공유 자원에 대해 여러 프로세스가 동시에 접근할 때, 결과값에 영향을 줄 수 있는 상태

> 동시 접근 시 자료의 일관성을 해치는 결과가 나타남

<br>

#### Race Condition이 발생하는 경우

1. ##### 커널 작업을 수행하는 중에 인터럽트 발생

   - 문제점 : 커널모드에서 데이터를 로드하여 작업을 수행하다가 인터럽트가 발생하여 같은 데이터를 조작하는 경우
   - 해결법 : 커널모드에서 작업을 수행하는 동안, 인터럽트를 disable 시켜 CPU 제어권을 가져가지 못하도록 한다.

2. ##### 프로세스가 'System Call'을 하여 커널 모드로 진입하여 작업을 수행하는 도중 문맥 교환이 발생할 때

   - 문제점 : 프로세스1이 커널모드에서 데이터를 조작하는 도중, 시간이 초과되어 CPU 제어권이 프로세스2로 넘어가 같은 데이터를 조작하는 경우 ( 프로세스2가 작업에 반영되지 않음 )
   - 해결법 : 프로세스가 커널모드에서 작업을 하는 경우 시간이 초과되어도 CPU 제어권이 다른 프로세스에게 넘어가지 않도록 함

3. ##### 멀티 프로세서 환경에서 공유 메모리 내의 커널 데이터에 접근할 때

   - 문제점 : 멀티 프로세서 환경에서 2개의 CPU가 동시에 커널 내부의 공유 데이터에 접근하여 조작하는 경우
   - 해결법 : 커널 내부에 있는 각 공유 데이터에 접근할 때마다, 그 데이터에 대한 lock/unlock을 하는 방법

   



================================================
FILE: Computer Science/Operating System/Semaphore & Mutex.md
================================================
## 세마포어(Semaphore) & 뮤텍스(Mutex)

<br>

공유된 자원에 여러 프로세스가 동시에 접근하면서 문제가 발생할 수 있다. 이때 공유된 자원의 데이터는 한 번에 하나의 프로세스만 접근할 수 있도록 제한을 둬야 한다.

이를 위해 나온 것이 바로 **'세마포어'**

**세마포어** : 멀티프로그래밍 환경에서 공유 자원에 대한 접근을 제한하는 방법

<br>

##### 임계 구역(Critical Section)

> 여러 프로세스가 데이터를 공유하며 수행될 때, **각 프로세스에서 공유 데이터를 접근하는 프로그램 코드 부분**

공유 데이터를 여러 프로세스가 동시에 접근할 때 잘못된 결과를 만들 수 있기 때문에, 한 프로세스가 임계 구역을 수행할 때는 다른 프로세스가 접근하지 못하도록 해야 한다.

<br>

#### 세마포어 P, V 연산

P : 임계 구역 들어가기 전에 수행 ( 프로세스 진입 여부를 자원의 개수(S)를 통해 결정)

V : 임계 구역에서 나올 때 수행 ( 자원 반납 알림, 대기 중인 프로세스를 깨우는 신호 )

<br>

##### 구현 방법

```sql
P(S);

// --- 임계 구역 ---

V(S);
```

<br>

```sql
procedure P(S)   --> 최초 S값은 1임
    while S=0 do wait  --> S가 0면 1이 될때까지 기다려야 함
    S := S-1   --> S를 0로 만들어 다른 프로세스가 들어 오지 못하도록 함
end P

--- 임계 구역 ---

procedure V(S) --> 현재상태는 S가 0임
    S := S+1   --> S를 1로 원위치시켜 해제하는 과정
end V
```

이를 통해, 한 프로세스가 P 혹은 V를 수행하고 있는 동안 프로세스가 인터럽트 당하지 않게 된다. P와 V를 사용하여 임계 구역에 대한 상호배제 구현이 가능하게 되었다.

***예시***

> 최초 S 값은 1이고, 현재 해당 구역을 수행할 프로세스 A, B가 있다고 가정하자

1. 먼저 도착한 A가 P(S)를 실행하여 S를 0으로 만들고 임계구역에 들어감
2. 그 뒤에 도착한 B가 P(S)를 실행하지만 S가 0이므로 대기 상태
3. A가 임계구역 수행을 마치고 V(S)를 실행하면 S는 다시 1이 됨
4. B는 이제 P(S)에서 while문을 빠져나올 수 있고, 임계구역으로 들어가 수행함

<br>

<br>

**뮤텍스** : 임계 구역을 가진 스레드들의 실행시간이 서로 겹치지 않고 각각 단독으로 실행되게 하는 기술

> 상호 배제(**Mut**ual **Ex**clusion)의 약자임

해당 접근을 조율하기 위해 lock과 unlock을 사용한다.

- lock : 현재 임계 구역에 들어갈 권한을 얻어옴 ( 만약 다른 프로세스/스레드가 임계 구역 수행 중이면 종료할 때까지 대기 )
- unlock : 현재 임계 구역을 모두 사용했음을 알림. ( 대기 중인 다른 프로세스/스레드가 임계 구역에 진입할 수 있음 )

<br>

뮤텍스는 상태가 0, 1로 **이진 세마포어**로 부르기도 함

<br>

#### **뮤텍스 알고리즘**

1. ##### 데커(Dekker) 알고리즘

   flag와 turn 변수를 통해 임계 구역에 들어갈 프로세스/스레드를 결정하는 방식

   - flag : 프로세스 중 누가 임계영역에 진입할 것인지 나타내는 변수
   - turn : 누가 임계구역에 들어갈 차례인지 나타내는 변수

   ```java
   while(true) {
       flag[i] = true; // 프로세스 i가 임계 구역 진입 시도
       while(flag[j]) { // 프로세스 j가 현재 임계 구역에 있는지 확인
           if(turn == j) { // j가 임계 구역 사용 중이면
               flag[i] = false; // 프로세스 i 진입 취소
               while(turn == j); // turn이 j에서 변경될 때까지 대기
               flag[i] = true; // j turn이 끝나면 다시 진입 시도
           }
       }
   }
   
   // ------- 임계 구역 ---------
   
   turn = j; // 임계 구역 사용 끝나면 turn을 넘김
   flag[i] = false; // flag 값을 false로 바꿔 임계 구역 사용 완료를 알림
   ```

   <br>

2. ##### 피터슨(Peterson) 알고리즘

   데커와 유사하지만, 상대방 프로세스/스레드에게 진입 기회를 양보하는 것에 차이가 있음

   ```java
   while(true) {
       flag[i] = true; // 프로세스 i가 임계 구역 진입 시도
       turn = j; // 다른 프로세스에게 진입 기회 양보
       while(flag[j] && turn == j) { // 다른 프로세스가 진입 시도하면 대기
       }
   }
   
   // ------- 임계 구역 ---------
   
   flag[i] = false; // flag 값을 false로 바꿔 임계 구역 사용 완료를 알림
   ```

   <br>

3. ##### 제과점(Bakery) 알고리즘

   여러 프로세스/스레드에 대한 처리가 가능한 알고리즘. 가장 작은 수의 번호표를 가지고 있는 프로세스가 임계 구역에 진입한다.

   ```java
   while(true) {
       
       isReady[i] = true; // 번호표 받을 준비
       number[i] = max(number[0~n-1]) + 1; // 현재 실행 중인 프로세스 중에 가장 큰 번호 배정 
       isReady[i] = false; // 번호표 수령 완료
       
       for(j = 0; j < n; j++) { // 모든 프로세스 번호표 비교
           while(isReady[j]); // 비교 프로세스가 번호표 받을 때까지 대기
           while(number[j] && number[j] < number[i] && j < i);
           
           // 프로세스 j가 번호표 가지고 있어야 함
           // 프로세스 j의 번호표 < 프로세스 i의 번호표
       }
   
       // ------- 임계 구역 ---------
   
       number[i] = 0; // 임계 구역 사용 종료
   }
   ```

   


================================================
FILE: Computer Science/Operating System/[OS] System Call (Fork Wait Exec).md
================================================
#### [Operating System] System Call

---

fork( ), exec( ), wait( )와 같은 것들은 Process 생성과 제어를 위한 System call임.

- fork, exec는 새로운 Process 생성과 관련이 되어 있다.
- wait는 Process (Parent)가 만든 다른 Process(child) 가 끝날 때까지 기다리는 명령어임.

---

##### Fork

> 새로운 Process를 생성할 때 사용.
>
> 그러나, 이상한 방식임.

```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {					    // (1) fork 실패
        exit(1);
    }
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
    }
    else {								// (3) parent case
        printf("parent of %d (pid : %d)", rc, (int)getpid());
    }
}
```

> pid : 29146
>
> parent of 29147 (pid : 29146)
>
> child (pid : 29147)

을 출력함 (parent와 child의 순서는 non-deterministic함. 즉, 확신할 수 없음. scheduler가 결정하는 일임.)

[해석]

PID :  프로세스 식별자. UNIX 시스템에서는 PID는 프로세스에게 명령을 할 때 사용함.

Fork()가 실행되는 순간. 프로세스가 하나 더 생기는데, 이 때 생긴 프로세스(Child)는 fork를 만든 프로세스(Parent)와 (almost) 동일한 복사본을 갖게 된다. **<u>이 때 OS는 위와 똑같은 2개의 프로그램이 동작한다고 생각하고, fork()가 return될 차례라고 생각한다.</u>** 그 때문에 새로 생성된 Process (child)는 main에서 시작하지 않고, if 문부터 시작하게 된다.

그러나, 차이점이 있었다. 바로 child와 parent의 fork() 값이 다르다는 점이다.
 따라서, 완전히 동일한 복사본이라 할 수 없다. 

> Parent의 fork()값 => child의 pid 값
>
> Child의 fork()값 => 0

Parent와 child의 fork 값이 다르다는 점은 매우 유용한 방식이다.

그러나! Scheduler가 부모를 먼저 수행할지 아닐지 확신할 수 없다. 따라서 아래와 같이 출력될 수 있다.

> pid : 29146
>
> child (pid : 29147)
>
> parent of 29147 (pid : 29146)

----

##### wait

> child 프로세스가 종료될 때까지 기다리는 작업

위의 예시에 int wc = wait(NULL)만 추가함.

```C
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {					    // (1) fork 실패
        exit(1);
    }
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
    }
    else {								// (3) parent case
        int wc = wait(NULL)				// 추가된 부분
        printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
    }
}
```

> pid : 29146
>
> child (pid : 29147)
>
> parent of 29147 (wc : 29147 / pid : 29146)

wait를 통해서, child의 실행이 끝날 때까지 기다려줌. parent가 먼저 실행되더라도, wait ()는 child가 끝나기 전에는 return하지 않으므로, 반드시 child가 먼저 실행됨.

----

##### exec

단순 fork는 동일한 프로세스의 내용을 여러 번 동작할 때 사용함.

child에서는 parent와 다른 동작을 하고 싶을 때는 exec를 사용할 수 있음.

```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

int main(int argc, char *argv[]) {
    printf("pid : %d", (int) getpid()); // pid : 29146
    
    int rc = fork();					// 주목
    
    if (rc < 0) {					    // (1) fork 실패
        exit(1);
    }
    else if (rc == 0) {					// (2) child 인 경우 (fork 값이 0)
        printf("child (pid : %d)", (int) getpid());
        char *myargs[3];
        myargs[0] = strdup("wc");		// 내가 실행할 파일 이름
        myargs[1] = strdup("p3.c");		// 실행할 파일에 넘겨줄 argument
        myargs[2] = NULL;				// end of array
        execvp(myarges[0], myargs);		// wc 파일 실행.
        printf("this shouldn't print out") // 실행되지 않음.
    }
    else {								// (3) parent case
        int wc = wait(NULL)				// 추가된 부분
        printf("parent of %d (wc : %d / pid : %d)", wc, rc, (int)getpid());
    }
}
```

exec가 실행되면, 

execvp( 실행 파일, 전달 인자 ) 함수는, code segment 영역에 실행 파일의 코드를 읽어와서 덮어 씌운다.

씌운 이후에는,  heap, stack, 다른 메모리 영역이 초기화되고, OS는 그냥 실행한다. 즉, 새로운 Process를 생성하지 않고, 현재 프로그램에 wc라는 파일을 실행한다. 그로인해서, execvp() 이후의 부분은 실행되지 않는다.


================================================
FILE: Computer Science/Software Engineering/Clean Code & Refactoring.md
================================================
## 클린코드와 리팩토링

<br>

클린코드와 리팩토링은 의미만 보면 비슷하다고 느껴진다. 어떤 차이점이 있을지 생각해보자

<br>

#### 클린코드

클린코드란, 가독성이 높은 코드를 말한다.

가독성을 높이려면 다음과 같이 구현해야 한다.

- 네이밍이 잘 되어야 함
- 오류가 없어야 함
- 중복이 없어야 함
- 의존성을 최대한 줄여야 함
- 클래스 혹은 메소드가 한가지 일만 처리해야 함

<br>

얼마나 **코드가 잘 읽히는 지, 코드가 지저분하지 않고 정리된 코드인지**를 나타내는 것이 바로 '클린 코드'

```java
public int AAA(int a, int b){
    return a+b;
}
public int BBB(int a, int b){
    return a-b;
}
```

<br>

두 가지 문제점이 있다.

<br>

```java
public int sum(int a, int b){
    return a+b;
}

public int sub(int a, int b){
    return a-b;
}
```

첫째는 **함수 네이밍**이다. 다른 사람들이 봐도 무슨 역할을 하는 함수인 지 알 수 있는 이름을 사용해야 한다.

둘째는 **함수와 함수 사이의 간격**이다. 여러 함수가 존재할 때 간격을 나누지 않으면 시작과 끝을 구분하는 것이 매우 힘들다.

<br>

<br>

#### 리팩토링

프로그램의 외부 동작은 그대로 둔 채, 내부의 코드를 정리하면서 개선하는 것을 말함

```
이미 공사가 끝난 집이지만, 더 튼튼하고 멋진 집을 만들기 위해 내부 구조를 개선하는 리모델링 작업
```

<br>

프로젝트가 끝나면, 지저분한 코드를 볼 때 가독성이 떨어지는 부분이 존재한다. 이 부분을 개선시키기 위해 필요한 것이 바로 '리팩토링 기법'

리팩토링 작업은 코드의 가독성을 높이고, 향후 이루어질 유지보수에 큰 도움이 된다.

<br>

##### 리팩토
Download .txt
gitextract_nbg_fwwo/

├── .github/
│   └── FUNDING.yml
├── Algorithm/
│   ├── Binary Search.md
│   ├── DFS & BFS.md
│   ├── Hash Table 구현하기.md
│   ├── HeapSort.md
│   ├── LCA(Lowest Common Ancestor).md
│   ├── LIS (Longest Increasing Sequence).md
│   ├── MergeSort.md
│   ├── QuickSort.md
│   ├── README.md
│   ├── SAMSUNG Software PRO등급 준비.md
│   ├── Sort_Counting.md
│   ├── Sort_Radix.md
│   ├── code/
│   │   ├── Heap.java
│   │   ├── InsertionSort.java
│   │   ├── QuickSort.java
│   │   ├── bubbleSort.java
│   │   └── mergeSort.java
│   ├── professional/
│   │   └── 프로 준비법.md
│   ├── 간단하지만 알면 좋은 최적화들.md
│   ├── 다익스트라(Dijkstra).md
│   ├── 동적 계획법 (Dynamic Programming).md
│   ├── 비트마스크(BitMask).md
│   ├── 순열 & 조합.md
│   └── 최대공약수 & 최소공배수.md
├── Computer Science/
│   ├── Computer Architecture/
│   │   ├── ARM 프로세서.md
│   │   ├── 고정 소수점 & 부동 소수점.md
│   │   ├── 명령어 Cycle.md
│   │   ├── 중앙처리장치(CPU) 작동 원리.md
│   │   ├── 캐시 메모리(Cache Memory).md
│   │   ├── 컴퓨터의 구성.md
│   │   └── 패리티 비트 & 해밍 코드.md
│   ├── Data Structure/
│   │   ├── Array vs ArrayList vs LinkedList.md
│   │   ├── Array.md
│   │   ├── B Tree & B+ Tree.md
│   │   ├── Binary Search Tree.md
│   │   ├── Hash.md
│   │   ├── Heap.md
│   │   ├── Linked List.md
│   │   ├── README.md
│   │   ├── Stack & Queue.md
│   │   ├── Tree.md
│   │   ├── Trie.md
│   │   └── code/
│   │       ├── MaxHeap.java
│   │       ├── MinHeap.java
│   │       ├── binarySearchTree.java
│   │       ├── juggling_array.cpp
│   │       ├── linked_list.java
│   │       ├── linked_list_push.java
│   │       ├── maxvalue_array.cpp
│   │       ├── rearrange_array.cpp
│   │       ├── reversal_array.cpp
│   │       └── rotate_array.cpp
│   ├── Database/
│   │   ├── Redis.md
│   │   ├── SQL Injection.md
│   │   ├── SQL과 NOSQL의 차이.md
│   │   ├── Transaction Isolation Level.md
│   │   ├── Transaction.md
│   │   ├── [DB] Anomaly.md
│   │   ├── [DB] Index.md
│   │   ├── [DB] Key.md
│   │   ├── [Database SQL] JOIN.md
│   │   ├── 저장 프로시저(Stored PROCEDURE).md
│   │   └── 정규화(Normalization).md
│   ├── Network/
│   │   ├── DNS.md
│   │   ├── HTTP & HTTPS.md
│   │   ├── OSI 7 계층.md
│   │   ├── TCP (흐름제어혼잡제어).md
│   │   ├── TCP 3 way handshake & 4 way handshake.md
│   │   ├── TLS HandShake.md
│   │   ├── UDP.md
│   │   ├── [Network] Blocking Non-Blocking IO.md
│   │   ├── [Network] Blocking,Non-blocking & Synchronous,Asynchronous.md
│   │   ├── 대칭키 & 공개키.md
│   │   └── 로드 밸런싱(Load Balancing).md
│   ├── Operating System/
│   │   ├── CPU Scheduling.md
│   │   ├── DeadLock.md
│   │   ├── File System.md
│   │   ├── IPC(Inter Process Communication).md
│   │   ├── Interrupt.md
│   │   ├── Memory.md
│   │   ├── Operation System.md
│   │   ├── PCB & Context Switcing.md
│   │   ├── Page Replacement Algorithm.md
│   │   ├── Paging and Segmentation.md
│   │   ├── Process Address Space.md
│   │   ├── Process Management & PCB.md
│   │   ├── Process vs Thread.md
│   │   ├── Race Condition.md
│   │   ├── Semaphore & Mutex.md
│   │   └── [OS] System Call (Fork Wait Exec).md
│   └── Software Engineering/
│       ├── Clean Code & Refactoring.md
│       ├── Fuctional Programming.md
│       ├── Object-Oriented Programming.md
│       ├── TDD(Test Driven Development).md
│       ├── 데브옵스(DevOps).md
│       ├── 마이크로서비스 아키텍처(MSA).md
│       ├── 써드파티(3rd party)란.md
│       ├── 애자일(Agile).md
│       ├── 애자일(Agile)2.md
│       └── 클린코드(Clean Code) & 시큐어코딩(Secure Coding).md
├── Design Pattern/
│   ├── Adapter Pattern.md
│   ├── Composite Pattern.md
│   ├── Design Pattern_Adapter.md
│   ├── Design Pattern_Factory Method.md
│   ├── Design Pattern_Template Method.md
│   ├── Observer pattern.md
│   ├── SOLID.md
│   ├── Singleton Pattern.md
│   ├── Strategy Pattern.md
│   ├── Template Method Pattern.md
│   └── [Design Pattern] Overview.md
├── ETC/
│   ├── Collaborate with Git on Javascript and Node.js.md
│   ├── Git Commit Message Convention.md
│   ├── Git vs GitHub vs GitLab Flow.md
│   ├── GitHub Fork로 협업하기.md
│   ├── GitHub 저장소(repository) 미러링.md
│   ├── OPIC.md
│   ├── [인적성] 명제 추리 풀이법.md
│   ├── 반도체 개념정리.md
│   ├── 시사 상식.md
│   └── 임베디드 시스템.md
├── Interview/
│   ├── Interview List.md
│   ├── Mock Test/
│   │   ├── 2019년 #기업 2차 필기테스트 유형.md
│   │   ├── 2019년 #기업 필기테스트.md
│   │   ├── 2019년 면접질문.md
│   │   └── GML Test (2019-10-03).md
│   ├── README.md
│   └── [Java] Interview List.md
├── LICENSE
├── Language/
│   ├── [C++] Vector Container.md
│   ├── [C++] 가상 함수(virtual function).md
│   ├── [C++] 입출력 실행속도 줄이는 법.md
│   ├── [C] 구조체 메모리 크기 계산.md
│   ├── [C] 동적할당.md
│   ├── [C] 포인터(Pointer).md
│   ├── [Cpp] shallow copy vs deep copy.md
│   ├── [Java] Auto Boxing & Unboxing.md
│   ├── [Java] Interned String in JAVA.md
│   ├── [Java] Intrinsic Lock.md
│   ├── [Java] Java 8 정리.md
│   ├── [Java] wait notify notifyAll.md
│   ├── [Java] 직렬화(Serialization).md
│   ├── [Java] 컴포지션(Composition).md
│   ├── [Javascript] Closure.md
│   ├── [Javascript] ES2015+ 요약 정리.md
│   ├── [Javascript] 데이터 타입.md
│   ├── [Javasript] Object Prototype.md
│   ├── [Python] 매크로 라이브러리.md
│   ├── [c] C언어 컴파일 과정.md
│   ├── [java] Call by value와 Call by reference.md
│   ├── [java] Casting(업캐스팅 & 다운캐스팅).md
│   ├── [java] Java major feature changes.md
│   ├── [java] Java에서의 Thread.md
│   ├── [java] Record.md
│   ├── [java] Stream.md
│   ├── [java] String StringBuilder StringBuffer 차이.md
│   ├── [java] 자바 가상 머신(Java Virtual Machine).md
│   └── [java] 자바 컴파일 과정.md
├── Linux/
│   ├── Linux Basic Command.md
│   ├── Permission.md
│   └── Von Neumann Architecture.md
├── New Technology/
│   ├── AI/
│   │   ├── Linear regression 실습.md
│   │   └── README.md
│   ├── Big Data/
│   │   ├── DBSCAN 클러스터링 알고리즘.md
│   │   └── 데이터 분석.md
│   └── IT Issues/
│       ├── 2020 ICT 이슈.md
│       ├── AMD vs Intel.md
│       ├── README.md
│       ├── [2019.08.07] 이메일 공격 증가로 보안업계 대응 비상.md
│       ├── [2019.08.08] IT 수다 정리.md
│       └── [2019.08.20] Google, 크롬 브라우저에서 FTP 지원 중단 확정.md
├── README.md
├── Seminar/
│   ├── 2019 삼성전자 비전캠프.md
│   ├── 2019 삼성전자 오픈소스 컨퍼런스(SOSCON).md
│   ├── NCSOFT 2019 JOB Cafe.md
│   └── NHN 2019 OPEN TALK DAY.md
└── Web/
    ├── CSR & SSR.md
    ├── CSRF & XSS.md
    ├── Cookie & Session.md
    ├── DevOps/
    │   ├── [AWS] 스프링 부트 배포 스크립트 생성.md
    │   ├── [Travis CI] 프로젝트 연동하기.md
    │   └── 시스템 규모 확장.md
    ├── HTTP Request Methods.md
    ├── HTTP status code.md
    ├── JWT(JSON Web Token).md
    ├── Logging Level.md
    ├── Nuxt.js.md
    ├── OAuth.md
    ├── PWA (Progressive Web App).md
    ├── README.md
    ├── REST API.pptx
    ├── React/
    │   ├── React & Spring Boot 연동하여 환경 구축하기.md
    │   ├── React Fragment.md
    │   └── React Hook.md
    ├── Spring/
    │   ├── JPA.md
    │   ├── Spring MVC.md
    │   ├── Spring Security - Authentication and Authorization.md
    │   ├── [Spring Boot] SpringApplication.md
    │   ├── [Spring Boot] Test Code.md
    │   ├── [Spring Data JPA] 더티 체킹 (Dirty Checking).md
    │   └── [Spring] Bean Scope.md
    ├── UI와 UX.md
    ├── Vue/
    │   ├── Vue CLI + Spring Boot 연동하여 환경 구축하기.md
    │   ├── Vue.js + Firebase로 이메일 회원가입로그인 구현.md
    │   ├── Vue.js + Firebase로 페이스북(facebook) 로그인 연동하기.md
    │   └── Vue.js 라이프사이클 이해하기.md
    ├── Vue.js와 React의 차이.md
    ├── Web Server와 WAS의 차이.md
    ├── [Travis CI] 프로젝트 연동하기.md
    ├── [Web] REST API.md
    ├── 네이티브 앱 & 웹 앱 & 하이브리드 앱.md
    ├── 브라우저 동작 방법.md
    └── 인증방식.md
Download .txt
SYMBOL INDEX (73 symbols across 15 files)

FILE: Algorithm/code/Heap.java
  class Heap (line 1) | public class Heap {
    method init (line 6) | static void init(int n) {
    method add (line 12) | static void add(int n) {
    method remove (line 22) | static int remove(int[] arr) {
    method swap (line 57) | static void swap(int a, int b) {

FILE: Algorithm/code/InsertionSort.java
  class InsertionSort (line 1) | public class InsertionSort {
    method insertionSort (line 5) | public static void insertionSort(int[] arr) {
    method main (line 18) | public static void main(String[] args) {

FILE: Algorithm/code/QuickSort.java
  class QuickSort (line 3) | public class QuickSort {
    method main (line 7) | public static void main(String[] args) throws Exception {
    method quickSort (line 15) | public static void quickSort(int[] arr, int start, int end) {

FILE: Algorithm/code/bubbleSort.java
  method bubbleSort (line 1) | void bubbleSort(int[] arr) {

FILE: Algorithm/code/mergeSort.java
  class mergeSort (line 4) | public class mergeSort {
    method main (line 8) | public static void main(String[] args) {
    method mergeSort (line 40) | private static void mergeSort(int[] arr, int left, int right) {

FILE: Computer Science/Data Structure/code/MaxHeap.java
  class MaxHeap (line 7) | public class MaxHeap {
    class maxHeap (line 9) | public static class maxHeap {
      method maxHeap (line 13) | public maxHeap() {
      method insert (line 18) | public void insert(int val) {
      method delete (line 31) | public int delete() {
    method main (line 69) | public static void main(String[] args) throws Exception {

FILE: Computer Science/Data Structure/code/MinHeap.java
  class MinHeap (line 7) | public class MinHeap {
    class minHeap (line 9) | public static class minHeap {
      method minHeap (line 14) | public minHeap() {
      method insert (line 20) | public void insert(int val) {
      method delete (line 37) | public int delete() {
    method main (line 76) | public static void main(String[] args) throws Exception {

FILE: Computer Science/Data Structure/code/binarySearchTree.java
  class binarySearchTree (line 1) | public class binarySearchTree {
    class Node (line 3) | public class Node {
      method Node (line 8) | public Node(int data) {
      method getData (line 14) | public int getData() {
      method setData (line 18) | public void setData(int data) {
      method getLeft (line 22) | public Node getLeft() {
      method setLeft (line 26) | public void setLeft(Node left) {
      method getRight (line 30) | public Node getRight() {
      method setRight (line 34) | public void setRight(Node right) {
    method binarySearchTree (line 40) | public binarySearchTree() {
    method find (line 45) | public boolean find(int id){
    method delete (line 62) | public boolean delete(int id){
    method getSuccessor (line 124) | public Node getSuccessor(Node deleleNode){
    method insert (line 141) | public void insert(int id){
    method display (line 167) | public void display(Node root){
    method main (line 175) | public static void main(String[] args) {

FILE: Computer Science/Data Structure/code/juggling_array.cpp
  function gcd (line 5) | int gcd(int a, int b)
  function leftRotate (line 15) | void leftRotate(int arr[], int d, int n)
  function printArray (line 37) | void printArray(int arr[], int size)
  function main (line 43) | int main()

FILE: Computer Science/Data Structure/code/linked_list.java
  class LinkedList (line 1) | class LinkedList{
    class Node (line 5) | static class Node {
      method Node (line 8) | Node(int d) { // 생성자
    method printList (line 13) | public void printList()
    method main (line 23) | public static void main(String[] args){

FILE: Computer Science/Data Structure/code/linked_list_push.java
  class LinkedList (line 1) | class LinkedList
    class Node (line 5) | class Node
      method Node (line 9) | Node(int d) {data = d; next = null; }
    method push (line 12) | public void push(int new_data)
    method insertAfter (line 21) | public void insertAfter(Node prev_node, int new_data)
    method append (line 36) | public void append(int new_data)
    method printList (line 56) | public void printList()
    method main (line 66) | public static void main(String[] args)

FILE: Computer Science/Data Structure/code/maxvalue_array.cpp
  function maxVal (line 6) | int maxVal(int arr[], int n){
  function main (line 30) | int main(void){

FILE: Computer Science/Data Structure/code/rearrange_array.cpp
  function fix (line 4) | int fix(int A[], int len){
  function printArray (line 31) | void printArray(int A[], int len){
  function main (line 37) | int main() {

FILE: Computer Science/Data Structure/code/reversal_array.cpp
  function reverseArr (line 5) | void reverseArr(int arr[], int start, int end){
  function rotateLeft (line 19) | void rotateLeft(int arr[], int d, int n){
  function printArray (line 25) | void printArray(int arr[], int n){
  function main (line 32) | int main(void){

FILE: Computer Science/Data Structure/code/rotate_array.cpp
  function leftRotatebyOne (line 5) | void leftRotatebyOne(int arr[], int n){
  function leftRotate (line 14) | void leftRotate(int arr[], int d, int n){
  function printArray (line 19) | void printArray(int arr[], int n){
  function main (line 25) | int main(){
Condensed preview — 214 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (880K chars).
[
  {
    "path": ".github/FUNDING.yml",
    "chars": 521,
    "preview": "# These are supported funding model platforms\n\ngithub: gyoogle\npatreon: \nopen_collective: # Replace with a single Open C"
  },
  {
    "path": "Algorithm/Binary Search.md",
    "chars": 820,
    "preview": "## 이분 탐색(Binary Search)\n\n> 탐색 범위를 두 부분으로 분할하면서 찾는 방식\n\n처음부터 끝까지 돌면서 탐색하는 것보다 훨~~~씬 빠른 장점을 지님\n\n```\n* 시간복잡도\n전체 탐색 : O(N)\n이분"
  },
  {
    "path": "Algorithm/DFS & BFS.md",
    "chars": 2331,
    "preview": "# DFS & BFS\n\n<br>\n\n그래프 알고리즘으로, 문제를 풀 때 상당히 많이 사용한다.\n\n경로를 찾는 문제 시, 상황에 맞게 DFS와 BFS를 활용하게 된다.\n\n<br>\n\n### DFS\n\n> 루트 노드 혹은 임"
  },
  {
    "path": "Algorithm/Hash Table 구현하기.md",
    "chars": 7018,
    "preview": "# Hash Table 구현하기\n\n> 알고리즘 문제를 풀기위해 필수적으로 알아야 할 개념\n\n브루트 포스(완전 탐색)으로는 시간초과에 빠지게 되는 문제에서는 해시를 적용시켜야 한다.\n\n<br>\n\n[연습 문제 링크](<"
  },
  {
    "path": "Algorithm/HeapSort.md",
    "chars": 2807,
    "preview": "#### 힙 소트(Heap Sort)\n\n---\n\n\n\n완전 이진 트리를 기본으로 하는 힙(Heap) 자료구조를 기반으로한 정렬 방식\n\n***완전 이진 트리란?***\n\n> 삽입할 때 왼쪽부터 차례대로 추가하는 이진 트리"
  },
  {
    "path": "Algorithm/LCA(Lowest Common Ancestor).md",
    "chars": 909,
    "preview": "## LCA(Lowest Common Ancestor) 알고리즘\n\n> 최소 공통 조상 찾는 알고리즘\n>\n> → 두 정점이 만나는 최초 부모 정점을 찾는 것!\n\n트리 형식이 아래와 같이 주어졌다고 하자\n\n<img sr"
  },
  {
    "path": "Algorithm/LIS (Longest Increasing Sequence).md",
    "chars": 734,
    "preview": "## LIS (Longest Increasing Sequence)\n\n> 최장 증가 수열 : 가장 긴 증가하는 부분 수열\n\n[ 7, **2**, **3**, 8, **4**, **5** ] → 해당 배열에서는 [2,3"
  },
  {
    "path": "Algorithm/MergeSort.md",
    "chars": 2816,
    "preview": "#### 머지 소트(Merge Sort)\n\n---\n\n\n\n합병 정렬이라고도 부르며, 분할 정복 방법을 통해 구현\n\n***분할 정복이란?***\n\n> 큰 문제를 작은 문제 단위로 쪼개면서 해결해나가는 방식\n\n\n\n빠른 정렬"
  },
  {
    "path": "Algorithm/QuickSort.md",
    "chars": 2511,
    "preview": "안전 정렬 : 동일한 값에 기존 순서가 유지 (버블, 삽입)\n\n불안정 정렬 : 동일한 값에 기존 순서가 유지X (선택,퀵)\n\n\n\n#### 퀵소트\n\n---\n\n퀵소트는 최악의 경우 O(n^2), 평균적으로 Θ(nlogn"
  },
  {
    "path": "Algorithm/README.md",
    "chars": 1148,
    "preview": "## 알고리즘(코딩테스트) 문제 접근법\n\n<br>\n\n#### Data Structure\n\n1. **배열** : 임의의 사이즈를 선언 (Heap, Queue, Binary Tree, Hashing 사용)\n2. **스택"
  },
  {
    "path": "Algorithm/SAMSUNG Software PRO등급 준비.md",
    "chars": 3558,
    "preview": "## SAMSUNG Software PRO등급 준비\n\n작성 : 2020.08.10.\n\n<br>\n\n#### 역량 테스트 단계\n\n---\n\n- *Advanced*\n\n- #### *Professional*\n\n- *Exper"
  },
  {
    "path": "Algorithm/Sort_Counting.md",
    "chars": 1168,
    "preview": "#### Comparison Sort\n\n------\n\n> N개 원소의 배열이 있을 때, 이를 모두 정렬하는 가짓수는 N!임\n>\n> 따라서, Comparison Sort를 통해 생기는 <u>트리의 말단 노드</u>가 "
  },
  {
    "path": "Algorithm/Sort_Radix.md",
    "chars": 2281,
    "preview": "#### Comparison Sort\n\n---\n\n> N개 원소의 배열이 있을 때, 이를 모두 정렬하는 가짓수는 N!임\n>\n> 따라서, Comparison Sort를 통해 생기는 <u>트리의 말단 노드</u>가 N! "
  },
  {
    "path": "Algorithm/code/Heap.java",
    "chars": 940,
    "preview": "public class Heap {\n\t\n\tstatic int N, heapSize;\n\tstatic int[] arr;\n\t\n\tstatic void init(int n) {\n\t\tN = n;\n\t\tarr = new int["
  },
  {
    "path": "Algorithm/code/InsertionSort.java",
    "chars": 588,
    "preview": "public class InsertionSort {\n    \n    static int[] arr = {10, 2, 6, 4, 3, 7, 5};\n    \n    public static void insertionSo"
  },
  {
    "path": "Algorithm/code/QuickSort.java",
    "chars": 718,
    "preview": "import java.util.Arrays;\n\npublic class QuickSort {\n\t\n\tstatic int[] arr = {5, 1, 1, 2, 1, 4, 4, 4, 5, 5};\n\t\n\tpublic stati"
  },
  {
    "path": "Algorithm/code/bubbleSort.java",
    "chars": 275,
    "preview": "void bubbleSort(int[] arr) {\n    int temp = 0;\n\tfor(int i = 0; i < arr.length; i++) {\n\t\tfor(int j= 1 ; j < arr.length-i;"
  },
  {
    "path": "Algorithm/code/mergeSort.java",
    "chars": 1762,
    "preview": "import java.util.Arrays;\nimport java.util.Random;\n\npublic class mergeSort {\n\t// SIZE 십 만\n\tstatic int MAX_LEN = 100_000;\n"
  },
  {
    "path": "Algorithm/professional/프로 준비법.md",
    "chars": 1785,
    "preview": "# 프로 준비법\n\n<br>\n\n#### Professional 시험 주요 특징\n\n- 4시간동안 1문제를 푼다.\n- 언어는 `c, cpp, java`로 가능하다.\n- 라이브러리를 사용할 수 없으며, 직접 자료구조를 구현"
  },
  {
    "path": "Algorithm/간단하지만 알면 좋은 최적화들.md",
    "chars": 767,
    "preview": "## [알고리즘] 간단하지만 알면 좋은 최적화들\n\n**1. for문의 ++i와 i++ 차이**\n\n```\nfor(int i = 0; i < 1000; i++) { ... } \n\nfor(int i = 0; i < 100"
  },
  {
    "path": "Algorithm/다익스트라(Dijkstra).md",
    "chars": 1983,
    "preview": "# 다익스트라(Dijkstra) 알고리즘\n\n<br>\n\n```\nDP를 활용한 최단 경로 탐색 알고리즘\n```\n\n<br>\n\n\n\n<img src=\"https://upload.wikimedia.org/wikipedia/co"
  },
  {
    "path": "Algorithm/동적 계획법 (Dynamic Programming).md",
    "chars": 1557,
    "preview": "## 동적 계획법 (Dynamic Programming)\n\n> 복잡한 문제를 간단한 여러 개의 문제로 나누어 푸는 방법\n\n<br>\n\n흔히 말하는 DP가 바로 '동적 계획법'\n\n**한 가지 문제**에 대해서, **단 "
  },
  {
    "path": "Algorithm/비트마스크(BitMask).md",
    "chars": 3111,
    "preview": "## 비트마스크(BitMask)\n\n> 집합의 요소들의 구성 여부를 표현할 때 유용한 테크닉\n\n<br>\n\n##### *왜 비트마스크를 사용하는가?*\n\n- DP나 순열 등, 배열 활용만으로 해결할 수 없는 문제\n- 작은"
  },
  {
    "path": "Algorithm/순열 & 조합.md",
    "chars": 1913,
    "preview": "# 순열 & 조합\n\n<br>\n\n### Java 코드\n\n```java\nimport java.util.ArrayList;\nimport java.util.Arrays;\n\npublic class 순열조합 {\n\tstatic "
  },
  {
    "path": "Algorithm/최대공약수 & 최소공배수.md",
    "chars": 691,
    "preview": "### [알고리즘] 최대공약수 & 최소공배수\n\n---\n\n면접 손코딩으로 출제가 많이 되는 유형 - 초등학교 때 배운 최대공약수와 최소공배수를 구현하기\n\n최대 공약수는 `유클리드 공식`을 통해 쉽게 도출해낼 수 있다."
  },
  {
    "path": "Computer Science/Computer Architecture/ARM 프로세서.md",
    "chars": 1717,
    "preview": "## ARM 프로세서\n\n<br>\n\n*프로세서란?*\n\n> 메모리에 저장된 명령어들을 실행하는 유한 상태 오토마톤\n\n<br>\n\n##### ARM : Advanced RISC Machine\n\n즉, `진보된 RISC 기기`"
  },
  {
    "path": "Computer Science/Computer Architecture/고정 소수점 & 부동 소수점.md",
    "chars": 1892,
    "preview": "## 고정 소수점 & 부동 소수점\n\n<br>\n\n컴퓨터에서 실수를 표현하는 방법은 `고정 소수점`과 `부동 소수점` 두가지 방식이 존재한다.\n\n<br>\n\n1. #### 고정 소수점(Fixed Point)\n\n   > 소"
  },
  {
    "path": "Computer Science/Computer Architecture/명령어 Cycle.md",
    "chars": 491,
    "preview": "## 명령어 Cycle\n\n- PC : 다음 실행할 명령어의 주소를 저장\n- MAR : 다음에 읽거나 쓸 기억장소의 주소를 지정\n- MBR : 기억장치에 저장될 데이터 혹은 기억장치로부터 읽은 데이터를 임시 저장\n- "
  },
  {
    "path": "Computer Science/Computer Architecture/중앙처리장치(CPU) 작동 원리.md",
    "chars": 2356,
    "preview": "## 중앙처리장치(CPU) 작동 원리\n\n\n\nCPU는 컴퓨터에서 가장 핵심적인 역할을 수행하는 부분. '인간의 두뇌'에 해당\n\n크게 연산장치, 제어장치, 레지스터 3가지로 구성됨\n\n\n\n- ##### 연산 장치\n\n  >"
  },
  {
    "path": "Computer Science/Computer Architecture/캐시 메모리(Cache Memory).md",
    "chars": 2831,
    "preview": "## 캐시 메모리(Cache Memory)\n\n속도가 빠른 장치와 느린 장치에서 속도 차이에 따른 병목 현상을 줄이기 위한 메모리를 말한다.\n\n<br>\n\n```\nex1) CPU 코어와 메모리 사이의 병목 현상 완화\ne"
  },
  {
    "path": "Computer Science/Computer Architecture/컴퓨터의 구성.md",
    "chars": 11672,
    "preview": "## 컴퓨터의 구성\n\n컴퓨터가 가지는 구성에 대해 알아보자\n\n<br>\n\n컴퓨터 시스템은 크게 하드웨어와 소프트웨어로 나누어진다.\n\n**하드웨어** : 컴퓨터를 구성하는 기계적 장치\n\n**소프트웨어** : 하드웨어의 "
  },
  {
    "path": "Computer Science/Computer Architecture/패리티 비트 & 해밍 코드.md",
    "chars": 828,
    "preview": "## 패리티 비트 & 해밍 코드\n\n<br>\n\n### 패리티 비트\n\n> 정보 전달 과정에서 오류가 생겼는 지 검사하기 위해 추가하는 비트를 말한다.\n>\n> 전송하고자 하는 데이터의 각 문자에 1비트를 더하여 전송한다."
  },
  {
    "path": "Computer Science/Data Structure/Array vs ArrayList vs LinkedList.md",
    "chars": 1541,
    "preview": "## Array vs ArrayList vs LinkedList\n\n<br>\n\n세 자료구조를 한 문장으로 정의하면 아래와 같이 말할 수 있다.\n\n\n\n<img src=\"https://t1.daumcdn.net/cfile"
  },
  {
    "path": "Computer Science/Data Structure/Array.md",
    "chars": 4839,
    "preview": "### 배열 (Array)\n\n---\n\n- C++에서 사이즈 구하기 \n\n```\nint arr[] = { 1, 2, 3, 4, 5, 6, 7 }; \nint n = sizeof(arr) / sizeof(arr[0]); /"
  },
  {
    "path": "Computer Science/Data Structure/B Tree & B+ Tree.md",
    "chars": 1764,
    "preview": "## B Tree & B+ Tree\n\n<br>\n\n> **이진 트리**는 하나의 부모가 두 개의 자식밖에 가지질 못하고, 균형이 맞지 않으면 검색 효율이 선형검색 급으로 떨어진다. 하지만 이진 트리 구조의 간결함과 균"
  },
  {
    "path": "Computer Science/Data Structure/Binary Search Tree.md",
    "chars": 1350,
    "preview": "## [자료구조] 이진탐색트리 (Binary Search Tree)\n\n<br>\n\n***이진탐색트리의 목적은?***\n\n> 이진탐색 + 연결리스트\n\n이진탐색 : **탐색에 소요되는 시간복잡도는 O(logN)**, but"
  },
  {
    "path": "Computer Science/Data Structure/Hash.md",
    "chars": 1181,
    "preview": "## 해시(Hash)\n\n데이터를 효율적으로 관리하기 위해, 임의의 길이 데이터를 고정된 길이의 데이터로 매핑하는 것\n\n해시 함수를 구현하여 데이터 값을 해시 값으로 매핑한다.\n\n<br>\n\n```\nLee → 해싱함수 "
  },
  {
    "path": "Computer Science/Data Structure/Heap.md",
    "chars": 2486,
    "preview": "## [자료구조] 힙(Heap)\n\n<br>\n\n##### 알아야할 것\n\n> 1.힙의 개념\n>\n> 2.힙의 삽입 및 삭제\n\n<br>\n\n힙은, 우선순위 큐를 위해 만들어진 자료구조다.\n\n먼저 **우선순위 큐**에 대해서 "
  },
  {
    "path": "Computer Science/Data Structure/Linked List.md",
    "chars": 2059,
    "preview": "### Linked List\n\n---\n\n![img](https://www.geeksforgeeks.org/wp-content/uploads/gq/2013/03/Linkedlist.png)\n\n연속적인 메모리 위치에 저"
  },
  {
    "path": "Computer Science/Data Structure/README.md",
    "chars": 3140,
    "preview": "## 자료구조\n\n<br>\n\n#### 배열(Array)\n\n---\n\n<u>정적으로 필요한만큼만 원소를 저장</u>할 수 있는 공간이 할당\n\n이때 각 원소의 주소는 연속적으로 할당됨\n\nindex를 통해 O(1)에 접근이 "
  },
  {
    "path": "Computer Science/Data Structure/Stack & Queue.md",
    "chars": 7011,
    "preview": "## 스택(Stack)\n\n입력과 출력이 한 곳(방향)으로 제한\n\n##### LIFO (Last In First Out, 후입선출) : 가장 나중에 들어온 것이 가장 먼저 나옴\n\n<br>\n\n***언제 사용?***\n\n함"
  },
  {
    "path": "Computer Science/Data Structure/Tree.md",
    "chars": 2169,
    "preview": "# Tree\n\n<br>\n\n```\nNode와 Edge로 이루어진 자료구조\nTree의 특성을 이해하자\n```\n\n<br>\n\n<img src=\"https://www.geeksforgeeks.org/wp-content/upl"
  },
  {
    "path": "Computer Science/Data Structure/Trie.md",
    "chars": 1203,
    "preview": "## 트라이(Trie)\n\n> 문자열에서 검색을 빠르게 도와주는 자료구조\n\n```\n정수형에서 이진탐색트리를 이용하면 시간복잡도 O(logN)\n하지만 문자열에서 적용했을 때, 문자열 최대 길이가 M이면 O(M*logN)"
  },
  {
    "path": "Computer Science/Data Structure/code/MaxHeap.java",
    "chars": 1623,
    "preview": "package practice;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\n\npublic "
  },
  {
    "path": "Computer Science/Data Structure/code/MinHeap.java",
    "chars": 1790,
    "preview": "package practice;\n\nimport java.io.BufferedReader;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\n\npublic "
  },
  {
    "path": "Computer Science/Data Structure/code/binarySearchTree.java",
    "chars": 3989,
    "preview": "public class binarySearchTree {\n\t\n\tpublic class Node {\n\t\tprivate int data;\n\t\tprivate Node left;\n\t\tprivate Node right;\n\t\t"
  },
  {
    "path": "Computer Science/Data Structure/code/juggling_array.cpp",
    "chars": 879,
    "preview": "#include  \nusing namespace std; \n\n// 최대공약수 gcd 활용\nint gcd(int a, int b) \n{ \n    if (b == 0) \n        return a; \n  \n    e"
  },
  {
    "path": "Computer Science/Data Structure/code/linked_list.java",
    "chars": 1442,
    "preview": "class LinkedList{\n    \n    Node head;\n\n    static class Node {\n        int data;\n        Node next;\n        Node(int d) "
  },
  {
    "path": "Computer Science/Data Structure/code/linked_list_push.java",
    "chars": 1786,
    "preview": "class LinkedList \n{ \n    Node head;\n  \n    class Node \n    { \n        int data; \n        Node next; \n        Node(int d)"
  },
  {
    "path": "Computer Science/Data Structure/code/maxvalue_array.cpp",
    "chars": 686,
    "preview": "// 지정된 배열에서 하나씩 회전을 해서 i*arr[i]의 합이 가장 컸을 때 값을 출력하는 문제\n\n#include <iostream>\nusing namespace std;\n\nint maxVal(int arr[], "
  },
  {
    "path": "Computer Science/Data Structure/code/rearrange_array.cpp",
    "chars": 924,
    "preview": "#include <iostream>\nusing namespace std;\n\nint fix(int A[], int len){\n    \n    for(int i = 0; i < len; i++) {\n        \n  "
  },
  {
    "path": "Computer Science/Data Structure/code/reversal_array.cpp",
    "chars": 740,
    "preview": "#include <iostream>\nusing namespace std;\n\n// swap을 활용한 reverse 구현\nvoid reverseArr(int arr[], int start, int end){\n    \n "
  },
  {
    "path": "Computer Science/Data Structure/code/rotate_array.cpp",
    "chars": 590,
    "preview": "#include  \nusing namespace std; \n\n//왼쪽으로 한번 회전\nvoid leftRotatebyOne(int arr[], int n){\n    int temp = arr[0], i;\n    for"
  },
  {
    "path": "Computer Science/Database/Redis.md",
    "chars": 565,
    "preview": "## Redis\n\n> 빠른 오픈 소스 인 메모리 키 값 데이터 구조 스토어\n\n보통 데이터베이스는 하드 디스크나 SSD에 저장한다. 하지만 Redis는 메모리(RAM)에 저장해서 디스크 스캐닝이 필요없어 매우 빠른 장"
  },
  {
    "path": "Computer Science/Database/SQL Injection.md",
    "chars": 1266,
    "preview": "## SQL Injection\n\n> 해커에 의해 조작된 SQL 쿼리문이 데이터베이스에 그대로 전달되어 비정상적 명령을 실행시키는 공격 기법\n\n<br>\n\n#### 공격 방법\n\n##### 1) 인증 우회\n\n보통 로그인을"
  },
  {
    "path": "Computer Science/Database/SQL과 NOSQL의 차이.md",
    "chars": 2911,
    "preview": "## SQL과 NOSQL의 차이\n\n<br>\n\n웹 앱을 개발할 때, 데이터베이스를 선택할 때 고민하게 된다.\n\n<br>\n\n```\nMySQL과 같은 SQL을 사용할까? 아니면 MongoDB와 같은 NoSQL을 사용할까?"
  },
  {
    "path": "Computer Science/Database/Transaction Isolation Level.md",
    "chars": 2195,
    "preview": "## 트랜잭션 격리 수준(Transaction Isolation Level)\n\n<br>\n\n#### **Isolation level** \n\n---\n\n트랜잭션에서 일관성 없는 데이터를 허용하도록 하는 수준\n\n<br>\n\n"
  },
  {
    "path": "Computer Science/Database/Transaction.md",
    "chars": 2721,
    "preview": "# DB 트랜잭션(Transaction)\n\n<br>\n\n#### 트렌잭션이란?\n\n> 데이터베이스의 상태를 변화시키기 위해 수행하는 작업 단위\n\n<br>\n\n상태를 변화시킨다는 것 → **SQL 질의어를 통해 DB에 접근"
  },
  {
    "path": "Computer Science/Database/[DB] Anomaly.md",
    "chars": 887,
    "preview": "#### [DB] Anomaly\n\n---\n\n> 정규화를 해야하는 이유는 잘못된 테이블 설계로 인해 Anomaly (이상 현상)가 나타나기 때문이다.\n>\n> 이 페이지에서는 Anomaly가 무엇인지 살펴본다.\n\n예) "
  },
  {
    "path": "Computer Science/Database/[DB] Index.md",
    "chars": 2091,
    "preview": "# Index(인덱스)\n\n<br>\n\n#### 목적\n\n```\n추가적인 쓰기 작업과 저장 공간을 활용하여 데이터베이스 테이블의 검색 속도를 향상시키기 위한 자료구조\n```\n\n테이블의 칼럼을 색인화한다.\n\n> 마치, 두꺼"
  },
  {
    "path": "Computer Science/Database/[DB] Key.md",
    "chars": 535,
    "preview": "### [DB] Key\n\n---\n\n> Key란? : 검색, 정렬시 Tuple을 구분할 수 있는 기준이 되는 Attribute.\n\n<br>\n\n#### 1. Candidate Key (후보키)\n\n> Tuple을 유일하게"
  },
  {
    "path": "Computer Science/Database/[Database SQL] JOIN.md",
    "chars": 2361,
    "preview": "## [Database SQL] JOIN\n\n##### 조인이란?\n\n> 두 개 이상의 테이블이나 데이터베이스를 연결하여 데이터를 검색하는 방법\n\n테이블을 연결하려면, 적어도 하나의 칼럼을 서로 공유하고 있어야 하므로 "
  },
  {
    "path": "Computer Science/Database/저장 프로시저(Stored PROCEDURE).md",
    "chars": 1945,
    "preview": "# 저장 프로시저(Stored PROCEDURE)\n\n<br>\n\n```\n일련의 쿼리를 마치 하나의 함수처럼 실행하기 위한 쿼리의 집합\n```\n\n<br>\n\n데이터베이스에서 SQL을 통해 작업을 하다 보면, 하나의 쿼리문"
  },
  {
    "path": "Computer Science/Database/정규화(Normalization).md",
    "chars": 2303,
    "preview": "# 정규화(Normalization)\n\n<br>\n\n```\n데이터의 중복을 줄이고, 무결성을 향상시킬 수 있는 정규화에 대해 알아보자\n```\n\n<br>\n\n### Normalization\n\n가장 큰 목표는 테이블 간 *"
  },
  {
    "path": "Computer Science/Network/DNS.md",
    "chars": 820,
    "preview": "# DNS (Domain Name Server)\n\n모든 통신은 IP를 기반으로 연결된다. 하지만 사용자에게 일일히 IP 주소를 입력하기란 UX적으로 좋지 않다\n\n때문에 DNS 가 등장 했으며 DNS 는 IP 주소와 "
  },
  {
    "path": "Computer Science/Network/HTTP & HTTPS.md",
    "chars": 2053,
    "preview": "## HTTP & HTTPS\n\n<br>\n\n- ##### HTTP(HyperText Transfer Protocol)\n\n  인터넷 상에서 클라이언트와 서버가 자원을 주고 받을 때 쓰는 통신 규약\n\n<br>\n\nHTTP는"
  },
  {
    "path": "Computer Science/Network/OSI 7 계층.md",
    "chars": 1136,
    "preview": "## OSI 7 계층\n\n<br>\n\n<img src=\"https://s7280.pcdn.co/wp-content/uploads/2018/06/osi-model-7-layers-1.png\">\n\n<br>\n\n#### 7계층"
  },
  {
    "path": "Computer Science/Network/TCP (흐름제어혼잡제어).md",
    "chars": 5178,
    "preview": "\n\n\n\n### TCP (흐름제어/혼잡제어)\n\n---\n\n#### 들어가기 전\n\n- TCP 통신이란?\n  - 네트워크 통신에서 신뢰적인 연결방식\n  - TCP는 기본적으로 unreliable network에서, reli"
  },
  {
    "path": "Computer Science/Network/TCP 3 way handshake & 4 way handshake.md",
    "chars": 1121,
    "preview": "## [TCP] 3 way handshake & 4 way handshake\n\n> 연결을 성립하고 해제하는 과정을 말한다\n\n<br>\n\n### 3 way handshake - 연결 성립\n\nTCP는 정확한 전송을 보장해"
  },
  {
    "path": "Computer Science/Network/TLS HandShake.md",
    "chars": 1460,
    "preview": "# TLS/SSL HandShake\n\n<br>\n\n```\nHTTPS에서 클라이언트와 서버간 통신 전\nSSL 인증서로 신뢰성 여부를 판단하기 위해 연결하는 방식\n```\n\n<br>\n\n![image](https://user"
  },
  {
    "path": "Computer Science/Network/UDP.md",
    "chars": 2680,
    "preview": "### 2019.08.26.(월) [BYM] UDP란? \n\n---\n\n#### 들어가기 전\n\n- UDP 통신이란?\n\n  - User Datagram Protocol의 약자로 데이터를 데이터그램 단위로 처리하는 프로토콜"
  },
  {
    "path": "Computer Science/Network/[Network] Blocking Non-Blocking IO.md",
    "chars": 1174,
    "preview": "#### Blocking I/O & Non-Blocking I/O\n\n---\n\n> I/O 작업은 Kernel level에서만 수행할 수 있다. 따라서, Process, Thread는 커널에게 I/O를 요청해야 한다.\n"
  },
  {
    "path": "Computer Science/Network/[Network] Blocking,Non-blocking & Synchronous,Asynchronous.md",
    "chars": 2528,
    "preview": "# [Network] Blocking/Non-blocking & Synchronous/Asynchronous\n\n<br>\n\n```\n동기/비동기는 우리가 일상 생활에서 많이 들을 수 있는 말이다.\n\nBlocking과 S"
  },
  {
    "path": "Computer Science/Network/대칭키 & 공개키.md",
    "chars": 1112,
    "preview": "## 대칭키 & 공개키\n\n<br>\n\n#### 대칭키(Symmetric Key)\n\n> 암호화와 복호화에 같은 암호키(대칭키)를 사용하는 알고리즘\n\n동일한 키를 주고받기 때문에, 매우 빠르다는 장점이 있음\n\nbut, 대"
  },
  {
    "path": "Computer Science/Network/로드 밸런싱(Load Balancing).md",
    "chars": 1182,
    "preview": "## 로드 밸런싱(Load Balancing)\n\n> 둘 이상의 CPU or 저장장치와 같은 컴퓨터 자원들에게 작업을 나누는 것\n\n<br>\n\n<img src=\"https://www.educative.io/api/col"
  },
  {
    "path": "Computer Science/Operating System/CPU Scheduling.md",
    "chars": 3397,
    "preview": "# CPU Scheduling\n\n<br>\n\n### 1. 스케줄링\n\n> CPU 를 잘 사용하기 위해 프로세스를 잘 배정하기\n\n- 조건 : 오버헤드 ↓ / 사용률 ↑ / 기아 현상 ↓\n- 목표\n    1. `Batch "
  },
  {
    "path": "Computer Science/Operating System/DeadLock.md",
    "chars": 2736,
    "preview": "## 데드락 (DeadLock, 교착 상태)\n\n> 두 개 이상의 프로세스나 스레드가 서로 자원을 얻지 못해서 다음 처리를 하지 못하는 상태\n>\n> 무한히 다음 자원을 기다리게 되는 상태를 말한다.\n>\n> 시스템적으로"
  },
  {
    "path": "Computer Science/Operating System/File System.md",
    "chars": 2009,
    "preview": "## 파일 시스템(File System)\n\n<br>\n\n컴퓨터에서 파일이나 자료를 쉽게 발견할 수 있도록, 유지 및 관리하는 방법이다.\n\n저장매체에는 수많은 파일이 있기 때문에, 이런 파일들을 관리하는 방법을 말한다."
  },
  {
    "path": "Computer Science/Operating System/IPC(Inter Process Communication).md",
    "chars": 2260,
    "preview": "### IPC(Inter Process Communication)\n\n---\n\n<img src=\"https://t1.daumcdn.net/cfile/tistory/99DB8C495C4C570417\">\n\n<br>\n\n프로"
  },
  {
    "path": "Computer Science/Operating System/Interrupt.md",
    "chars": 1545,
    "preview": "## 인터럽트(Interrupt)\n\n##### 정의\n\n프로그램을 실행하는 도중에 예기치 않은 상황이 발생할 경우 현재 실행 중인 작업을 즉시 중단하고, 발생된 상황에 대한 우선 처리가 필요함을 CPU에게 알리는 것\n"
  },
  {
    "path": "Computer Science/Operating System/Memory.md",
    "chars": 4098,
    "preview": "#### 메인 메모리(main memory)\n\n> 메인 메모리는 CPU가 직접 접근할 수 있는 기억 장치\n>\n> 프로세스가 실행되려면 프로그램이 메모리에 올라와야 함\n\n주소가 할당된 일련의 바이트들로 구성되어 있음\n"
  },
  {
    "path": "Computer Science/Operating System/Operation System.md",
    "chars": 2163,
    "preview": "## 운영 체제란 무엇인가?\n\n> **운영 체제(OS, Operating System)**\n>\n> : 하드웨어를 관리하고, 컴퓨터 시스템의 자원들을 효율적으로 관리하며, 응용 프로그램과 하드웨어 간의 인터페이스로써 "
  },
  {
    "path": "Computer Science/Operating System/PCB & Context Switcing.md",
    "chars": 1694,
    "preview": "## PCB & Context Switching\n\n<br>\n\n#### Process Management\n\n> CPU가 프로세스가 여러개일 때, CPU 스케줄링을 통해 관리하는 것을 말함\n\n이때, CPU는 각 프로세스"
  },
  {
    "path": "Computer Science/Operating System/Page Replacement Algorithm.md",
    "chars": 2519,
    "preview": "### 페이지 교체 알고리즘\n\n---\n\n> 페이지 부재 발생 → 새로운 페이지를 할당해야 함 → 현재 할당된 페이지 중 어떤 것 교체할 지 결정하는 방법\n\n<br>\n\n- 좀 더 자세하게 생각해보면?\n\n가상 메모리는 "
  },
  {
    "path": "Computer Science/Operating System/Paging and Segmentation.md",
    "chars": 1138,
    "preview": "### 페이징과 세그먼테이션\n\n---\n\n##### 기법을 쓰는 이유\n\n> 다중 프로그래밍 시스템에 여러 프로세스를 수용하기 위해 주기억장치를 동적 분할하는 메모리 관리 작업이 필요해서\n\n<br>\n\n#### 메모리 관"
  },
  {
    "path": "Computer Science/Operating System/Process Address Space.md",
    "chars": 570,
    "preview": "## 프로세스의 주소 공간\n\n> 프로그램이 CPU에 의해 실행됨 → 프로세스가 생성되고 메모리에 '**프로세스 주소 공간**'이 할당됨\n\n프로세스 주소 공간에는 코드, 데이터, 스택으로 이루어져 있다.\n\n- **코드"
  },
  {
    "path": "Computer Science/Operating System/Process Management & PCB.md",
    "chars": 1692,
    "preview": "## PCB & Context Switching\n\n<br>\n\n#### Process Management\n\n> CPU가 프로세스가 여러개일 때, CPU 스케줄링을 통해 관리하는 것을 말함\n\n이때, CPU는 각 프로세스"
  },
  {
    "path": "Computer Science/Operating System/Process vs Thread.md",
    "chars": 1791,
    "preview": "# 프로세스 & 스레드\n\n<br>\n\n> **프로세스** : 프로그램을 메모리 상에서 실행중인 작업\n>\n> **스레드** : 프로세스 안에서 실행되는 여러 흐름 단위\n\n<br>\n\n기본적으로 프로세스마다 최소 1개의 스"
  },
  {
    "path": "Computer Science/Operating System/Race Condition.md",
    "chars": 752,
    "preview": "## [OS] Race Condition\n\n공유 자원에 대해 여러 프로세스가 동시에 접근할 때, 결과값에 영향을 줄 수 있는 상태\n\n> 동시 접근 시 자료의 일관성을 해치는 결과가 나타남\n\n<br>\n\n#### Rac"
  },
  {
    "path": "Computer Science/Operating System/Semaphore & Mutex.md",
    "chars": 3259,
    "preview": "## 세마포어(Semaphore) & 뮤텍스(Mutex)\n\n<br>\n\n공유된 자원에 여러 프로세스가 동시에 접근하면서 문제가 발생할 수 있다. 이때 공유된 자원의 데이터는 한 번에 하나의 프로세스만 접근할 수 있도록"
  },
  {
    "path": "Computer Science/Operating System/[OS] System Call (Fork Wait Exec).md",
    "chars": 3575,
    "preview": "#### [Operating System] System Call\n\n---\n\nfork( ), exec( ), wait( )와 같은 것들은 Process 생성과 제어를 위한 System call임.\n\n- fork, ex"
  },
  {
    "path": "Computer Science/Software Engineering/Clean Code & Refactoring.md",
    "chars": 3511,
    "preview": "## 클린코드와 리팩토링\n\n<br>\n\n클린코드와 리팩토링은 의미만 보면 비슷하다고 느껴진다. 어떤 차이점이 있을지 생각해보자\n\n<br>\n\n#### 클린코드\n\n클린코드란, 가독성이 높은 코드를 말한다.\n\n가독성을 높이"
  },
  {
    "path": "Computer Science/Software Engineering/Fuctional Programming.md",
    "chars": 3302,
    "preview": "## 함수형 프로그래밍\n\n> 순수 함수를 조합하고 공유 상태, 변경 가능한 데이터 및 부작용을 **피해** 소프트웨어를 만드는 프로세스\n\n<br>\n\n<img src=\"https://user-images.githubu"
  },
  {
    "path": "Computer Science/Software Engineering/Object-Oriented Programming.md",
    "chars": 6202,
    "preview": "## 객체지향 프로그래밍\n\n<br>\n\n보통 OOP라고 많이 부른다. 객체지향은 수 없이 많이 들어왔지만, 이게 뭔지 설명해달라고 하면 어디서부터 해야할 지 막막해진다.. 개념을 잡아보자\n\n<br>\n\n객체지향 패러다임"
  },
  {
    "path": "Computer Science/Software Engineering/TDD(Test Driven Development).md",
    "chars": 4459,
    "preview": "## TDD(Test Driven Development)\n\n\n##### TDD : 테스트 주도 개발\n\n'테스트가 개발을 이끌어 나간다.'\n\n<br>\n<br>\n우리는 보통 개발할 때, 설계(디자인)를 한 이후 코드 개"
  },
  {
    "path": "Computer Science/Software Engineering/데브옵스(DevOps).md",
    "chars": 612,
    "preview": "## 데브옵스(DevOps)\n\n<br>\n\n> Development + Operations의 합성어\n\n소프트웨어 개발자와 정보기술 전문가 간의 소통, 협업 및 통합을 강조하는 개발 환경이나 문화를 의미한다.\n\n<br>"
  },
  {
    "path": "Computer Science/Software Engineering/마이크로서비스 아키텍처(MSA).md",
    "chars": 1878,
    "preview": "# 마이크로서비스 아키텍처(MSA)\n\n<br>\n\n```\nMSA는 소프트웨어 개발 기법 중 하나로, 어플리케이션 단위를 '목적'으로 나누는 것이 핵심\n```\n\n<br>\n\n## Monolithic vs MSA \n\nMSA"
  },
  {
    "path": "Computer Science/Software Engineering/써드파티(3rd party)란.md",
    "chars": 706,
    "preview": "## 써드 파티(3rd party)란?\n\n<br>\n\n간혹 써드 파티라는 말을 종종 볼 수 있다. 경제 용어가 IT에서 쓰이는 부분이다.\n\n##### *3rd party*\n\n> 하드웨어 생산자와 소프트웨어 개발자의 관"
  },
  {
    "path": "Computer Science/Software Engineering/애자일(Agile).md",
    "chars": 4603,
    "preview": "## 애자일(Agile)\n\n<br>\n\n소프트웨어 개발 기법으로 많이 들어본 단어다. 특히 소프트웨어 공학 수업을 들을 때 분명 배웠다. (근데 기억이 안남..)\n\n폭포수 모델, 애자일 기법 등등.. 무엇인지 알아보자"
  },
  {
    "path": "Computer Science/Software Engineering/애자일(Agile)2.md",
    "chars": 4184,
    "preview": "Agile이란 무엇인가.\n\n> 이 글의 목표는 Agile을 이해하는 것이다.\n> 아래의 내용을 종합하여, Agile이 무엇인지 한 문장으로 정의할 수 있어야 한다.\n\n---\n\n### #0 Software Develo"
  },
  {
    "path": "Computer Science/Software Engineering/클린코드(Clean Code) & 시큐어코딩(Secure Coding).md",
    "chars": 4382,
    "preview": "## 클린코드(Clean Code) & 시큐어코딩(Secure Coding)\n\n<br>\n\n#### 전문가들이 표현한 '클린코드'\n\n>`한 가지를 제대로 한다.`\n>\n>`단순하고 직접적이다.`\n>\n>`특정 목적을 달성"
  },
  {
    "path": "Design Pattern/Adapter Pattern.md",
    "chars": 2218,
    "preview": "### 어댑터 패턴\n\n---\n\n> - 용도 : 클래스를 바로 사용할 수 없는 경우가 있음 (다른 곳에서 개발했다거나, 수정할 수 없을 때)\n>   중간에서 변환 역할을 해주는 클래스가 필요 → 어댑터 패턴\n>\n> -"
  },
  {
    "path": "Design Pattern/Composite Pattern.md",
    "chars": 2620,
    "preview": "# Composite Pattern\n\n### 목적\ncompositie pattern의 사용 목적은 object의 **hierarchies**를 표현하고 각각의 object를 독립적으로 동일한 인터페이스를 통해 처리할"
  },
  {
    "path": "Design Pattern/Design Pattern_Adapter.md",
    "chars": 1009,
    "preview": "#### Design Pattern - Adapter Pattern\n\n---\n\n[어댑터 패턴]\n\n국가별 사용하는 전압이 달라서 220v를 110v형으로 바꿔서 끼우는 경우를 생각해보기.\n\n- 실행 부분 (Main.j"
  },
  {
    "path": "Design Pattern/Design Pattern_Factory Method.md",
    "chars": 853,
    "preview": "#### Design Pattern - Factory Method Pattern\n\n---\n\n한 줄 설명 : 객체를 만드는 부분을 Sub class에 맡기는 패턴.\n\n> Robot (추상 클래스)\n>\n> ​\tㄴ Sup"
  },
  {
    "path": "Design Pattern/Design Pattern_Template Method.md",
    "chars": 2001,
    "preview": "#### 디자인 패턴 _ Template Method Pattern\n\n---\n\n[디자인 패턴 예]\n\n1. 템플릿 메서드 패턴\n\n   특정 환경 or 상황에 맞게 확장, 변경할 때 유용한 패턴\n\n   **<u>추상 클"
  },
  {
    "path": "Design Pattern/Observer pattern.md",
    "chars": 3443,
    "preview": "## 옵저버 패턴(Observer pattern)\n\n> 상태를 가지고 있는 주체 객체 & 상태의 변경을 알아야 하는 관찰 객체\n\n(1 대 1 or 1 대 N 관계)\n\n서로의 정보를 주고받는 과정에서 정보의 단위가 클"
  },
  {
    "path": "Design Pattern/SOLID.md",
    "chars": 4950,
    "preview": "# An overview of design pattern - SOLID, GRASP\n\n먼저 디자인 패턴을 공부하기 전에 Design Principle인 SOLID와 GRASP에 대해서 알아보자\n\n\n# Design S"
  },
  {
    "path": "Design Pattern/Singleton Pattern.md",
    "chars": 3580,
    "preview": "## [디자인 패턴] 싱글톤 패턴(Singleton pattern)\n\n<br>\n\n##### *싱글톤 패턴이란?*\n\n애플리케이션이 시작될 때, 어떤 클래스가 최초 한 번만 메모리를 할당(static)하고 해당 메모리"
  },
  {
    "path": "Design Pattern/Strategy Pattern.md",
    "chars": 1362,
    "preview": "## 스트레티지 패턴(Strategy Pattern)\n\n> 어떤 동작을 하는 로직을 정의하고, 이것들을 하나로 묶어(캡슐화) 관리하는 패턴\n\n새로운 로직을 추가하거나 변경할 때, 한번에 효율적으로 변경이 가능하다.\n"
  },
  {
    "path": "Design Pattern/Template Method Pattern.md",
    "chars": 1205,
    "preview": "## [디자인 패턴] Template Method Pattern\n\n> 로직을 단계 별로 나눠야 하는 상황에서 적용한다.\n>\n> 단계별로 나눈 로직들이 앞으로 수정될 가능성이 있을 경우 더 효율적이다.\n\n<br>\n\n#"
  },
  {
    "path": "Design Pattern/[Design Pattern] Overview.md",
    "chars": 1264,
    "preview": "### [Design Pattern] 개요\n\n---\n\n> 일종의 설계 기법이며, 설계 방법이다.\n\n\n\n* #### 목적\n\n  SW **재사용성, 호환성, 유지 보수성**을 보장.\n\n  <br>\n\n* #### 특징\n\n"
  },
  {
    "path": "ETC/Collaborate with Git on Javascript and Node.js.md",
    "chars": 10265,
    "preview": "## Javascript와 Node.js로 Git을 통해 협업하기\n\n<br>\n\n협업 프로젝트를 하기 위해서는 Git을 잘 써야한다. \n\n하나의 프로젝트를 같이 작업하면서 자신에게 주어진 파트에 대한 영역을 pull과"
  },
  {
    "path": "ETC/Git Commit Message Convention.md",
    "chars": 2151,
    "preview": "# Git Commit Message Convention\n\n<br>\n\nGit은 컴퓨터 파일의 변경사항을 추적하고 여러 명의 사용자들 간에 해당 파일들의 작업을 조율하기 위한 분산 버전 관리 시스템이다. 따라서, 커밋"
  },
  {
    "path": "ETC/Git vs GitHub vs GitLab Flow.md",
    "chars": 3191,
    "preview": "# Git vs GitHub vs GitLab Flow\n\n<br>\n\n```\ngit-flow의 종류는 크게 3가지로 분리된다.\n어떤 차이점이 있는지 간단히 알아보자\n```\n\n<br>\n\n## 1. Git Flow\n\n가장"
  },
  {
    "path": "ETC/GitHub Fork로 협업하기.md",
    "chars": 557,
    "preview": "### GitHub Fork로 협업하기 \n\n---\n\n1. Fork한 자신의 원격 저장소 확인 (최초에는 존재하지 않음)\n\n   ```bash\n   git remote -v\n   ```\n\n2. Fork한 자신의 로컬 "
  },
  {
    "path": "ETC/GitHub 저장소(repository) 미러링.md",
    "chars": 1338,
    "preview": "### GitHub 저장소(repository) 미러링\n\n---\n\n- ##### 미러링 : commit log를 유지하며 clone\n\n##### <br>\n\n1. #### 저장소 미러링\n\n   1. 복사하고자 하는 저"
  },
  {
    "path": "ETC/OPIC.md",
    "chars": 1023,
    "preview": "## OPIC\n\n> 인터뷰 형식의 영어 스피킹 시험\n\n<br>\n\n정형화된 비즈니스 영어에 가까운 토익스피킹과는 다르게 자유로운 실전 영어 스타일\n\n문법, 단어의 완성도가 떨어져도 괜찮음. '나의 이야기'를 전달하고 "
  },
  {
    "path": "ETC/[인적성] 명제 추리 풀이법.md",
    "chars": 1179,
    "preview": "## [인적성] 명제 추리 풀이법\n\n<br>\n\n모든, 어떤이 들어간 문장에 대한 명제 추리는 항상 까다롭다. 이를 대우로 바꾸며 옳은 문장을 찾기 위한 문제는 인적성에서 꼭 나온다.\n\n실제로 정확한 답을 유추하기 위"
  },
  {
    "path": "ETC/반도체 개념정리.md",
    "chars": 4791,
    "preview": "### 반도체(Semiconductor)\n\n> 도체와 부도체의 중간정도 되는 물질\n\n<br>\n\n빛이나 열을 가하거나, 특정 불순물을 첨가해 도체처럼 전기가 흐르게 함\n\n즉, **전기전도성을 조절할 수 있는 것**이 "
  },
  {
    "path": "ETC/시사 상식.md",
    "chars": 1963,
    "preview": "## 시사 상식\n\n<br>\n\n- ##### 디노미네이션\n\n  화폐의 액면 단위를 100분의 1 혹은 10분의 1 등으로 낮추는 화폐개혁\n\n  <br>\n\n- ##### 카니발라이제이션\n\n  파격적인 후속 제품이 시장에"
  },
  {
    "path": "ETC/임베디드 시스템.md",
    "chars": 672,
    "preview": "## 임베디드 시스템\n\n<br>\n\n특정한 목적을 수행하도록 만든 컴퓨터로, 사람의 개입 없이 작동 가능한 하드웨어와 소프트웨어의 결합체\n\n임베디드 시스템의 하드웨어는 특정 목적을 위해 설계됨\n\n<br>\n\n#### 임"
  },
  {
    "path": "Interview/Interview List.md",
    "chars": 17119,
    "preview": "# Interview List\n\n간단히 개념들을 정리해보며 머리 속에 넣자~\n\n<br>\n\n- [언어(Java, C++ ... )](<https://github.com/kim6394/Dev_BasicKnowledge"
  },
  {
    "path": "Interview/Mock Test/2019년 #기업 2차 필기테스트 유형.md",
    "chars": 199,
    "preview": "1. 데드락\n2. IP 프로토콜\n3. 서브넷 마스크(브로드캐스팅)\n4. Isolation Level\n5. 이진 탐색 트리\n6. 버블 정렬\n7. Round Robin 스케줄링\n8. 페이징 번호\n9. DB JOIN\n10"
  },
  {
    "path": "Interview/Mock Test/2019년 #기업 필기테스트.md",
    "chars": 1182,
    "preview": "1. ##### 일치하는 자료구조 작성하기\n\n   > 1) 문자열이 주어지고 빠른 검색 ~~ : 해시\n   >\n   > 2) 운영체제 라운드 로빈에서 사용 ~~ : 연결리스트 \n   >\n   > 3) 우선순위로 뽑고"
  },
  {
    "path": "Interview/Mock Test/2019년 면접질문.md",
    "chars": 471,
    "preview": "1. 퀵소트 구현하고 시간복잡도 설명\n2. 최악으로 바꾸고 진행\n3. 공간복잡도\n4. 디자인패턴이 뭐로 나눠지는지\n5. 아는거 다말하고 뭔지설명하면서 어디 영역에 해당하는지\n6. PWA랑 SPA 차이점\n7. Vue "
  },
  {
    "path": "Interview/Mock Test/GML Test (2019-10-03).md",
    "chars": 3128,
    "preview": "### GML Test (2019-10-03)\n\n---\n\n1. OOP 특징에 대해 잘못 설명한 것은?\n\n   > 1. OOP는 유지 보수성, 재사용성, 확장성이라는 장점이 있다.\n   > 2. 캡슐화는 정보 은닉을 "
  },
  {
    "path": "Interview/README.md",
    "chars": 1714,
    "preview": "### 기술 면접 준비하기\n\n------\n\n- #### 시작하기\n\n  *기술면접을 준비할 때는 절대 문제와 답을 읽는 식으로 하지 말고, 문제를 직접 푸는 훈련을 해야합니다.*\n\n  1. ##### 직접 문제를 풀수"
  },
  {
    "path": "Interview/[Java] Interview List.md",
    "chars": 3741,
    "preview": "# [Java ]Interview List\n\n> - 간단히 개념들을 정리해보며 머리 속에 넣자~\n> - 질문 자체에 없는 질문 의도가 있는 경우 추가 했습니다.\n> - 완전한 설명보다는 면접 답변에 초점을 두며, "
  },
  {
    "path": "LICENSE",
    "chars": 1068,
    "preview": "MIT License\n\nCopyright (c) 2019 Gyuseok Kim\n\nPermission is hereby granted, free of charge, to any person obtaining a cop"
  },
  {
    "path": "Language/[C++] Vector Container.md",
    "chars": 1132,
    "preview": "# [C++] Vector Container\n\n<br>\n\n```cpp\n#include <vector>\n```\n\n자동으로 메모리를 할당해주는 Cpp 라이브러리\n\n데이터 타입을 정할 수 있으며, push pop은 스택과"
  },
  {
    "path": "Language/[C++] 가상 함수(virtual function).md",
    "chars": 1061,
    "preview": "### 가상 함수(virtual function)\n\n---\n\n> C++에서 자식 클래스에서 재정의(오버라이딩)할 것으로 기대하는 멤버 함수를 의미함\n>\n> 멤버 함수 앞에 `virtual` 키워드를 사용하여 선언함 "
  },
  {
    "path": "Language/[C++] 입출력 실행속도 줄이는 법.md",
    "chars": 662,
    "preview": "## [C++] 입출력 실행속도 줄이는 법\n\n<br>\n\nC++로 알고리즘 문제를 풀 때, `cin, cout`은 실행속도가 느리다. 하지만 최적화 방법을 이용하면 실행속도 단축에 효율적이다.\n\n만약 `cin, cou"
  },
  {
    "path": "Language/[C] 구조체 메모리 크기 계산.md",
    "chars": 1879,
    "preview": "## [C] 구조체 메모리 크기 (Struct Memory Size)\n\ntypedef struct 선언 시, 변수 선언에 대한 메모리 공간 크기에 대해 알아보자\n\n> 기업 필기 테스트에서 자주 나오는 유형이기도 함\n"
  },
  {
    "path": "Language/[C] 동적할당.md",
    "chars": 1437,
    "preview": "## [C] 동적할당\n\n<br>\n\n##### *동적할당이란?*\n\n> 프로그램 실행 중에 동적으로 메모리를 할당하는 것\n>\n> Heap 영역에 할당한다\n\n<br>\n\n- `<stdlib.h>` 헤더 파일을 include"
  },
  {
    "path": "Language/[C] 포인터(Pointer).md",
    "chars": 2117,
    "preview": "## [C] 포인터(Pointer)\n\n<br>\n\n***포인터*** : 특정 변수를 가리키는 역할을 하는 변수\n\n<br>\n\nmain에서 한번 만들어둔 변수 값을 다른 함수에서 그대로 사용하거나, 변경하고 싶은 경우가 "
  },
  {
    "path": "Language/[Cpp] shallow copy vs deep copy.md",
    "chars": 828,
    "preview": "# [Cpp] 얕은 복사 vs 깊은 복사\n\n<br>\n\n> shallow copy와 deep copy가 어떻게 다른지 알아보자\n\n<br>\n\n### 얕은 복사(shallow copy)\n\n한 객체의 모든 멤버 변수의 값을"
  },
  {
    "path": "Language/[Java] Auto Boxing & Unboxing.md",
    "chars": 1575,
    "preview": "# [Java] 오토 박싱 & 오토 언박싱\n\n<br>\n\n자바에는 기본 타입과 Wrapper 클래스가 존재한다.\n\n- 기본 타입 : `int, long, float, double, boolean` 등\n- Wrapper"
  },
  {
    "path": "Language/[Java] Interned String in JAVA.md",
    "chars": 1923,
    "preview": "# Interned String in Java\n자바(Java)의 문자열(String)은 불변(immutable)하다. \nString의 함수를 호출을 하면 해당 객체를 직접 수정하는 것이 아니라, 함수의 결과로 해당 "
  },
  {
    "path": "Language/[Java] Intrinsic Lock.md",
    "chars": 2280,
    "preview": "### Java 고유 락 (Intrinsic Lock)\n\n---\n\n#### Intrinsic Lock / Synchronized Block / Reentrancy\n\nIntrinsic Lock (= monitor lo"
  },
  {
    "path": "Language/[Java] Java 8 정리.md",
    "chars": 1039,
    "preview": "# [Java] Java 8 정리\n\n<br>\n\n```\nJava 8은 가장 큰 변화가 있던 버전이다.\n자바로 구현하기 힘들었던 병렬 프로세싱을 활용할 수 있게 된 버전이기 때문\n```\n\n<br>\n\n시대가 발전하면서 이"
  },
  {
    "path": "Language/[Java] wait notify notifyAll.md",
    "chars": 455,
    "preview": "#### Object 클래스 wait, notify, notifyAll\n\n----\n\nJava의 최상위 클래스 = Object 클래스\n\nObject Class 가 갖고 있는 메서드\n\n* toString()\n\n* has"
  },
  {
    "path": "Language/[Java] 직렬화(Serialization).md",
    "chars": 2826,
    "preview": "# [Java] 직렬화(Serialization)\n\n<br>\n\n```\n자바 시스템 내부에서 사용되는 객체 또는 데이터를 외부의 자바 시스템에서도 사용할 수 있도록 바이트(byte) 형태로 데이터 변환하는 기술\n```"
  },
  {
    "path": "Language/[Java] 컴포지션(Composition).md",
    "chars": 5220,
    "preview": "# [Java] 컴포지션(Composition)\n\n<br>\n\n```\n컴포지션 : 기존 클래스가 새로운 클래스의 구성요소가 되는 것\n상속(Inheritance)의 단점을 커버할 수 있는 컴포지션에 대해 알아보자\n```"
  },
  {
    "path": "Language/[Javascript] Closure.md",
    "chars": 9518,
    "preview": "# [Javascript] Closure\n\nclosure는 주변 state(lexical environment를 의미)에 대한 참조와 함께 묶인 함수의 조합이다. 다시말해서, closure는 inner functio"
  },
  {
    "path": "Language/[Javascript] ES2015+ 요약 정리.md",
    "chars": 9047,
    "preview": "# [Javascript] ES2015+ 요약 정리\n\n<br>\n\n<br>\n\n### ES2015+의 등장\n\n기존의 자바스크립트 문법에 다른 언어의 장점들을 더한 편리한 기능들이 많이 추가되었다. 이 중에  활용도가 높"
  },
  {
    "path": "Language/[Javascript] 데이터 타입.md",
    "chars": 1667,
    "preview": "\n# 데이터 타입\n\n자바스크립트의 데이터 타입은 크게 Primitive type, Structural Type, Structural Root Primitive 로 나눌 수 있다.\n\n- Primitive type\n  "
  },
  {
    "path": "Language/[Javasript] Object Prototype.md",
    "chars": 1220,
    "preview": "# Object Prototype\nPrototype은 JavaScript object가 다른 object에서 상속하는 매커니즘이다. \n\n## A prototype-based language?\nJavaScript는 종"
  },
  {
    "path": "Language/[Python] 매크로 라이브러리.md",
    "chars": 1145,
    "preview": "# 파이썬 매크로\n\n<br>\n\n### 설치\n\n```\npip install pyautogui\n\nimport pyautogui as pag\n```\n\n<br>\n\n### 마우스 명령\n\n마우스 커서 위치 좌표 추출\n\n```p"
  },
  {
    "path": "Language/[c] C언어 컴파일 과정.md",
    "chars": 897,
    "preview": "### C언어 컴파일 과정\n\n---\n\ngcc를 통해 C언어로 작성된 코드가 컴파일되는 과정을 알아보자\n\n<br>\n\n<img src=\"https://t1.daumcdn.net/cfile/tistory/254DB03A5"
  },
  {
    "path": "Language/[java] Call by value와 Call by reference.md",
    "chars": 4193,
    "preview": "## Call by value와 Call by reference\n\n<br>\n\n상당히 기본적인 질문이지만, 헷갈리기 쉬운 주제다.\n\n<br>\n\n#### call by value\n\n> 값에 의한 호출\n\n함수가 호출될 때"
  },
  {
    "path": "Language/[java] Casting(업캐스팅 & 다운캐스팅).md",
    "chars": 1569,
    "preview": "## Casting(업캐스팅 & 다운캐스팅)\n\n#### 캐스팅이란?\n\n> 변수가 원하는 정보를 다 갖고 있는 것\n\n```java\nint a = 0.1; // (1) 에러 발생 X\nint b = (int) true; "
  },
  {
    "path": "Language/[java] Java major feature changes.md",
    "chars": 1060,
    "preview": "> Java 버전별 변화 중 중요한 부분만 기록했습니다. 더 자세한건 참고의 링크를 봐주세요.\n\n## Java 8\n\n1. 함수형 프로그래밍 패러다임 적용\n    1. Lambda expression\n    2. St"
  },
  {
    "path": "Language/[java] Java에서의 Thread.md",
    "chars": 5464,
    "preview": "## Java에서의 Thread\n\n<br>\n\n요즘 OS는 모두 멀티태스킹을 지원한다.\n\n***멀티태스킹이란?***\n\n> 예를 들면, 컴퓨터로 음악을 들으면서 웹서핑도 하는 것\n>\n> 쉽게 말해서 두 가지 이상의 작업"
  },
  {
    "path": "Language/[java] Record.md",
    "chars": 1206,
    "preview": "# [Java] Record\n\n<br>\n\n<img src=\"https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblog.kakaoc"
  },
  {
    "path": "Language/[java] Stream.md",
    "chars": 3402,
    "preview": "# JAVA Stream\n\n> Java 8버전 이상부터는 Stream API를 지원한다\n\n<br>\n\n자바에서도 8버전 이상부터 람다를 사용한 함수형 프로그래밍이 가능해졌다.\n\n기존에 존재하던 Collection과 S"
  },
  {
    "path": "Language/[java] String StringBuilder StringBuffer 차이.md",
    "chars": 980,
    "preview": "### String, StringBuffer, StringBuilder\n\n----\n\n| 분류   | String    | StringBuffer                    | StringBuilder     "
  },
  {
    "path": "Language/[java] 자바 가상 머신(Java Virtual Machine).md",
    "chars": 2082,
    "preview": "## 자바 가상 머신(Java Virtual Machine)\n\n시스템 메모리를 관리하면서, 자바 기반 애플리케이션을 위해 이식 가능한 실행 환경을 제공함\n\n<br>\n\n<img src=\"http://www.itworl"
  },
  {
    "path": "Language/[java] 자바 컴파일 과정.md",
    "chars": 1573,
    "preview": "### 자바 컴파일과정\n\n---\n\n#### 들어가기전\n\n> 자바는 OS에 독립적인 특징을 가지고 있습니다. 그게 가능한 이유는 JVM(Java Vitual Machine) 덕분인데요. 그렇다면 JVM(Java Vit"
  },
  {
    "path": "Linux/Linux Basic Command.md",
    "chars": 1875,
    "preview": "## 리눅스 기본 명령어\n\n> 실무에서 자주 사용하는 명령어들\n\n<br>\n\n`shutdown`, `halt`, `init 0`, `poweroff` : 시스템 종료 \n\n`reboot`, `init 6`, `shutd"
  },
  {
    "path": "Linux/Permission.md",
    "chars": 2023,
    "preview": "## 퍼미션(Permisson) 활용\n\n<br>\n\n리눅스의 모든 파일과 디렉토리는 퍼미션들의 집합으로 구성되어있다.\n\n이러한 Permission은 시스템에 대한 읽기, 쓰기, 실행에 대한 접근 여부를 결정한다. (`"
  },
  {
    "path": "Linux/Von Neumann Architecture.md",
    "chars": 579,
    "preview": "## 폰 노이만 구조\n\n> 존 폰 노이만이 고안한 내장 메모리 순차처리 방식\n\n<br>\n\n프로그램과 데이터를 하나의 메모리에 저장하여 사용하는 방식\n\n데이터는 메모리에 읽거나 쓰는 것이 가능하지만, 명령어는 메모리에"
  },
  {
    "path": "New Technology/AI/Linear regression 실습.md",
    "chars": 4279,
    "preview": "### [딥러닝] Tensorflow로 간단한 Linear regression 알고리즘 구현\n\n<br>\n\n시험 점수를 예상해야 할 때 (0~100) > regression을 사용\n\nregression을 사용하는 예제"
  },
  {
    "path": "New Technology/AI/README.md",
    "chars": 1488,
    "preview": "### **AI/ML 용어 정리**\n\n---\n\n- **머신러닝:** 인공 지능의 한 분야로, 컴퓨터가 학습할 수 있도록 하는 알고리즘과 기술을 개발하는 분야입니다.\n- **데이터 마이닝:** 정형화된 데이터를 중심으"
  },
  {
    "path": "New Technology/Big Data/DBSCAN 클러스터링 알고리즘.md",
    "chars": 2094,
    "preview": "## DBSCAN 클러스터링 알고리즘\n\n> 여러 클러스터링 알고리즘 中 '밀도 방식'을 사용\n\nK-Means나 Hierarchical 클러스터링처럼 군집간의 거리를 이용해 클러스터링하는 방법이 아닌, 점이 몰려있는 "
  },
  {
    "path": "New Technology/Big Data/데이터 분석.md",
    "chars": 1907,
    "preview": "DataFrame을 만들어 다루기 위한 설치\n\n```\n>>> pip install pandas\n>>> pip install numpy\n>>> pip install matplotlib\n```\n\n> pandas : Da"
  },
  {
    "path": "New Technology/IT Issues/2020 ICT 이슈.md",
    "chars": 335,
    "preview": "## 2020 ICT 이슈\n\n> 2020 ICT 산업전망 컨퍼런스에서 선정된 이슈들\n\n<br>\n\n- 5G\n- 보호무역주의\n- AI\n- 규제\n- 모빌리티\n- 신남방, 신북방 정책\n- 구독경제\n- 반도체\n- 4차 산업혁"
  },
  {
    "path": "New Technology/IT Issues/AMD vs Intel.md",
    "chars": 3109,
    "preview": "## AMD와 Intel의 반백년 전쟁, 그리고 2020년의 '반도체'\n\n<br>\n\nAMD와 Intel은 잘 알려진 CPU 시장을 선도하고 있는 기업이다. 여태까지 Intel의 천하였다면, AMD가 빠르고 무서운 속"
  },
  {
    "path": "New Technology/IT Issues/README.md",
    "chars": 27,
    "preview": "# IT Issues\n\n최근 IT 이슈 동향 정리"
  },
  {
    "path": "New Technology/IT Issues/[2019.08.07] 이메일 공격 증가로 보안업계 대응 비상.md",
    "chars": 902,
    "preview": "## 이주의 IT 이슈 (19.08.07)\n\n### 이메일 공격 증가로 보안업계 대응 비상\n\n---\n\n> 올해 악성메일 탐지 건수 약 342,800건 예상 (SK인포섹 발표)\n>\n> 전년보다 2배 이상, 4년전보다 "
  },
  {
    "path": "New Technology/IT Issues/[2019.08.08] IT 수다 정리.md",
    "chars": 1238,
    "preview": "## [모닝 스터디] IT 수다 정리(19.08.08)\n\n1. ##### 쿠팡 서비스 오류\n\n   > 지난 7월 24일 오전 7시부터 쿠팡 판매 상품 재고가 모두 0으로 표시되는 오류 발생\n\n   재고 데이터베이스에"
  },
  {
    "path": "New Technology/IT Issues/[2019.08.20] Google, 크롬 브라우저에서 FTP 지원 중단 확정.md",
    "chars": 781,
    "preview": "## Google, 크롬 브라우저에서 FTP 지원 중단 확정\n\n<br>\n\n<img src=\"https://imgnews.pstatic.net/image/092/2019/08/19/0002168591_001_20190"
  },
  {
    "path": "README.md",
    "chars": 33663,
    "preview": "# tech-interview-for-developer\n\n[![Since](https://img.shields.io/badge/since-2019.03.01-333333.svg?style=flat-square)](h"
  },
  {
    "path": "Seminar/2019 삼성전자 비전캠프.md",
    "chars": 1061,
    "preview": "## [2019 삼성전자 비전캠프]\n\n#### 기업에 대해 새로 알게된 점\n\n------\n\n- 삼성전자 DS와 CE/IM은 완전히 다른 기업\n\n  그러므로, **반도체 공정을 돕는 데이터 분석**을 하고 싶다든지, "
  },
  {
    "path": "Seminar/2019 삼성전자 오픈소스 컨퍼런스(SOSCON).md",
    "chars": 783,
    "preview": "## 2019 SOSCON\n\n> 삼성전자 오픈소스 컨퍼런스\n\n2019.10.16~17 ( 삼성전자 R&D 캠퍼스 )\n\n<br>\n\n#### 삼성전자 오픈소스 추진 현황\n\n- 2002 : PDA\n- 2009 : Gala"
  },
  {
    "path": "Seminar/NCSOFT 2019 JOB Cafe.md",
    "chars": 364,
    "preview": "### 2019-10-02 NCSOFT JOB Cafe\n\n---\n\n- Micro Service Architecture 사용\n- 사용하는 언어와 프레임워크는 다양 (C++ 기반 자사 제품도 사용)\n- NC Test\n "
  },
  {
    "path": "Seminar/NHN 2019 OPEN TALK DAY.md",
    "chars": 4842,
    "preview": "## NHN 2019 OPEN TALK DAY\n\n> 2019.08.29\n\n#### ※ NHN 주요 사업\n\n1. **TOAST** : 국내 클라우드 서비스\n2. **PAYCO** : 간편결제 핀테크 플랫폼\n3. **한"
  },
  {
    "path": "Web/CSR & SSR.md",
    "chars": 1655,
    "preview": "## CSR & SSR\n\n<br>\n\n> CSR : Client Side Rendering\n>\n> SSR : Server Side Rendering\n\n<br>\n\nCSR에는 모바일 시대에 들어서 SPA가 등장했다.\n\n#"
  },
  {
    "path": "Web/CSRF & XSS.md",
    "chars": 2572,
    "preview": "# CSRF & XSS\n\n<br>\n\n### CSRF\n\n> Cross Site Request Forgery\n\n웹 어플리케이션 취약점 중 하나로, 인터넷 사용자가 자신의 의지와는 무관하게 공격자가 의도한 행위 (modi"
  },
  {
    "path": "Web/Cookie & Session.md",
    "chars": 1046,
    "preview": "## Cookie & Session\n\n\n\n|          |                        Cookie                        |     Session      |\n| :------:"
  },
  {
    "path": "Web/DevOps/[AWS] 스프링 부트 배포 스크립트 생성.md",
    "chars": 3522,
    "preview": "# [AWS] 스프링 부트 배포 스크립트 생성\n\n<br>\n\n<img src=\"https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fb"
  },
  {
    "path": "Web/DevOps/[Travis CI] 프로젝트 연동하기.md",
    "chars": 2620,
    "preview": "# [Travis CI] 프로젝트 연동하기\n\n<br>\n\n<img src=\"https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fblo"
  },
  {
    "path": "Web/DevOps/시스템 규모 확장.md",
    "chars": 2808,
    "preview": "# 시스템 규모 확장\n\n<br>\n\n```\n시스템 사용자 수에 따라 설계해야 하는 규모가 달라진다.\n수백만의 이용자가 존재하는 시스템을 개발해야 한다면, 어떤 것들을 고려해야 할 지 알아보자\n```\n\n<br>\n\n1. "
  },
  {
    "path": "Web/HTTP Request Methods.md",
    "chars": 1301,
    "preview": "# HTTP Request Methods\n\n<br>\n\n```\n클라이언트가 웹서버에게 요청하는 목적 및 그 종류를 알리는 수단을 말한다.\n```\n\n<br>\n\n<img src=\"https://qph.cf2.quoracd"
  },
  {
    "path": "Web/HTTP status code.md",
    "chars": 1926,
    "preview": "## HTTP status code\n\n> 클라우드 환경에서 HTTP API를 통해 통신하는 것이 대부분임\n>\n> 이때, 응답 상태 코드를 통해 성공/실패 여부를 확인할 수 있으므로 API 문서를 작성할 때 꼭 알아야"
  },
  {
    "path": "Web/JWT(JSON Web Token).md",
    "chars": 2710,
    "preview": "# JWT (JSON Web Token)\n```\nJSON Web Tokens are an open, industry standard [RFC 7519]\nmethod for representing claims secu"
  },
  {
    "path": "Web/Logging Level.md",
    "chars": 582,
    "preview": "## Logging Level\n\n<br>\n\n보통 log4j 라이브러리를 활용한다.\n\n크게 ERROR, WARN, INFO, DEBUG로 로그 레벨을 나누어 작성한다.\n\n<br>\n\n- #### ERROR\n\n  에러 로"
  },
  {
    "path": "Web/Nuxt.js.md",
    "chars": 1603,
    "preview": "# Nuxt.js\n\n<img src=\"https://t1.daumcdn.net/cfile/tistory/990CB73A5AF842A422\">\n\n<br>\n\n> vue.js를 서버에서 렌더링할 수 있도록 도와주는 오픈소"
  },
  {
    "path": "Web/OAuth.md",
    "chars": 916,
    "preview": "## OAuth\n\n> Open Authorization\n\n인터넷 사용자들이 비밀번호를 제공하지 않고, 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수있는 개방형 표준 방법\n\n"
  },
  {
    "path": "Web/PWA (Progressive Web App).md",
    "chars": 631,
    "preview": "### PWA (Progressive Web App)\n\n> 웹의 장점과 앱의 장점을 결합한 환경\n>\n> `앱 수준과 같은 사용자 경험을 웹에서 제공하는 것이 목적!`\n\n<br>\n\n#### 특징\n\n확장성이 좋고, 깊이"
  },
  {
    "path": "Web/README.md",
    "chars": 2041,
    "preview": "## Web\n\n- [브라우저 동작 방법](https://github.com/kim6394/tech-interview-for-developer/blob/master/Web/%EB%B8%8C%EB%9D%BC%EC%9A%"
  },
  {
    "path": "Web/React/React & Spring Boot 연동하여 환경 구축하기.md",
    "chars": 7650,
    "preview": "## React & Spring Boot 연동해보기!\n\n<img src=\"https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=https%3A%2F%2Fk.k"
  },
  {
    "path": "Web/React/React Fragment.md",
    "chars": 1775,
    "preview": "# [React] Fragment\n\n<br>\n\n```\nJSX 파일 규칙상 return 시 하나의 태그로 묶어야한다.\n이런 상황에 Fragment를 사용하면 쉽게 그룹화가 가능하다.\n```\n\n<br>\n\n아래와 같이 T"
  },
  {
    "path": "Web/React/React Hook.md",
    "chars": 1087,
    "preview": "# React Hook \n\n> useState(), useEffect() 정의\n\n<img src=\"https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&fname=htt"
  },
  {
    "path": "Web/Spring/JPA.md",
    "chars": 1690,
    "preview": "#  JPA\n\n> Java Persistence API\n\n<br>\n\n```\n개발자가 직접 SQL을 작성하지 않고, JPA API를 활용해 DB를 저장하고 관리할 수 있다.\n```\n\n<br>\n\nJPA는 오늘날 스프링에"
  },
  {
    "path": "Web/Spring/Spring MVC.md",
    "chars": 1649,
    "preview": "# Spring MVC Framework\n\n<br>\n\n```\n스프링 MVC 프레임워크가 동작하는 원리를 이해하고 있어야 한다\n```\n\n<br>\n\n<img src=\"https://media.vlpt.us/images/"
  },
  {
    "path": "Web/Spring/Spring Security - Authentication and Authorization.md",
    "chars": 2707,
    "preview": "# Spring Security - Authentication and Authorization\n\n<br>\n\n```\nAPI에 권한 기능이 없으면, 아무나 회원 정보를 조회하고 수정하고 삭제할 수 있다. 따라서 이를 막"
  },
  {
    "path": "Web/Spring/[Spring Boot] SpringApplication.md",
    "chars": 718,
    "preview": "## [Spring Boot] SpringApplication\n\n<br>\n\n스프링 부트로 프로젝트를 실행할 때 Application 클래스를 만든다.\n\n클래스명은 개발자가 프로젝트에 맞게 설정할 수 있지만, 큰 틀은"
  },
  {
    "path": "Web/Spring/[Spring Boot] Test Code.md",
    "chars": 2400,
    "preview": "# [Spring Boot] Test Code\n\n<br>\n\n#### 테스트 코드를 작성해야 하는 이유\n\n- 개발단계 초기에 문제를 발견할 수 있음\n- 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 시 기존 기능이"
  },
  {
    "path": "Web/Spring/[Spring Data JPA] 더티 체킹 (Dirty Checking).md",
    "chars": 1752,
    "preview": "# [JPA] 더티 체킹 (Dirty Checking)\n\n<br>\n\n\n```\n트랜잭션 안에서 Entity의 변경이 일어났을 때\n변경한 내용을 자동으로 DB에 반영하는 것\n```\n\n<br>\n\nORM 구현체 개발 시 더"
  }
]

// ... and 14 more files (download for full content)

About this extraction

This page contains the full source code of the MangKyu/tech-interview-for-developer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 214 files (513.8 KB), approximately 233.2k tokens, and a symbol index with 73 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!