├── DataStructure ├── Array │ ├── Array.md │ └── shift.png ├── LinkedList │ ├── LinkedList.md │ ├── Singly_linked_list.png │ ├── circular.png │ ├── doubly-linked-delete.png │ ├── doubly-linked-insert.png │ ├── doubly-linked-list.png │ └── head-tail.png ├── Map │ ├── Maps.md │ ├── hashtable-timecomlexity.png │ ├── hashtable.png │ ├── linear-probing.png │ └── separate.png ├── StackAndQueue │ ├── Lifo_stack.png │ ├── PriorityQueue.md │ ├── Queue.md │ ├── Stack.md │ ├── compare_unsorted.png │ ├── deque.jpeg │ ├── queue-data.png │ └── queue.png └── Tree │ ├── Heap.md │ ├── Tree.md │ ├── array-based-tree.jpeg │ ├── bfs.jpeg │ ├── catalan.png │ ├── inorder.jpeg │ ├── linked-binary-tree.jpeg │ ├── log2.svg │ ├── max-heap.png │ ├── postorder.jpeg │ ├── preorder.jpeg │ ├── travel.jpeg │ └── tree.jpeg ├── Interview ├── question │ ├── previous_interview.md │ ├── sorting.png │ ├── week1.md │ ├── week2.md │ └── week3.md └── sorting │ ├── bubleSort.js │ ├── heapSort.js │ ├── insertionSort.js │ ├── mergeSort.js │ ├── quickSort.js │ └── selectionSort.js ├── Network ├── IPAndDNS.md ├── WebBrowser.md └── images │ ├── http.png │ └── ipv4.png ├── OS ├── CPUScheduling.md ├── Deadlock.md ├── Memory.md ├── ProcessAndThread.md ├── Synchronization.md ├── WhatIsOS.md └── images │ ├── FCFS.png │ ├── buddy.png │ ├── budy-example.jpeg │ ├── components-of-os.png │ ├── dining.png │ ├── disk.png │ ├── edf.svg │ ├── fair.png │ ├── memory-fit.png │ ├── monitor.png │ ├── rm.png │ ├── round-robin.png │ ├── sequencer.png │ ├── status.png │ ├── system-call.png │ └── unsafe.png └── README.md /DataStructure/Array/Array.md: -------------------------------------------------------------------------------- 1 | # Array 2 | - 같은 자료형을 가진 `연속된 메모리 공간`으로 이루어진 자료구조 3 | - Array의 첫번째 Element의 주소값이 Array의 이름이 되며 이를 `first address` 혹은 `foundation address`라고 부르고 이 주소값을 통해 Array를 이용할 수 있다. 4 | - Index를 통한 Random access가 가능하므로 Constant Time `O(1)`에 접근이 가능하다. 5 | - 메모리의 지역성을 보이므로 loop등 반복적으로 접근해야 할 경우 이점이 있다. 6 | 7 | ## Static Array 8 | - Array의 크기는 처음 생성 될 때 정해진다. 9 | - Static Array는 생성 될 때 고정 된 크기를 가지므로 일반적으로 Element를 insert하거나 delete 할 수 없다. 10 | 11 | ## Dynamic Array 12 | - 일반적으로 필요한 size보다 큰 Static Array를 만들어쓰는 방식으로 Dynamic Array를 구성 할 수 있다. 13 | - 단순히 Static Array의 size를 필요한 size보다 크게 만든다고 Dynamic Array가 되는 것은 아님 14 | - size는 Element가 적재되어 있는 논리적 크기인 `size`와 최대 이용가능한 물리적 size인 `capacity`로 나누어 볼 수 있다. 15 | - Dynamic Array에서 더 큰 capacity의 Array의 필요성이 생기면 더 큰 capacity의 Static Array를 새로 만들어 기존에 있던 배열을 통째로 복사해 옮기는 방식으로 capacity를 늘린다.(e.g. Java ArrayList) 16 | 17 | ## Dynamic Array에서의 Insert / Delete 18 | - ![Dynamic Array Insert](./shift.png) 19 | - Array는 연속된 메모리 공간에 저장되어 있다는 특성을 가지고 있으므로 Insert와 Delete시에 `Shift`가 일어난다. 20 | - 중간, 혹은 맨 처음에 Element Insert시 삽입될 위치와 뒤에있는 Element들이 메모리 주소상 뒤로 1칸씩 밀려야하므로 `O(n)`의 시간 복잡도가 필요하다. 21 | - Delete의 경우도 비슷한데 delete된 Element 뒤에 있는 Element들이 메모리 주소상 앞으로 1칸씩 당겨져야 하므로 `O(n)`의 시간 복잡도가 필요하다. 22 | - 단, 배열의 맨 뒤에 Insert / Delete하는 경우 Shift될 Element들이 존재하지 않으므로 `O(1)`의 시간 복잡도가 필요하다. 23 | -------------------------------------------------------------------------------- /DataStructure/Array/shift.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Array/shift.png -------------------------------------------------------------------------------- /DataStructure/LinkedList/LinkedList.md: -------------------------------------------------------------------------------- 1 | # Linked Lists 2 | - Linked List는 각 노드가 데이터와 포인터를 가지고 한 줄로 연결되어 있는 방식으로 데이터를 저장하는 자료 구조이다. 3 | - Array처럼 고정된 크기를 가지고 있지 않다. 4 | - Array처럼 데이터가 물리적으로 연속되어 연결되어 있지 않다. 5 | - 데이터 이외에 메모리 주소를 저장해야하므로 추가 메모리 공간이 필요하다. 6 | - Insert/delete가 Linked List의 중간에 자주 일어난다면 Array보다 Linked List를 이용하는 것이 유리하다. 7 | Linked List에서의 Insert/Delete는 포인터를 이용하기만 하면 되지만 Array는 Insert/Delete가 일어날 경우 실제 메모리에서 데이터의 Shift가 일어나기 때문 8 | 9 | ## Singly Linked List 10 | - ![Singly linked list - wikipedia](./Singly_linked_list.png) 11 | - Singly Linked List에서 각각의 Node는 자료와 다음 Node를 가르키는 포인터(Next)로 구성되어 있다. 12 | - ![Head and Tail - DataStructure and Algorithm in Java, 6th Edition](./head-tail.png) 13 | - `Head`는 Linked List의 첫 Node에 대한 포인터를 가지고 있다. 만약 Head가 가르키는 Node가 없다면 이를 통해 다른 Node를 찾을 방법이 없게된다. 14 | - `Tail`은 Linked List이 마지막 Node에 대한 포인터를 가지고 있다. 15 | - Tail은 Head부터 다음 Node로 탐색을 진행하며 Next가 `Null`인 Node를 찾음으로써 찾아낼 수 있다. (이렇게 Tail을 찾아내는 것을 link hopping이라고 함) 16 | - 일반적으로 Linked List에 Tail을 저장해 두어 매번 Tail을 찾는 탐색과정을 거치지 않게 한다. 17 | - Linked List의 size(length)또한 저장하고 유지하는 것이 일반적이다. 18 | - 특정 Node를 찾기 위해서는 Head부터 순차적인 탐색이 필요하다. Time complexity `O(n)` 19 | 20 | ### Singly Linked List 구현 21 | #### Insert 22 | - addFirst(e) -> 첫번째 위치에 Node 추가 23 | - Time complexity `O(1)` 24 | ``` 25 | Algorithm addFirst(e): 26 | newest = Node(e) ;; Node를 새로 만들고 newest에 저장 27 | newest.next = head ;; newest의 next가 현재 head인 Node를 가리키도록 함 28 | head = newest ;; head가 새로운 Node를 가리키도록 함 29 | size = size + 1 ;; size를 1 증가시킨다 30 | ``` 31 | 32 | - addLast(e) -> 마지막 위치에 Node 추가 33 | - Time complexity `O(1)` 34 | ``` 35 | Algorithm addLast(e): 36 | newest = Node(e) ;; Node를 새로 만들고 newest에 저장 37 | newest.next = null ;; newest의 next가 tail되어야 하므로 null을 가리키도록 함 38 | tail.next = newest ;; 현 시점의 tail의 next가 newest를 가리키도록 함 39 | tail = newest ;; tail이 새로운 Node를 가리키도록 함 40 | size = size + 1 ;; size를 1 증가시킨다 41 | ``` 42 | 43 | - addBetween(e) -> 중간에 Node 추가 44 | - Time complexity `O(n)` 45 | - 탐색 시간 `O(n)` + insert하는 시간 `O(1)` = `O(n)` 46 | ``` 47 | Algorithm addBetween(e, current): ;; 현재 위치 뒤에 Node 삽입 48 | newest = Node(e) ;; Node를 새로 만들고 newest에 저장 49 | newest.next = current.next ;; 새로운 Node의 next가 현재 위치의 다음 Node를 가리키도록 함 50 | current.next = newest ;; 현재 위치의 Node의 next가 새로운 Node를 가리키도록 함 51 | size = size + 1 52 | ``` 53 | 54 | #### Remove 55 | - removeFirst() -> 첫번째 Node 삭제 56 | - Time complexity `O(1)` 57 | ``` 58 | Algorithm removeFirst() 59 | if head == null then 60 | the list is empty. 61 | head = head.next = head를 Head다음 Node로 지정 62 | size = size - 1 63 | ``` 64 | 65 | - removeBetween(current) -> 중간 Node 삭제 66 | - 탐색 시간 `O(n)` + delete하는 시간 `O(1)` = `O(n)` 67 | ``` 68 | Algorithm removeBetween(current) 69 | if head == null then 70 | the list is empty. 71 | before.next = current.next ;; current까지 탐색하는 과정에서 before도 알 수 있다. 72 | current = before 73 | size = size - 1 74 | ``` 75 | 76 | ## Circular Linked List 77 | - ![Circular Linked List - DataStructure and Algorithm in Java, 6th Edition](./circular.png) 78 | - 기본적으로 Single Linked List와 거의 동일하지만 `Tail.next`가 다시 `head`를 가리킨다는 것이 다르다. 79 | - 실제 Application에서는 cycle order를 이용할 필요가 생기기 때문 (Round robin schedule, 보드게임 사용자 턴) 80 | - 한번의 탐색 과정에서 previous node로의 접근이 가능해진다. (Singly Linked list는 head부터 재탐색 해야 함) 81 | - 이렇게 linked list에 cycle이 생기면 head와 tail을 구분할 필요가 없지만 필요에따라 구현해도 좋다. 82 | - `rotate()`라는 것을 이용해 tail의 position을 옮길 수 있음 83 | ``` 84 | Algorithm rotate() 85 | if tail == null then 86 | the list is empty. 87 | tail = tail.next 88 | ``` 89 | 90 | ## Doubly Linked List 91 | - ![Doubly Linked List - DataStructure and Algorithm in Java, 6th Edition](./doubly-linked-list.png) 92 | - Node에 next이외에 추가로 previous Node에대한 포인터를 저장함으로써 이전 Node에 접근이 가능하게 만든 Linked List 93 | - Previous Node의 주소를 저장해야해서 Singly Linked List보다 메모리를 더 사용한다. 94 | 95 | ### Doubly Linked List 구현 96 | #### Insert 97 | - ![Doubly Linked List Insert - DataStructure and Algorithm in Java, 6th Edition](./doubly-linked-insert.png) 98 | 99 | ``` 100 | Algorithm insertNode(e, current): ;; 현재위치 바로뒤에 삽입 101 | newest = Node(e) ;; 새로운 Node 생성 102 | newest.next = current.next ;; 새로운 Node의 next를 현재 위치 Node의 다음 Node를 가리키도록 103 | current.next = newest ;; 현재 위치의 Node의 next가 새로운 Node를 가르키도록 104 | newest.prev = current ;; 새로운 Node의 prev가 현재 위치 Node를 가르키도록 105 | if newest.next != null then 106 | newest.next.prev = newest ;; 현재 위치 다음 Node의 prev가 새로운 Node를 가르키도록 107 | ``` 108 | 109 | #### Delete 110 | - ![Doubly Linked List Delete - DataStructure and Algorithm in Java, 6th Edition](./doubly-linked-delete.png) 111 | 112 | ``` 113 | Algorithm deleteNode(current): 114 | current.prev.next = current.next 115 | current.next.prev = current.prev 116 | ``` 117 | -------------------------------------------------------------------------------- /DataStructure/LinkedList/Singly_linked_list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/LinkedList/Singly_linked_list.png -------------------------------------------------------------------------------- /DataStructure/LinkedList/circular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/LinkedList/circular.png -------------------------------------------------------------------------------- /DataStructure/LinkedList/doubly-linked-delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/LinkedList/doubly-linked-delete.png -------------------------------------------------------------------------------- /DataStructure/LinkedList/doubly-linked-insert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/LinkedList/doubly-linked-insert.png -------------------------------------------------------------------------------- /DataStructure/LinkedList/doubly-linked-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/LinkedList/doubly-linked-list.png -------------------------------------------------------------------------------- /DataStructure/LinkedList/head-tail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/LinkedList/head-tail.png -------------------------------------------------------------------------------- /DataStructure/Map/Maps.md: -------------------------------------------------------------------------------- 1 | # Maps(or associative arrays) 2 | - Map은 Unique한 search Key를 기반으로 값을 효율적으로 저장하고 검색하도록 설계된 Abstract Data Type이다. 3 | - 고유한(Unique) 값의 key `k`와 k에 대응되는 value `v`가 한 쌍으로 map에 저장된다. 4 | - Map은 고유한 key값을 가지는 점에서 array의 index와 유사한 특징을 가지고 있기 때문에 `associative arrays`라고 하기도 한다. 하지만 기본적인 array와는 다르게 key값이 꼭 숫자일 필요는 없으며 5 | array의 index처럼 key값이 data 구조 내의 위치를 지정하지도 않는다. 6 | 7 | ## Hash Table 8 | ![hash table](./hashtable.png) 9 | - Hash Table은 Map의 ADT를 구현해 만든 자료구조이다. 10 | - 더 자세한 설명이 필요하면 이 [블로그](https://ratsgo.github.io/data%20structure&algorithm/2017/10/25/hash/)를 참고 11 | - 기본 적인 개념은 `hash function`을 이용해 array에 저장 될 index를 구하고 value를 저장한다. 12 | - `index = hashFunction(key) % sizeOfArray` 13 | - hash function 한 번만 계산해주면 바로 index를 알 수 있기 때문에 데이터의 저장과 삭제가 매우 빠르다. 14 | 15 | ### Hash Function 16 | - Hash function은 각 Key `k`를 [0, N-1] 범위의 정수(array의 index)로 바꿔주는 함수이다. (N 사이즈의 array에 저장 할 수 있도록) 17 | - 동일한 hash 값을 가진 두 개 이상의 키가 있는 경우 `collision(충돌)`이 발생 할 수 있다. 18 | - 이러한 충돌이 되도록 발생하지 않도록 정해진 범위 내의 hash 값을 고르게 만들어 줄 수 있는 Hash function이 좋은 Hash function이다. 19 | - Hash function은 `hash code`와 `compression function(압축 함수)` 두가지 부분으로 나눌 수 있다. 20 | - Hash code 21 | - Key값을 정수로 바꿔주는 부분 22 | - compression function 23 | - hash code를 정해진 범위 내의 숫자로 바꿔주는 부분 (배열의 크기 이내 등) 24 | - 단순히 나머지를 이용해 구할 수 있다. `i Mod N`이, N이 소수일 경우 충돌을 좀 더 줄일 수 있다. 25 | - 또 한가지 방법은 `Multiply-Add-and-Divide(MAD)`방식을 사용하는 것이다. 26 | - `[(ai+b) mod p] mod N`, p는 N보다 큰 소수이며, a와 b는 [0, p-1]범위 내의 무작위 두 수이며 a > 0이다. 이 방식은 충돌 확률을 `1/N`에 가깝게 되도록 만들어 준다. 27 | - 두가지 부분으로 나누었을 때 이점은, hash code가 테이블의 크기에 독립적으로 관리될 수 있기 때문이다. 28 | - compression function만 바꾸어주면 hash code를 변경하지 않고 동적으로 해시 테이블에 이용된 기본 array의 크기를 바꿀 수 있다. 29 | 30 | ### Collision-Handling 31 | - 동일한 Hash 값을 가진 key가 생기면 저장할 때 collision이 생긴다. 이를 해결하는 법을 알아보자 32 | 33 | #### Separate Chaining 34 | ![separate chaining](./separate.png) 35 | - Array의 각 index가 Linked list의 포인터를 가지는 방식 36 | - 동일한 index로 인해 collision이 발생하면 해당 index가 가리키고 있는 Linked list에 노드를 추가하여 값을 추가. 37 | - 데이터를 검색할 때는 Key값으로 index를 찾고 해당 index가 가리키고 있는 Linkded list에서 key값으로 알맞은 node를 탐색한다. 38 | - 이 방법은 키가 있는 항목들을 유지하기 위해 추가 공간이 필요하므로 공간 제약이 있는 경우 알맞지 않다. (각 index별로 linked list를 가리키는 포인터를 가지게 되므로) 39 | 40 | #### Open Addressing 41 | - Spearate Chaning과는 다르게 추가적인 공간을 사용하지 않고 hash table array의 빈 공간을 이용하는 방법 42 | - Open Addressing을 구현하는 방법은 여러가지가 있지만 가장 간단한 것은 `Linear Probing`이다. 43 | 44 | ##### Linear Probing 45 | ![linear probing](./linear-probing.png) 46 | - collision이 일어나면 정해진 고정된 계수만큼 index를 건너 뛰며 빈 공간에 값을 할당하는 방식 47 | - 이러한 방식 때문에 같은 hash 값에 데이터가 몰리면 성능이 떨어진다. 48 | - 삭제와 탐색을 진행할 때 고려해야될 문제들이 있다. 49 | - 탐색을 진행 할 때 원하는 값을 찾기 위해서 hash function으로 index를 찾고 원하는 값이 나올때 까지 고정된 계수만큼 index를 건너뛰며 탐색을 한다. 이때 원하는 값을 찾거나 빈 공간을 찾으면 탐색이 끝난다. 50 | - 빈 공간을 찾으면 탐색이 끝나는 이유는 collision이 일어났으면 특정 값을 찾을 때 까지 빈 공간이 나오면 안되기 때문이다. 물론 이 경우는 원하는 값을 찾지 못한 경우이다. 51 | - 삭제시에는 탐색과 마찬가지로 진행되지만 원하는 값을 찾은 경우 값을 지우는 대신 `Dummy Data`로 교체한다. 왜냐하면 탐색은 빈 공간을 찾을 경우에도 끝나므로 탐색을 원하는 값이 저장되어있음에도 빈 공간 때문에 탐색이 실패할 수 있기 때문이다. 52 | - 즉 Dummy Data는 탐색을 계속 이어나갈 수 있게 해준다. 53 | - 저장과 삭제가 빈번히 일어나게 되면 Dummy Data들이 쌓이게되고 가령 Dummy Data가 없다고 하더라도 저장과 삭제시에 탐색에 걸리는 시간이 증가하므로 어느정도 Hash Table array가 찼다면 Hash Table에 이용되는 array의 크기를 늘려주면서 기존 값들을 `Rehashing` 해주는 것이 성능 향상에 좋다 54 | 55 | ### Time complexity 56 | ![hashtable-timecomplexity](./hashtable-timecomlexity.png) 57 | - Open Addressing 혹은 Separate Chaining의 Worst case는 모든 key값이 같은 index에 저장되는 것이므로 `O(n)`이다. 58 | -------------------------------------------------------------------------------- /DataStructure/Map/hashtable-timecomlexity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Map/hashtable-timecomlexity.png -------------------------------------------------------------------------------- /DataStructure/Map/hashtable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Map/hashtable.png -------------------------------------------------------------------------------- /DataStructure/Map/linear-probing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Map/linear-probing.png -------------------------------------------------------------------------------- /DataStructure/Map/separate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Map/separate.png -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/Lifo_stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/StackAndQueue/Lifo_stack.png -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/PriorityQueue.md: -------------------------------------------------------------------------------- 1 | # Priority Queue 2 | - 이름은 Queue이지만 FIFO를 따르지 않는다. 삽입 순서는 상관 없지만 제거시엔 Priority가 가장 높은 Entry부터 제거해나간다. 3 | - 우선순위를 나타내는 Key를 Element와 함께 저장하여(`Entry`) Key로 priority를 구별한다. 4 | 5 | ## ADT 6 | - insert(k, v): Key k와 Value v를 갖는 entry를 만들어 priority queue에 삽입 7 | - min(): Minimal priority key를 가지는 entry를 반환하며 제거는 하지 않음 (만약 큐가 비어있다면 null 반환) 8 | - removeMin(): Minimal priority key를 가지는 entry를 반환하고 제거 (만약 큐가 비어있다면 null 반환) 9 | - size(): Priority Queue의 entry의 개수 반환 10 | - isEmpty(): Priority Queue가 비어있는지 확인 11 | 12 | ## 구현 13 | ### Unsorted List로 구현 14 | ``` java 15 | public class UnsortedPriorityQueue extends AbstractPriorityQueue { 16 | private PositionalList> list = new LinkedPositionalList<>(); 17 | public UnsortedPriorityQueue() { super(); } 18 | public UnsortedPriorityQueue(Comparator comp) { super(comp); } 19 | 20 | private Position> findMin() { // Big-O O(n) 21 | Position> small = list.first(); 22 | for (Position> walk : list.positions()) 23 | if (compare(walk.getElement(), small.getElement()) < 0) 24 | small = walk; // found an even smaller key 25 | return small; 26 | } 27 | 28 | public Entry insert(K key, V value) throws IllegalArgumentException { // Big-O O(1) 29 | checkKey(key); // auxiliary key-checking method (could throw exception) 30 | Entry newest = new PQEntry<>(key, value); 31 | list.addLast(newest); 32 | return newest; 33 | } 34 | public Entry min() { // Big-O O(n) 35 | if (list.isEmpty()) return null; 36 | return findMin().getElement(); 37 | } 38 | public Entry removeMin() { // Big-O O(n) 39 | if (list.isEmpty()) return null; 40 | return list.remove(findMin()); 41 | } 42 | public int size() { return list.size(); } // Big-O O(1) 43 | } 44 | ``` 45 | ### Sorted List로 구현 46 | 47 | ``` java 48 | public class SortedPriorityQueue extends AbstractPriorityQueue { 49 | private PositionalList> list = new LinkedPositionalList<>(); 50 | 51 | public SortedPriorityQueue() { super(); } 52 | public SortedPriorityQueue(Comparator comp) { super(comp); } 53 | 54 | public Entry insert(K key, V value) throws IllegalArgumentException { 55 | checkKey(key); 56 | Entry newest = new PQEntry<>(key, value); 57 | Position> walk = list.last(); 58 | // Doubly Linked List로 구현하여 last node부터 거꾸로 탐색해 insert가 용이하도록 구현한다. 59 | while (walk != null && compare(newest, walk.getElement()) < 0) 60 | walk = list.before(walk); 61 | if (walk == null) 62 | list.addFirst(newest); 63 | else 64 | list.addAfter(walk, newest); 65 | return newest; 66 | } 67 | 68 | public Entry min() { 69 | if (list.isEmpty()) return null; 70 | return list.first().getElement(); 71 | } 72 | 73 | public Entry removeMin() { 74 | if (list.isEmpty()) return null; 75 | return list.remove(list.first()); 76 | } 77 | 78 | public int size() { return list.size(); } 79 | } 80 | ``` 81 | 82 | ### Unsorted List와 Sorted List로 구현한 Priority Queue의 차이 83 | ![](./compare_unsorted.png) 84 | - Unsorted List는 정렬된 순서가 없기 때문에 특정 규칙을 따를 필요 없이 Linked List의 마지막에 node를 추가하므로 빠르다 `O(1)` 85 | - Unsorted List는 정렬된 순서가 없어 가장 높은 priority의 Entry를 찾기 위해선 모든 node를 탐색해야 하므로 `O(n)` 86 | - Sorted List는 정렬된 순서를 가지고 있기 때문에 Priority가 가장 높은 Entry가 List의 항상 처음에 존재하므로 제거가 빠르다 `O(1)` 87 | - Sorted List는 정렬된 순서를 가지고 있어 삽입을 하려면 올바른 위치를 찾아야 하므로 모든 노드를 탐색해야 할 수도 있다 `O(n)` 88 | 89 | ### Heap으로 구현 90 | - priority가 높거나 낮은 Node부터 제거해야하는 `Priority Queue` 특성상 Heap과 유사한 속성을 가지고 있다. 91 | - 때문에 대부분의 Priority Queue는 Heap으로 구현됨. 92 | - 자세한 내용은 [Heap](../Tree/Heap.md) 참고 93 | -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/Queue.md: -------------------------------------------------------------------------------- 1 | # Queue 2 | - ![queue](./queue.png) 3 | - Queue는 FIFO(First-In, First-Out) 방식으로 삽입되고 제거되는 자료구조이다. 4 | - 놀이공원에서 줄을서거나, 콜센터에서 전화를 받는 방식이 이와 비슷하다. 5 | - ADT(Abstract Data Type) 6 | - enqueue(e): Queue의 맨 뒤에 Element를 추가한다. 7 | - dequeue(): Queue의 맨 앞에있는 Element를 제거하면서 해당 값을 return한다. (Queue가 비어있으면 null을 return) 8 | - first(): Queue의 첫번째 Element를 return한다. 9 | - size(): Queue에 있는 Element 개수를 return한다. 10 | - isEmpty(): Queue가 비어있는지 확인한다. (Boolean) 11 | 12 | ## Array로 구현한 Queue 13 | - Array로 Queue의 enqueue와 dequeue를 구현할 때 쉽게 생각할 수 있는 방법으로는 14 | - enqueue: array의 index를 1씩 늘려가며 추가 15 | - dequeue: dequeue시마다 array[0]를 return, remove해주며 data들을 왼쪽으로 한칸씩 shift 16 | - enqueue는 문제가 없지만 dequeue마다 모든 element의 이동이 필요하므로 `O(n)`의 시간 복잡도를 가진다. 17 | - 개선 할 수 없을까? 18 | - 그럼 element를 shift하지 않고 queue의 first element에 해당하는 index를 따로 저장하자 19 | - enqueue: 아까와 동일 20 | - dequeue: first element의 index를 알고 있으므로 `O(1)`의 시간 복잡도를 가진다. 21 | - 문제점이 또 하나 있다. Array는 capacity가 정해져 있으므로 enqueue와 dequeue가 반복될 수록 22 | 사용할 수 있는 공간이 점점 줄어든다. (enqueue 할 때 index를 늘리기만 하므로) 23 | - ![enqueue 한계](./queue-data.png) 24 | - 그럼 enqeue또한 바꿔보자 25 | - Array를 circular하게 이용하기 26 | - Array가 가득차면 다시 Array의 첫 index부터 enqueue를 한다. 27 | - first element의 index를 따로 저장하고 있으니 어떤 element가 첫번째인지 햇갈릴 일은 없다. 28 | ``` java 29 | public class ArrayQueue implements Queue { 30 | public static final int CAPACITY = 1000; 31 | private E[] data; 32 | private int f = 0; 33 | private int sz = 0; 34 | 35 | public ArrayQueue() {this(CAPACITY);} 36 | public ArratQueue(int capacity) { 37 | data = (E[]) new Object[capacity]; 38 | } 39 | 40 | public int size() { return sz; } 41 | public boolean isEmpty() { return (sz == 0); } 42 | 43 | public void enqueue(E e) throws IllegalStateException {// Time Comlexity O(1) 44 | if (sz === data.length) throw new IllegalStateException("Queue is full"); 45 | int avail = (f + sz) % data.length; 46 | data[avail] = e; 47 | sz++; 48 | } 49 | 50 | public E first() { 51 | if (isEmpty()) return null; 52 | return data[f]; 53 | } 54 | 55 | public E dequeue() {// Time Comlexity O(1) 56 | if (isEmpty()) return null; 57 | E answer = data[f]; 58 | data[f] = null; 59 | f = (f + 1) % data.length; 60 | sz--; 61 | return answer; 62 | } 63 | } 64 | ``` 65 | 66 | ## Linked-List로 구현한 Queue 67 | ``` java 68 | public class LinkedQueue implements Queue { 69 | private SinglyLinkedList list = new SinglyLinkedList<>(); 70 | public LinkedQueue() {} 71 | public int size() { return list.size(); } 72 | public boolean isEmpty() { return list.isEmpty(); } 73 | public void enqueue(E element) { list.addLast(element); } 74 | public E first() { return list.first(); } 75 | public E dequeue() { return list.removeFirst(); } 76 | } 77 | ``` 78 | 79 | ## Deque (Double-Ended Queue) 80 | - ![deque](./deque.jpeg) 81 | - 일반적인 Queue와는 다르게 맨 앞과 맨 뒤에서 모두 삽입과 제거가 가능한 자료구조 82 | - ADT(Abstract Data Type) 83 | - addFirst(e): Deque의 맨 앞에 Element 추가 84 | - addLast(e): Deque의 맨 뒤에 Element 추가 85 | - removeFirst(): Deque의 첫번째 Element 제거 및 return 86 | - removeLast(): Deque의 마지막 Element 제거 및 return 87 | - first(): Deque의 첫번째 Element return 88 | - last(): Deque의 마지막 Element return 89 | - size(): Deque의 Element 개수를 return 90 | - isEmpty(): Deque가 비었는지 확인 91 | -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/Stack.md: -------------------------------------------------------------------------------- 1 | # Stacks 2 | - ![Stack](./Lifo_stack.png) 3 | - Stack은 LIFO(Last-In, First-Out) 방식으로 삽입되고 제거되는 자료구조이다. 4 | - 브라우저에서 방문 기록을 저장하는 방식 등 실제로 많이 사용되고 있는 자료구조 5 | - ADT(Abstract Data Type) 6 | - push(e): Stack의 맨 위에 Element를 추가한다. 7 | - pop(): Stack의 맨 위에 있는 Element를 제거하면서 해당 값을 return한다. (Stack이 비어있으면 null을 return) 8 | - top() 혹은 peek(): Stack의 맨 위에 있는 Element를 return한다. 9 | - size(): stack의 크기를 return한다. 10 | - isEmpty(): Stack이 비어있는지 확인한다.(Boolean) 11 | 12 | ## Array로 구현한 Stack 13 | ``` java 14 | public class ArrayStack implements Stack { 15 | public static final int CAPACITY = 1000; 16 | private E[] data; 17 | private int t = -1; 18 | public ArrayStack() { this(CAPACITY) }; 19 | public ArrayStack(int capacity) { 20 | // 필요한 만큼만 capacity를 설정할 수 있어 메모리 낭비를 최소화 할 수 있게 만들었다. 21 | data = (E[]) new Object[capacity]; 22 | } 23 | pubic int size() { return (t + 1) }; 24 | public boolean isEmpty() { return (t == -1) }; 25 | public void push(E e) throws IllegalStateException {// Time Comlexity O(1) 26 | if (size() == data.length) throw new IllegalStateException("Stack is full"); 27 | data[++t] = e; 28 | } 29 | public E top() { 30 | if (isEmpty()) return null; 31 | return data[t]; 32 | } 33 | public E pop() {// Time Comlexity O(1) 34 | if (isEmpty()) return null; 35 | E answer = data[t]; 36 | data[t] = null; // null로 만들지 않아도 돌아가기야 하겠지만 GC를 위해서 이렇게 하는게 좋음 37 | t--; 38 | return answer; 39 | } 40 | } 41 | ``` 42 | 43 | ## Linked-List로 구현한 Stack 44 | ``` java 45 | public class LinkedStack implements Stack { 46 | private SinglyLinkedList list = new SinglyLinkedList<>(); 47 | public LinkedStack() {} 48 | public int size() { return list.size(); } 49 | public boolean isEmpty() { return list.isEmpty(); } 50 | public void push(E element) { list.addFirst(element); } 51 | public E top() { return list.first(); } 52 | public E pop() { return list.removeFirst(); } 53 | } 54 | ``` 55 | -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/compare_unsorted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/StackAndQueue/compare_unsorted.png -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/deque.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/StackAndQueue/deque.jpeg -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/queue-data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/StackAndQueue/queue-data.png -------------------------------------------------------------------------------- /DataStructure/StackAndQueue/queue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/StackAndQueue/queue.png -------------------------------------------------------------------------------- /DataStructure/Tree/Heap.md: -------------------------------------------------------------------------------- 1 | # Heap 2 | ![max-heap](./max-heap.png) 3 | - Heap은 tree-based data structure이다. 4 | - Parent와 child의 key값에 따라 `Max Heap`과 `Min Heap`으로 나눌 수 있다. 5 | - 오직 Parent-child 사이의 관계에만 연관성이 있다. 6 | - Parent Node의 Key값 `P`,Child Node의 Key값 `C` 7 | - Max Heap: `P >= C` 8 | - Min Heap: `P <= C` 9 | - root node를 top이라고 부른다. 10 | - Heap은 Sorted Structure가 아니고 부분적으로 정렬 된 것처럼 보일 뿐이다. 11 | - Heap은 Priority가 가장 높거나 낮은 node를 반복적으로 제거해야 할 때 유용한 Data structure이다. 12 | - 일반적으로 Heap은 Binary Tree로 구현된 `Binary Heap`이다. 13 | 14 | ## 구현 15 | - 일반적으로 Array를 사용해 구현하고 one-based-array로 구현하기도 한다.(구현할때 index 계산이 편해짐) 16 | - 아래는 0-based array로 구현됨 17 | - insert와 delete 18 | - insert (min-heap 기준) 19 | 1. Full binary Tree를 유지하기위해 Tree의 맨 마지막 level에서 가장 오른쪽에 추가. 20 | 2. 새로 추가한 node와 parent를 비교하여 `P > C` 라면 swap(P, C) (max-heap이면 P < C인 경우) 21 | 3. 반복해서 parent와 비교한다. 22 | 4. root에 도달했거나 P > C를 만족하지 않는다면 멈춤 23 | - delete (min-heap 기준) 24 | 1. root 노드를 return한다. 25 | 2. 맨 마지막 노드를 root 노드로 이동 26 | 3. child 중 priority가 높은 것(더 작은 수)를 선택 27 | 4. swap(P, C) 28 | 5. 반복하여 child와 비교 29 | 6. leaf node에 도착했거나 P > C를 만족하지 않는다면 멈춤 30 | - Time-Complexity 31 | - Search: `O(n)` 32 | - Insert: `O(log n)` 33 | - delete: `O(log n)` 34 | - peek: `O(1)` 35 | - Full binary tree에서 노드의 수가 `n`이라면 높이는 ![log](./log2.svg)이므로 worst case기준 모든 leaf까지 탐색하여 `O(log n)`이다. 36 | 37 | ``` java 38 | public class minHeap { 39 | private ArrayList heap = new ArrayList<>(); 40 | 41 | public int getLeftChild(int idx) { 42 | return idx * 2 + 1; 43 | } 44 | 45 | public int getRightChild(int idx) { 46 | return idx * 2 + 2; 47 | } 48 | 49 | public int getParent(int idx) { 50 | if (idx % 2 == 0) return (idx / 2) - 1; 51 | return idx / 2; 52 | } 53 | 54 | public int getPriority(int value1, int value2) { 55 | return Integer.compare(value1, value2); 56 | } 57 | 58 | public boolean isEmpty() { 59 | return heap.isEmpty(); 60 | } 61 | 62 | public void print() { 63 | for (Integer el : heap) { 64 | System.out.print(el + " "); 65 | } 66 | System.out.println(); 67 | } 68 | 69 | private boolean isGoUp(int idx, int value) { 70 | if (idx <= 1) return false; 71 | int parent_value = heap.get(getParent(idx)); 72 | 73 | return getPriority(parent_value, value) == 1; 74 | } 75 | 76 | private int getPriorityChild(int idx) { 77 | int leftChildIdx = getLeftChild(idx); 78 | if (leftChildIdx > heap.size() - 1) { 79 | return -1; 80 | } else if (leftChildIdx == heap.size() - 1) { 81 | return leftChildIdx; 82 | } 83 | int rightChildIdx = getRightChild(idx); 84 | int leftChildValue = heap.get(leftChildIdx); 85 | int rightChildValue = heap.get(rightChildIdx); 86 | 87 | if (getPriority(leftChildValue, rightChildValue) == -1) { 88 | return leftChildIdx; 89 | } else { 90 | return rightChildIdx; 91 | } 92 | 93 | } 94 | 95 | private boolean isGoDown(int idx, int value) { 96 | int childIdx = getPriorityChild(idx); 97 | if (childIdx == -1) { 98 | return false; 99 | } 100 | int childValue = heap.get(childIdx); 101 | 102 | return getPriority(childValue, value) == -1; 103 | } 104 | 105 | public int size() { 106 | return heap.size(); 107 | } 108 | 109 | public void insert(int el) { 110 | if (isEmpty()) { 111 | heap.add(el); 112 | return; 113 | } 114 | 115 | heap.add(el); 116 | 117 | int newest_idx = heap.size() - 1; 118 | 119 | while (isGoUp(newest_idx, el)) { 120 | int parent_idx = getParent(newest_idx); 121 | heap.set(newest_idx, heap.get(parent_idx)); 122 | 123 | newest_idx = parent_idx; 124 | } 125 | 126 | heap.set(newest_idx, el); 127 | } 128 | 129 | private void swap(int node1, int node2) { 130 | int temp = heap.get(node1); 131 | heap.set(node1, heap.get(node2)); 132 | heap.set(node2, temp); 133 | } 134 | 135 | public int removeMin() { 136 | int top = heap.get(0); 137 | int lastIdx = heap.size() - 1; 138 | int lastData = heap.get(lastIdx); 139 | 140 | int idx_value = 0; 141 | heap.set(0, lastData); 142 | heap.remove(lastIdx); 143 | while (isGoDown(idx_value, lastData)) { 144 | int child_idx = getPriorityChild(idx_value); 145 | swap(idx_value, child_idx); 146 | idx_value = child_idx; 147 | } 148 | 149 | return top; 150 | } 151 | 152 | public static void main(String[] args) { 153 | minHeap heap = new minHeap(); 154 | heap.insert(3); 155 | heap.insert(5); 156 | heap.insert(1); 157 | heap.insert(10); 158 | heap.insert(8); 159 | heap.insert(7); 160 | heap.insert(4); 161 | heap.insert(5); 162 | heap.insert(2); 163 | heap.insert(6); 164 | heap.insert(9); 165 | 166 | heap.print(); 167 | 168 | int heapSize = heap.size() - 1; 169 | for (int i = 0; i <= heapSize; i++) { 170 | System.out.print(heap.removeMin() + " "); 171 | } 172 | } 173 | } 174 | ``` 175 | -------------------------------------------------------------------------------- /DataStructure/Tree/Tree.md: -------------------------------------------------------------------------------- 1 | # Tree 2 | ## 개념 3 | - Tree `T`는 `parent-child relationship`을 갖도록 Element를 저장하는 node의 집합이다. 4 | - parent-child relationship은 다음과 같은 속성을 만족해야한다. 5 | - Tree `T`가 비어있지 않으면 `T`는 parent가 없는 특별한 node인 `root`를 가진다. 6 | - Tree `T`의 각각의 노드 `v`에는 parent node인 `w`가 존재한다; `w`를 parent node로 갖는 모든 nodesms `w`의 child node이다. 7 | 8 | - Empty Tree (node가 하나도 없는 Tree)가 존재할 수 있다. 9 | 10 | ## Tree가 될 수 없는 경우 11 | 1. node의 edge가 자기 자신을 향하는 경우 12 | 2. path에서 cycle이 생기는 경우 13 | 3. node가 2개 이상의 parent를 가지는 경우 14 | 4. 서로 연결되지 않은 subtree가 존재하는 경우 15 | 16 | ## 용어 17 | ![tree](./tree.jpeg) 18 | - siblings node(형제): 같은 parent를 갖는 node들을 `siblings(형제)`라고 부른다. 19 | - Leaf node(리프): node에 child가 하나도 없으면 이를 `external node`라고 하고 leaf라고 부른다. 20 | - internal node: child가 하나라도 존재하면 `internal`하다고 한다. 21 | - ancestor(조상): 어떤한 child node `v`에서 반복해서 parent node를 찾으며 올라갈 때 거쳤던 모든 node들을 `v`의 ancestor라고 한다. 22 | - descendant(자손): 어떠한 parent node `v`에서 반복해서 child node를 찾을 때 찾을 수 있는 모든 node들을 `v`의 descendant라고 한다. 23 | - edge(에지): 두 node간의 연결되어 있는 선을 edge라고 한다. 24 | - path(경로): 한 node와 다른 node를 연결하는 일련의 node 및 edge의 순서 25 | - length(길이): 출발 node에서 도착 node까지 거치는 node의 개수 26 | - depth(깊이): root node에서 다른 node까지의 edge의 수 27 | - height(높이) 28 | - height of node: 해당 노드부터 가장 먼 leaf node까지 연결된 edge의 개수 29 | - height of tree: root 노드부터 가장 먼 leaf node까지 연결된 edge의 개수 30 | - degree(차수): 해당 node의 subtree의 개수 31 | - size(크기): node의 개수 32 | - level(계층): Tree에서 각 계층을 나타내며 루트(level 1)부터 단계마다 +1씩 증가한다. 33 | 34 | ## Ordered Tree 35 | - 각 node가 유의미한 순서를 가지는 정렬된 Tree 36 | - 대개 순서에 따라 왼쪽에서 오른쪽으로 정렬하여 시각화한다. 37 | 38 | ## ADT 39 | - Tree의 node에 대한 추상화로서 `position`이라는 개념을 사용한다. 40 | - getElement(): 현재 position의 element를 return한다. 41 | - root(): root의 position을 return한다. (빈 Tree일 경우 null을 return) 42 | - parent(p): position `p`에 대한 parent 의 position을 return한다. (p 가 root를 가리킬 경우 null을 return) 43 | - children(p): child node가 존재하는 경우 position `p`에 대한 모든 child node를 return한다. 44 | - numChildren(p): position `p`에 대한 child node의 개수를 return한다. 45 | - isInternal(p): position `p`가 적어도 1개 이상의 child를 가지고 있으면 `true`를 return한다. 46 | - isExternal(p): position `p`가 child를 가지고 있지 않으면 `true`를 return한다. 47 | - isRoot(p): position `p`가 root이면 `true`를 return한다. 48 | - size(): Tree에 포함 되어 있는 모든 position의 개수를 return한다. 49 | - isEmpty(): Tree에 어떠한 position도 속해있지 않으면 `true`를 return한다. 50 | - iterator(): Tree의 모든 Element에 대한 Iterator를 return한다. 51 | - positions(): Tree의 모든 position에 대한 iterable collection을 return한다. 52 | 53 | ## Binary Trees 54 | - Binary Tree는 다음 원리를 만족하는 ordered tree이다. 55 | 1. 모든 node는 최대 두 개의 child node를 가진다. 56 | 2. 각각의 child node는 left child 혹은 right child로 이름 붙여진다. 57 | 3. left child node가 right child node보다 순서가 앞선다. 58 | 59 | - internal node `v`의 왼쪽 또는 오른쪽 child를 root로 하는 subtree를 `v`의 left subtree, right subtree라고 한다. 60 | - 각 node가 leaf node를 제외하고 2개의 child를 가질때 이를 `full binary tree` 라고 한다. 61 | - 각 마지막 level을 제외한 모든 레벨이 완전히 채워지고 모든 node가 왼쪽 child부터 채워진 상태일때 `complete binary tree`라고 한다. 62 | 63 | 64 | - level이 n인 Binary Tree의 최대 node수는 `2^n-1`개이다. (root가 level 1부터 시작시) 65 | - Binary Tree의 leaf node의 개수는 degree가 2인 node의 개수 +1이다. 66 | - node 개수 `n`개로 이루어진 서로 다른 Binary Tree의 개수는 `Catalan number`와 같다. 67 | ![catalan number](./catalan.png) 68 | 69 | 70 | ### Linked Binary Tree 71 | ![linked-binary-tree](./linked-binary-tree.jpeg) 72 | - Single Node와 Bianry Tree를 표현 73 | 74 | ### Array-Based Binary Tree 75 | ![array-based-tree](./array-based-tree.jpeg) 76 | - position p가 `root`이면 `f(p) = 0` (root node의 index는 항상 0) 77 | - position p가 `left child`면 `f(p) = 2f(q) + 1` 78 | - position p가 `right child`면 `f(p) = 2f(q) + 2` 79 | 80 | - Array-based Binary Tree의 장점은 position `p`가 single integer `f(p)`로 표현된다는 점이다. 81 | - root, parent, left, right등 모든 position을 구할 때 `f(p)`를 통해 구할 수 있다. 82 | 83 | - Array-based Binary Tree는 Tree의 모양에 따라 Array의 size가 결정된다. 84 | - Array의 length `N`, node의 개수 `n`일때 최악의 경우 `N = 2^n - 1`까지 될 수 있다. (공간 필요량이 너무 많다) 85 | 86 | ## Tree Traversal Algorithms 87 | ### Depth-first Tree Traversal 88 | - 깊이 우선 탐색 89 | - 재귀적으로 leaf 노드까지 우선 방문하며 탐색한다. 90 | #### Pre-order 91 | ![preorder](./preorder.jpeg) 92 | ``` java 93 | void preorder(Node node) { 94 | if (node == null) return; 95 | Display node.element // display 부분이 맨 앞에 있음 96 | preorder(node.leftSubtree); 97 | preorder(node.rightSubtree); 98 | } 99 | ``` 100 | - preorder: 1 -> 2 -> 4 -> 5 -> 3 101 | 102 | #### In-order 103 | ![inorder](./inorder.jpeg) 104 | ``` java 105 | void inorder(Node node) { 106 | if (node == null) return; 107 | inorder(node.leftSubtree); 108 | Display node.element음 // display 부분이 가운데 있음 109 | inorder(node.rightSubtree); 110 | } 111 | ``` 112 | - inorder: 4 -> 2 -> 5 -> 1 -> 3 113 | 114 | #### Post-order 115 | ![postorder](./postorder.jpeg) 116 | ``` java 117 | void postorder(Node node) { 118 | if (node == null) return; 119 | postorder(node.leftSubtree); 120 | postorder(node.rightSubtree); 121 | Display node.element // display 부분이 맨 뒤에 있음 122 | } 123 | ``` 124 | - postorder: 4 -> 5 -> 2 -> 3 -> 1 125 | 126 | ### Breadth-First Tree Traversal 127 | ![bfs](./bfs.jpeg) 128 | - 너비 우선 탐색 129 | - 같은 level에 있는 node들 부터 순차적으로 탐색한다. 130 | ``` java 131 | void breadthfirst() { 132 | Queue queue = new Queue(); // Queue를 새로 만든다 133 | queue.enqueue(root); // Queue에 root의 position을 enqueue 134 | 135 | while (queue.isEmpty()) { 136 | p = queue.dequeue(); 137 | Display p.element 138 | for (Position c : children(p)) { 139 | queue.enqueue(c); // 현재 position의 child node를 순서대로 enqueue 140 | } 141 | } 142 | } 143 | ``` 144 | - Breadth-First: 1 -> 2 -> 3 -> 4 -> 5 145 | 146 | ### DFS vs BFS 147 | - 모든 탐색에서 `O(n)`의 Time complexity를 보인다. (모든 노드를 탐색하므로) 148 | - BFS는 `O(w)`의 공간이 추가로 필요하다. w는 Binary Tree의 maximum width (Queue에 같은 level에 있는 node들이 쌓이므로) 149 | - DFS는 `O(h)`의 공간이 추가로 필요하다. h는 Binary Tree의 maximum height (Call stack에 모든 ancestors가 쌓이므로) 150 | - DFS는 재귀적으로 동작하므로 function call overhead가 필요로하다. 151 | - 우리가 Search를 진행 할 때 우리가 찾고자 하는 것이 Root쪽에 가까울 확률이 높으면 BFS를, Leaf쪽에 가까울 확률이 높으면 DFS를 사용하는 것이 좋다. 152 | -------------------------------------------------------------------------------- /DataStructure/Tree/array-based-tree.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/array-based-tree.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/bfs.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/bfs.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/catalan.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/catalan.png -------------------------------------------------------------------------------- /DataStructure/Tree/inorder.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/inorder.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/linked-binary-tree.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/linked-binary-tree.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/log2.svg: -------------------------------------------------------------------------------- 1 | 2 | {\displaystyle \lfloor \log _{2}n\rfloor } 3 | 12 | 23 | -------------------------------------------------------------------------------- /DataStructure/Tree/max-heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/max-heap.png -------------------------------------------------------------------------------- /DataStructure/Tree/postorder.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/postorder.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/preorder.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/preorder.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/travel.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/travel.jpeg -------------------------------------------------------------------------------- /DataStructure/Tree/tree.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/DataStructure/Tree/tree.jpeg -------------------------------------------------------------------------------- /Interview/question/previous_interview.md: -------------------------------------------------------------------------------- 1 | # 역대 면접 질문 2 | 3 | > 여러 곳 면접을 보면서 받았던 질문 중 생각나는 것들을 모았습니다. 4 | 5 | ## 목차 6 | 7 | ### [Sorting](#sorting-solution) 8 | 9 | 1. Sorting Algorithm에서 stable 하다는 것은 무엇을 의미하나요? 10 | 2. Sorting Algorithm이 가짓수가 많은데 그 이유가 무엇일 것 같나요? 11 | 3. Quick sort에 대해서 설명해 줄 수 있나요? 12 | 13 | ### [OS](#os-solution) 14 | 15 | 1. 프로세스 생성 과정에 대해서 설명해보세요 16 | 2. 크롬 탭이 프로세스인지 쓰레드인지 설명해보세요 17 | 3. 프로세스와 쓰레드의 차이를 설명해보세요 18 | 4. 프로세스의 생성 과정에 대해 설명해보세요 19 | 5. Heap과 Stack의 차이점은 무엇인가요? 20 | 21 | ### [Network](#network-solution) 22 | 23 | 1. HTTPS란? 24 | 2. TCP와 UDP의 차이점은? 25 | 3. TCP란 무엇인가? 26 | 4. 브라우저에서 주소창에 url 입력시 어떤일이 일어나는가? 27 | 28 | ### [DB](#db-solution) 29 | 30 | 1. postgresql과 elastic search의 차이점은 무엇인가요? 31 | 32 | ### [Front-End](#front-end-solution) 33 | 34 | 1. 평소 Angular를 사용할때 State 관리는 어떤 식으로 했나요? 35 | 2. Redux가 뭔지 아시나요? 안다면 어떤건지 설명해 줄 수 있나요? 36 | 3. javascript sourcemap에 대해 알고있나요? 알고있다면 Production에서 sourcemap을 디버깅할 수 있는 방법을 알고있나요? 37 | 38 | ## 답변 39 | 40 | > 답변은 개인적으로 찾아보고 공부해서 써놓은 것으로 틀릴 수 있습니다. 41 | 42 | ### Sorting Solution 43 | 44 | #### 1. Sorting Algorithm에서 stable 하다는 것은 무엇을 의미하나요 45 | 46 | 동일한 Element가 있을 때 정렬 전의 순서와 정렬 후의 순서가 동일함을 보장하는 것이 47 | Stable이다. 48 | 49 | 예를 들어 `[{k: 4, v: 1}, {k: 3, v: 2}, {k: 3, v: 1}, {k: 2, v: 1}, {k: 5, v: 1}]` 을 stable한 sorting algorithm을 이용한다면. 50 | 51 | `[{k: 2, v: 1}, {k: 3, v: 2}, {k: 3, v: 1}, {k: 4, v: 1}, {k: 5, v: 1}]`가 된다. (k가 3인 동일한 정렬 기준을 가진 Element가 2개가 있지만 input된 순서 그대로 정렬되었다.) 52 | 53 | ---- 54 | 55 | #### 2. Sorting Algorithm이 가짓수가 많은데 그 이유가 무엇일 것 같나요 56 | 57 | ![sorting](./sorting.png) 58 | 출처: [http://bigocheatsheet.com/](http://bigocheatsheet.com/) 59 | 60 | 1. sorting algorithm마다 expected되는 속도가 다르다. 61 | 2. 속도가 아닌 Space Comlexity가 고려대상이 될 수 있다. Merge sort같은 경우 insertion sort나 selection sort에 비해 추가 메모리 공간을 사용하기 때문 62 | 3. Stable한지 안한지에 따라 사용되어야 할 sorting algorithm이 다를 수 있다. 63 | 64 | ---- 65 | 66 | #### 3. Quick sort에 대해서 설명해 줄 수 있나요 67 | 68 | Quick sort는 Divide-and-Conquer paradigm을 이용해 정렬을 수행하는 정렬 알고리즘이며 그중에서도 Partitioning이라는 아이디어를 이용한다. 69 | 70 | Partitioning이란 Pivot element를 기준으로 왼쪽은 Pivot보다 작거나 같은 것을 모아주고 오른쪽은 Pivot보다 크거나 같은것을 모아주는 것을 말한다. 71 | 72 | Partitioning을 재귀적으로 진행하다보면 정렬이 완료된다. 73 | 74 | - [js로 구현한 quick sort](../sorting/quickSort.js) 75 | 76 | ---- 77 | 78 | ### OS Solution 79 | 80 | #### 1. 프로세스 생성 과정에 대해서 설명해보세요 81 | 82 | 일반적인 프로세스 생성 과정 83 | 84 | 1. PCB가 생성되며 OS가 실행한 프로그램의 코드를 읽어들여 프로세스에 할당된 메모리의 Text segment에 저장한다. 85 | 2. 초기화된 전역 변수 및 static 변수를 data segment에 할당. 86 | 3. HEAP과 Stack은 초기 메모리 주소만 초기화됨. 87 | 4. PCB에 여러 정보가 기록되면 Ready Queue에서 CPU를 할당받기까지 대기한다. 88 | 89 | ---- 90 | 91 | #### 2. 프로세스와 쓰레드의 차이를 설명해보세요 92 | 93 | 프로세스는 실행되는 프로그램 자체와 프로그램이 실행되는 주변 환경을 포함하는 개념이다. 94 | 실행되는 주변 환경이란 사용중인 파일, 데이터, 메모리 영역 주소 공간등을 뜻한다. 95 | 96 | 쓰레드는 프로세스 내부에서 프로세스의 자원을 공유하거나 공유하지 않고 실행되는 작업의 단위이다. 97 | 98 | ---- 99 | 100 | #### 3. Heap과 Stack의 차이점은 무엇인가요 101 | 102 | Heap은 메모리 주소가 낮은 영역부터 채워지고 Stack은 메모리 주소가 높은 영역부터 채워진다. 103 | 104 | 1. Heap: 동적 할당을 할 경우 Heap 영역에 할당됨 105 | 2. Stack: 함수를 호출할 때 함수내부의 지역변수를 저장하거나 함수를 호출한 caller의 환경정보를 저장함. 106 | 107 | 결론적으로 물리적으론 같은 메모리 공간을 공유하지만 쓰임새가 다르고 서로의 영역을 누가 침범하느냐에 따라 Stack overflow, Heap overflow가 일어난다. 108 | 109 | - [http://www.phrack.org/archives/issues/49/14.txt](http://www.phrack.org/archives/issues/49/14.txt) 110 | 111 | ---- 112 | 113 | #### 4. 크롬 탭이 프로세스인지 쓰레드인가요 114 | 115 | > 진지한 질문은 아니었고 알고있는지, 그래서 일어나는 특성이 뭔지 물어보려는 것 같았음 116 | 117 | 크롬은 탭마다 PID를 가지고 있으니 Process이며 각 Tab마다 랜더링 정보나 기타 데이터를 118 | 따로 관리한다고 한다. 그로인해 메모리를 많이 잡아먹기도 하지만 하나의 Tab에 오류가 생겼다고 119 | 모든 Tab에 영향을 끼치진 않는다. 120 | 121 | ---- 122 | 123 | ### Network Solution 124 | 125 | #### 1. HTTPS란 126 | 127 | HTTP Secure의 약자이며 HTTPS를 사용하여 전송되는 데이터는 TLS를 통해 보호된다. 128 | 129 | TLS는 Certificate Authority(CA)라 불리는 서드 파티로부터 서버와 클라이언트 130 | 의 인증을 하는데 사용된다. 131 | 132 | SSL(TLS) 동작방식 133 | 134 | 1. 클라이언트가 서버에 접속하며 랜덤 데이터를 전송. (Client hello) 135 | 2. 서버가 Client hello에 대한 응답으로 `Server hello`를 함 (이때 인증서와 랜덤데이터 제공) 136 | 3. 클라이언트의 브라우저에서 서버가 건네준 인증서가 CA에서 발급된건지를 확인하고 공개키로 인증서를 복호화한다. (인증서가 믿을 수 있다고 판단함) 137 | 4. 클라이언트와 서버의 각각의 랜덤 데이터를 가지고 클라이언트에서 `pre master secret`값을 만들어냄 (대칭키) 138 | 5. pre master secret 값을 비대칭키 (클라이언트가 알고있는 공개키)를 이용하여 암호화하고 이를 서버에 보냄 이렇게 암호화 된 값을 `master secret`이라하고 이는 `session key`를 만들어냄 139 | 6. 이 session key를 이용하여 서버와 클라이언트는 `대칭키` 방식으로 암호화 통신을 함 140 | 141 | ---- 142 | 143 | #### 2. TCP와 UDP의 차이점은 144 | 145 | TCP는 연결 동작을 통해 ACK와 Sequence Number를 주고받으며 신뢰성과 흐름제어를 제공하는 방면 UDP는 IP를 거의 그대로 사용하며 단순히 Checksum말고는 데이터의 훼손을 감지할 수 없다. 또한 ACK와 Sequence Number를 주고받지 않으므로 중간에 데이터가 유실되어도 이를 다시 요청하거나 할 수 있는 방법이 없다. 또한 TCP와 다르게 UDP는 혼잡을 제어할 수 있는 방법이 없다. 146 | 147 | ---- 148 | 149 | #### 3. TCP란 무엇인가 150 | 151 | 데이터의 송수신을 위해 IP를 이용하는 프로토콜이며 통신간에 신뢰성을 보장해주기 위해 만든 것이다. 152 | 153 | TCP는 3-way handshake라고 불리는 연결 동작과 4-way handshake라고 불리는 연결 종료를 통해 ACK와 Sequence Number를 주고 받아 데이터 흐름의 신뢰성을 구축한다. 154 | 155 | ---- 156 | 157 | #### 4. 브라우저에서 주소창에 url 입력시 어떤일이 일어나는가 158 | 159 | 1. 브라우저의 주소창에 url 입력 160 | 2. 브라우저 캐시에서 DNS 레코드를 확인하여 IP주소를 찾음 (없다면 DNS resolver를 통해 IP주소를 알아냄) 161 | 3. 브라우저가 서버와 TCP 연결을 시작함 162 | 4. 브라우저가 웹 서버에 HTTP 요청을 보냄 163 | 5. 서버가 요청을 처리하고 응답을 되돌려보냄 164 | 6. 브라우저는 서버가 보낸 HTML 내용을 표시 165 | 166 | - [what happens when you type an url in the browser and press enter](https://medium.com/@maneesha.wijesinghe1/what-happens-when-you-type-an-url-in-the-browser-and-press-enter-bb0aa2449c1a) 167 | 168 | ---- 169 | 170 | ### DB Solution 171 | 172 | #### 1. postgresql과 elastic search의 차이점은 무엇인가요 173 | 174 | postgresql은 관계형 데이터베이스이고 elastic search는 검색엔진이다. 175 | 단 elastic search는 데이터 모델을 JSON으로 사용하고 있어서 NoSQL처럼 사용할 수 있다. 176 | 177 | ---- 178 | 179 | ### Front-End Solution 180 | 181 | #### 1. 평소 Angular를 사용할때 State 관리는 어떤 식으로 했나요 182 | 183 | > 정확히 어떤 식으로 대답해야 정답인지 모르겠다. 184 | 185 | URI Parameter로 넘기거나, stateProvider를 이용해서 state를 전달하거나 했다. 186 | 필요하다면 global scope에 넣어두기도 하고. 187 | 188 | - [https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f](https://blog.nrwl.io/managing-state-in-angular-applications-22b75ef5625f) 189 | 190 | ---- 191 | 192 | #### 2. Redux가 뭔지 아시나요? 안다면 어떤건지 설명해 줄 수 있나요 193 | 194 | > Redux를 사용해 production을 개발해 본 적이 없어 자세한 설명을 불가능 했음. 당시 대답을 적어두도록 함 195 | 196 | React project가 커지다보면 state나 props등 데이터의 이동이 parent-child 구조로 넘기기가 복잡해집니다. 그래서 하나의 store를 두어 state와 props을 관리하게되며 data의 변경이 있을때 View에 통지하는 방식으로 데이터를 반영합니다. 197 | 198 | - [https://d2.naver.com/helloworld/1848131](https://d2.naver.com/helloworld/1848131) 199 | 200 | ---- 201 | 202 | #### 3. javascript sourcemap에 대해 알고있나요? 알고있다면 Production에서 sourcemap을 디버깅할 수 있는 방법을 알고있나요 203 | 204 | javascript sourcemap이란 원본 파일에 대한 정보를 담은 파일이다. 205 | javascript project를 build하면 javascirpt 파일을 minified 하거나 uglify해서 사용하는데 이 sourcemap이란 파일이 존재하므로써 디버깅시 원래의 모습으로 돌려줄 수 있도록 한다. *.map file을 production에 같이 배포했다면 Chrome 개발자 도구가 자동으로 mapping을 해준다. 206 | 207 | - [source map](https://www.html5rocks.com/en/tutorials/developertools/sourcemaps/) 208 | 209 | ---- 210 | 211 | #### 4. Webpack 써보신 적 있나요 212 | 213 | > 개인적으로 웹팩은 create-react-app이나 angular-cli에서 기본적으로 사용하기 때문에 사용해본 적은 있지만 직접 config file을 작성해본 적은 없고 gulp를 많이 이용했기 때문에 이 질문에선 webpack이 무엇이고 왜 사용하는지에 대해 답변했다. 214 | 215 | Webpack은 module bundler이며 bundling이란 javascript 모듈들을 의존성을 통해 하나 혹은 여러개의 파일로 묶는 것을 뜻한다. 번들링을 진행하는동안 uglify나 minified등을 해줄 수 있고 이는 config 파일을 설정하면 가능하다. 216 | 217 | ES6에 들어서면서 모듈 관련 스펙이 들어갔지만 모든 브라우저가 이를 지원하는 것은 아니기때문에 webpack의 도움이 필요하다. 또한 모듈로 나눠진 js파일들을 하나 또는 여러개의 작은 js 파일로 번들링 함으로써 네트워크 통신 비용도 줄어들게 된다. html에 import해야하는 js파일이 줄어드는 것 또한 덤 218 | -------------------------------------------------------------------------------- /Interview/question/sorting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/Interview/question/sorting.png -------------------------------------------------------------------------------- /Interview/question/week1.md: -------------------------------------------------------------------------------- 1 | # 목차 2 | 3 | 1. Array vs LinkedList 4 | 2. GET, POST 방식의 차이점 5 | 3. 프로세스와 스레드의 차이 6 | 4. 데이터베이스를 사용하는 이유 7 | 5. JavaScript Event Loop 8 | 9 | ## Array vs LinkedList 10 | 11 | Static Array기준 LinkedList와 다른점은 Capacity다. Static Array는 Capacity가 정해져있는 방면 LinkedList는 Capacity에 상관없이 item을 추가할 수 있다. 12 | 또한 Array는 같은 자료형을 가진 연속된 메모리 공간으로 이루어져있고, LinkedList는 데이터와 다음 노드를 가리키는 포인터가 모인 노드로 이루어져있고 연속된 메모리 공간에 없어도 된다. 13 | 특정 Element에 접근하려면 Array는 Constant Time에 접근 가능하고 LinkedList는 O(n)의 시간이 걸린다. Array는 첫 Element의 주소값이 Array의 이름이되고 같은 자료형의 데이터만 가지고 있으니 14 | 주소값 + index * 자료형 크기로 바로 접근 가능 하지만 LinkedList는 찾는 Element에 도달할때까지 포인터를 타고 계속 search 해야한다. 15 | 16 | ## GET, POST 방식의 차이점 17 | 18 | 용도가 다르다. HTTP 자체가 클라이언트와 서버가 주고받는 메시지의 내용이나 순서를 약속한 것이고 이때 GET은 정보를 조회하기 위한 메소드라고 약속했고 19 | POST는 서버로 데이터를 전송하기 위해 설계된 메소드라고 약속했다. 둘다 데이터를 서버에 전달할 수 있다는 것이 공통점이지만 방식은 전혀 다른데 20 | GET은 URL의 파라미터로 이름과 데이터가 쌍으로 명시되어 전달되고, POST는 HTTP Request Message의 Body 부분에 데이터가 담겨있다. 21 | 또한 URL의 길이는 제한적이기 때문에 GET으로는 많은 양의 데이터를 전송할 수도 없다. 22 | 23 | [https://tools.ietf.org/html/rfc2616](https://tools.ietf.org/html/rfc2616) 24 | 25 | ## 프로세스와 스레드의 차이 26 | 27 | 프로세스는 운영체제에의해 자원을 할당받는 실행의 단위이고, 스레드는 프로세스가 할당받은 자원을 공유하는 실행의 단위이다. 28 | 스레드는 User-level Thread와 Kernel-level Thread 두 가지가 있는데, 29 | User-level Thread는 Kernel 입장에서 보면 그냥 단순히 Single Thread이다. 그래서 CPU에서 다중처리가 가능해도 이에따른 이득을 보지 못한다. 30 | 그리고 특정 Thread의 대기가 프로세스 내의 모든 스레드의 대기를 초래할 수 있다. (CPU 기준엔 Single Process이므로 대기시에 process 전체가 대기한다.) 31 | 그럼에도 불구하고 Thread는 한 프로세스의 자원 및 메모리를 공유하므로 스레드간의 통신 비용이 작고(동기화에 신경 써줘야함), 런타임 라이브러리가 context를 유지하기 때문에 switching 비용이 발생하지 않는다. 그래서 멀티 프로세스에 비해 빠르다. 또 한가지 Kernel-level Thread는 모든 스레드를 kernel이 관리하는데 스레드가 독립적으로 kernel에 의해 스케쥴링 되므로 독립된 thread에 blocking이 생기더라도 process 자체가 blocking되는 일이 발생하지 않는다. 요즘은 CPU 코어 수가 늘어나면서 Kernel-level Thread 강세라고 한다. 32 | 33 | [https://kldp.org/node/295](https://kldp.org/node/295) 34 | 35 | ## 데이터베이스를 사용하는 이유 36 | 37 | 파일처리 시스템을 이용할 수도 있겠지만, 여러가지 문제점이 있다. 38 | 데이터의 일부분을 수정하려고하면 그와 연관된 모든 파일을 모두 수정해야하는 번거로움이 있고, 비슷한 내용이 여러파일에 산재해 있는 경우가 생길 수 있다. 39 | 또한 파일 시스템은 OS의 영역이고 파일 시스템이 OS마다 다를 수 있기 때문에 OS에 종속적인 파일 시스템을 이용하는 것은 프로그램의 확장성을 해칠 수 있다. 40 | 원하는 데이터를 찾으려면 관련된 파일도 모두 찾아야하고 그 안에서 데이터도 찾아야하기 때문에 검색이 힘들고 이를 기반으로하는 단순 작업또한 어렵게된다. 41 | 이러한 단점을 극복하기위해 이러한 데이터의 저장을 전문으로 관라하는 프로그램인 DBMS를 두어 효율적으로 데이터를 관리한다. 42 | 또한 DBMS를 통해 여러 유저가 DB의 세션을 열어 사용하더라도 문제가 없게 만들어준다. 43 | 44 | [http://yang1650.tistory.com/28](http://yang1650.tistory.com/28) 45 | 46 | ## JavaScript Event Loop 47 | 48 | ECMAScript 스펙에는 사실 Event Loop가 없고 단순히 단일 Call Stack을 사용하여 요청이 들어올 때마다 해당 요청을 순차적으로 호출 스택에 담아 처리한다. 49 | Event Loop는 Javascript 자체 스팩이아닌 Javascript 구동 환경에 포함되어 있다. Javascript는 단일 Call Stack이기 때문에 브라우저나 Node.js의 API들과 잘 섞여 쓸 수 있도록 50 | 도와주는 것이 Event Loop의 역할이다. 모든 비동기 API들은 작업이 완료되면 Call back 함수를 Task Queue에 추가한다. Event Loop는 현재 실행중인 Task가 없을 때(Call stack이 비어있을 때) 51 | Task Queue에서 Pop해서 실행한다. 이렇게 비동기 처리가 되는 것이다. Promise의 then 메소드는 Call back 함수를 Task Queue가 아닌 Micro Task Queue에 추가한다. 52 | Micro Task Queue는 Task Queue보다 우선순위가 높으며 Event Loop는 Micro Task Queue의 Task부터 꺼내서 실행하게된다. 이는 HTML 스펙에 명시되어있다. 53 | 근데 ES6부터는 또 Job Queue라고 Promise Callback을 관리하는 Queue가 새로 생겼는데 HTML의 Micro Task Queue와 동시에 사용될 수 있다고 한다. 54 | 근데 두개가 어떻게 우선순위를 가지고 돌아가는건지는 찾아봐도 잘 안나옴 55 | 56 | [http://meetup.toast.com/posts/89](http://meetup.toast.com/posts/89) 57 | [https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint](https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint) 58 | [http://www.ecma-international.org/ecma-262/6.0/#sec-jobs-and-job-queues](http://www.ecma-international.org/ecma-262/6.0/#sec-jobs-and-job-queues) 59 | -------------------------------------------------------------------------------- /Interview/question/week2.md: -------------------------------------------------------------------------------- 1 | # 목차 2 | 3 | 1. RESTFul API란? 4 | 2. Stack and Queue 5 | 3. TCP 3-way-handshake 6 | 4. 스케줄러의 종류 7 | 5. CPU 스케줄링 기법 8 | 6. DB Index 9 | 7. Javascript Hoisting 10 | 8. Javascript, What is 'This' 11 | 12 | ## RESTFul API란 13 | 14 | REST는 Representational State Transfer의 약자입니다. REST API는 HTTP 설계의 우수성을 좀 더 잘 활용할 수 있도록 설계한 아키텍처이며 RESTFul API는 여러 특징을 가지고 있는데 작업을 위한 상태정보를 따로 저장하고 관리하지 않기 때문에(Stateless) API 서버는 요청만을 단순히 처리할 수 있게 됩니다. 또한 15 | REST 아키텍처는 HTTP의 표준을 잘 지키고 있기 때문에 HTTP가 가진 캐싱 기능을 잘 활용할 수 있고 API Message만 보고도 어떤 API인지 쉽게 이해 가능한 점이 RESTFul API의 특징입니다. 16 | 이러한 RESTFul API를 설계할때는 중요한 규칙이 있는데, 첫번째는 URI는 정보의 자원을 표현해야한다는 것이고 두번째는 자원에대한 행위는 HTTP Method로 표현해야 한다는 점입니다. 17 | 18 | - [http://meetup.toast.com/posts/92](http://meetup.toast.com/posts/92) 19 | - [http://bcho.tistory.com/953](http://bcho.tistory.com/953) 20 | - [https://developer.mozilla.org/ko/docs/Web/HTTP/Caching](https://developer.mozilla.org/ko/docs/Web/HTTP/Caching) 21 | 22 | ## Stack and Queue 23 | 24 | Stack은 LIFO 방식으로 삽입되고 제거되는 자료구조이며 Queue는 FIFO 방식으로 삽입되고 제거되는 자료구조이다. 25 | 26 | ## TCP 3-way-handshake 27 | 28 | TCP의 접속 동작을 의미한다. ACK 번호와 시퀀스 번호를 주고 받으며 서로 데이터를 주고 받을 수 있는 상태라는 것을 확인하는 단계이다. 29 | Client에서 Server로 시퀀스 번호의 초기값과 컨트롤 비트인 SYN(Synchronize)를 보낸다. Server는 Client로 시퀀스 번호의 초기값과 ACK(Acknowledge), 컨트롤비트 SYN, ACK를 보낸다. 30 | Client는 Server에 ACK를 보낸다. 컨트롤 비트는 통신 제어 상태를 의미하며 시퀀스 번호는 데이터의 고유한 번호로서 통신 개시부터 따져서 몇 번째 바이트에 해당하는지를 나타낸다. ACK 번호는 시퀀스 번호에 1을 더한 숫자이며 해당 데이터를 잘 받았다고 고지하는 역할을 한다. 31 | 32 | - [https://www.youtube.com/watch?v=LyDqA-dAPW4](https://www.youtube.com/watch?v=LyDqA-dAPW4) 33 | 34 | ## 스케줄러의 종류 35 | 36 | - 장기 스케줄러 37 | - 디스크에 있는 프로그램을 일괄처리큐에 대기시킨 후 프로세스가 되도록 하는 스케줄러 38 | - 다중 프로그래밍의 정도를 조절 39 | - 중기 스케줄러 40 | - 특정 프로세스에게 할당되어 있는 메모리를 빼앗거나 복귀시키는 스케줄러 (swapping) 41 | - 단기 스케줄러 42 | - 준비 상태의 프로세스중에 어느 프로세스에게 CPU를 할당할지 결정하는 스케줄러 43 | 44 | ## CPU 스케줄링 기법 45 | 46 | - FCFS 47 | - First Come First Service의 약자로 비선점 방식의 스케줄링 방식이다. Ready Queue에 들어온 순서대로 CPU를 할당하고 처리한다. 48 | - SJF(or SPN) 49 | - Shortest Job First의 약자로 이름대로 CPU 요구량이 적은 것 부터 처리하는 비선점 방식의 스케줄링 방식이다. CPU 요구량이 높은 것은 무한대기 할 수도 있다. 50 | - SRT 51 | - Shortest Remaining Time의 약자로 SJF를 선점 방식으로 처리하는 방식이다. CPU 요구량이 적은 것부터 스케줄링을 해나가되 CPU 요구량이 더 적은 것이 들어 올 경우 CPU를 빼앗겨 Context Swiching이 된다. 52 | - Multi-Level Queue 53 | - 정적 우선순위를 사용하는 선점 방식 스케줄링으로 우선순위 개수만큼 Queue가 있으며 가장 우선순위가 높은 Queue부터 작업을 처리하다가 더 높은 우선순위의 작업이 들어오면 CPU를 빼앗긴다. 54 | - Multi Level Feedback Queue 55 | - 동적 우선순위를 사용하는 선점 방식 스케줄링으로 우선순위 개수만큼 Queue가 있으며 최상위 단계의 Ready Queue부터 FCFS의 방식으로 실행 후 해당 큐의 할당량이 끝나면 하위 우선순위 준비큐에 들어간다. 우선 순위가 낮을수록 큐의 CPU 시간 할당량이 많아지게되며 마지막엔 결국 RR 스케줄링이 된다. 단 Queue의 할당량을 다 사용할 때까지 다른 Queue에게 CPU를 빼앗기진 않음. 입출력에의해 할당량을 채우지 못하고 CPU를 빼앗기게되면 해당 프로세스의 우선순위를 한단계 높인다. 56 | - Round Robin 57 | - FCFS 스케줄링을 기반으로하여 CPU를 할당하되 각 프로세스는 한번에 쓸 수 있는 CPU 시간이 있어 그 시간이 지나면 시간종료 인터럽트에 의해 CPU를 빼앗가는 선점 방식의 스케줄링이다. 프로세스 하나가 CPU를 독점하는 단점을 막을 수 있지만 Context Switch의 오버헤드를 감수해야한다. 58 | 59 | ## DB Index 60 | 61 | > TODO... 62 | - Index란 무엇인가 63 | - Index의 자료구조 64 | - Primary index vs Secondary index 65 | - Composite index 66 | - Index의 성능과 고려해야할 사항 67 | 68 | ## Javascript Hoisting 69 | 70 | 변수의 정의와 할당이 분리되는 것을 뜻하며 해당 스코프의 최상단에 선언이 끌어올려지는 것을 의미한다. 71 | ES6에 와서 Reference Error때문에 let과 Const는 Hoisting이 안되는 것 처럼 보이지만 72 | 실제론 Temporal Dead Zone에 빠져있는 시기에 호출되었기 때문에 Reference Error가 뜨는 것이다. 73 | 변수 생성은 선언, 초기화, 할당 총 3가지의 단계로 이루어져있다. var는 선언과 초기화를 동시에 진행하기 때문에 74 | `var x = 1;`라면 선언과 초기화를 동시에 해서 `x = undefined`가 되었다가 할당을 통해 `x = 1`이 된다. 75 | 하지만 let / const는 선언과 초기화를 분리하여 진행하기 때문에 undefined로 초기화되기 전에 변수에 접근하면 76 | Reference Error가 뜨는 것이다. 77 | 78 | ```javascript 79 | let x = 1; 80 | { 81 | console.log(x); 82 | let x = 2; // Reference Error 83 | } 84 | 85 | /////// 86 | 87 | let x = 1; 88 | { 89 | console.log(x); // 1 90 | } 91 | ``` 92 | 93 | - [https://poiemaweb.com/es6-block-scope](https://poiemaweb.com/es6-block-scope) 94 | 95 | ## Javascript, What is 'This' 96 | 97 | Javascript의 this는 함수를 호출하는 방법에 의해 결정된다. 98 | 99 | - 전역 실행 컨텍스트에서 `this`는 `전역 객체`를 참조한다. 100 | - 함수 컨텍스트에서 `this` 101 | - 단순 함수 호출 102 | - non-strict: `전역 객체` 103 | - strict: 함수 실행시 할당된 값을 반환, 만약 정의 되지 않았다면 `undefined` 104 | - 객체의 메소드로서 `this` 105 | - 단순히 메소드에서 호출시 `호출한 객체`가 this가 된다. 106 | - 객체의 prototype 체인에서의 this도 `호출한 객체`가 this가 된다. 107 | - getter와 setter에서도 `호출한 객체`가 this가 된다. 108 | - 생성자에서 `this` 109 | - new에의해 생성된 객체가 this가 된다. 110 | - DOM 이벤트 핸들러로서 111 | - 함수가 이벤트 핸들러로 사용될 때는 이벤트가 발생한 Element가 this 112 | - in-line 이벤트 핸들러에서는 리스너가 위치한 `DOM 엘리먼트`가 할당됨 113 | 114 | - call, apply, bind 115 | - 세 메소드 모두 this를 특정한 객체와 연결해준다. 116 | - call과 apply는 this로 사용할 객체를 전달해줌과 동시에 함수를 실행한다. 117 | - bind는 넘겨준 객체를 this로 사용하는 새로운 함수를 생성한다. 118 | 119 | > bind 예제 120 | ```javascript 121 | function f1() { 122 | console.log(this.x) 123 | } 124 | 125 | const f2 = f1.bind({x: 1}) 126 | 127 | f2() // 1 128 | ``` 129 | 130 | - [https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this](https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this) -------------------------------------------------------------------------------- /Interview/question/week3.md: -------------------------------------------------------------------------------- 1 | # 목차 2 | 3 | 1. TDD란 무엇이며 어떠한 장점이 있는가? 4 | 2. Tree 5 | 3. Binary Tree 6 | 4. Full Binary Tree 7 | 5. Complete Binary Tree 8 | 6. BST(Binary Search Tree) 9 | 7. TCP와 UDP의 차이점 10 | 8. 동기와 비동기의 차이 11 | 9. Closure(javascript) 12 | 13 | ## TDD란 무엇이며 어떠한 장점이 있는가 14 | 15 | Test Driven Development로 테스트 코드를 먼저 짜고 Red - Green - Refactor의 Cycle로 진행되며 일단 실패하는 테스트 코드(명세에 따라서)를 작성 한 후 그 것을 통과하는 코드를 짜고 16 | 리팩토링을 진행하는 cycle로 개발을 해가는 개발 방법이다. TDD로 개발하면 Test Coverage가 높아지고 디버깅이 쉬워지며 코드의 신뢰성이 높아진다. 17 | 18 | ## Tree 19 | 20 | Tree T는 `parent-child relationship`을 갖도록 Element를 저장하는 node의 집합이다. 21 | parent-child relationship은 다음과 같은 속성을 만족한다. 22 | 23 | 1. Tree T가 비어있지 않으면 parent가 없는 특별한 node인 `root node`를 가진다. 24 | 2. Tree T의 각각의 node `v`에는 parent node인 `w`가 존재한다. `w`를 parent로 가지는 모든 node는 `w`의 child node이다. 25 | 26 | 또한 Tree가 될 수 없는 경우가 몇가지 있는데 27 | 28 | 1. node의 edge가 자기 자신을 향하는 경우 29 | 2. path에서 cycle이 생기는 경우 30 | 3. node가 2개 이상의 parent를 가지는 경우 31 | 4. 서로 연결되지 않은 subtree가 존재하는 경우 32 | 33 | - [Tree에 관하여](https://github.com/qkraudghgh/coding-interview/blob/master/DataStructure/Tree/Tree.md) 34 | 35 | ## Binary Tree 36 | 37 | Child node의 개수가 최대 2개인 Ordered Tree를 Binary Tree라고 한다. 38 | Ordered Tree인 이유는 Ordered Tree의 의미 자체가 순서가 정해진 Tree라는 뜻이고 Binary Tree는 left Child가 right Child 보다 순서가 앞선다는 특징이 있다. 39 | 40 | - [ordered Tree](http://cs.lmu.edu/~ray/notes/orderedtrees/) 41 | 42 | ## Full Binary Tree 43 | 44 | leaf node를 제외하고 모든 node가 child node를 2개씩 가지는 Tree 45 | 46 | - [Full and Complete Binary Tree](http://web.cecs.pdx.edu/~sheard/course/Cs163/Doc/FullvsComplete.html) 47 | 48 | ## Complete Binary Tree 49 | 50 | Tree의 마지막 Level을 제외하고는 모든 level이 완벽하게 채워져 있어야하고 가능한 왼쪽 노드부터 채워져 있어야 한다는 속성을 가진 Tree 51 | 52 | ## BST(Binary Search Tree) 53 | 54 | Binary search Tree는 다음과 같은 속성을 만족하는 Binary Tree이다. 55 | 56 | 1. parent node `v` 기준 left Child의 모든 node는 v보다 작거나 같아야한다. 57 | 2. parent node `v` 기준 right Child의 모든 node는 v보다 크거나 같아야한다. 58 | 59 | Inorder traversal시 Sorting된 결과물이 나온다. 60 | 특정 element를 search시 expected O(log n), unbalance Tree(1, 2, 3, 4, 5 처럼 right child로 치우쳤을 경우(Linked list와 닮은))일 때 Big O(n) 61 | 62 | - [Binary Search Tree](http://cs.lmu.edu/~ray/notes/binarysearchtrees/) 63 | 64 | ## TCP와 UDP의 차이점 65 | 66 | TCP는 ACK와 Timeout, 재전송을 매개로 불안정한 네트워크에 안정성을 더한다. 하지만 UDP는 저런 안전 장치들이 존재하지 않고 데이터를 전송하기만한다. 67 | 즉 별거 안해서 TCP보다 UDP가 빠르지만 데이터 손실이 크다. 68 | 69 | - [인벤에 이런.. 좋은 글이..](http://www.inven.co.kr/webzine/news/?news=165870) 70 | 71 | ## 동기와 비동기의 차이 72 | 73 | - Synchronous Programming 74 | - 결과값을 바로 돌려받아야 다음 작업을 실행 할 수 있는 프로그래밍 방식 75 | - Asynchoronous Programming 76 | - 프로그램의 주 실행흐름에 멈춤이 없이 결과값이 바로 주어지지 않더라도 즉시 다른 작업을 수행 할 수 있도록 만드는 프로그래밍 방식 77 | - Promise 객체를 즉시 돌려받거나, callback function 같은 방식으로 결과 값에대한 처리를 한다. 78 | - Asynchronous가 Non-blocking IO는 아니며 비동기 프로그래밍을 충족시키기위한 재료로 Non-blocking IO를 사용할 수도 있다. 79 | - Blocking IO 80 | - I/O처리가 끝날때까지 CPU는 유휴상태가 되며 작업이 끝나면 결과값을 반환 81 | - Non-blocking IO 82 | - I/O처리가 끝나지 않더라도 특정 상태값이 바로 반환되며 CPU는 유휴상태에 들어가지 않고 다른 작업을 처리할 수 있게된다. IO에대한 결과값은 나중에 시그널을 주어 처리 83 | 84 | - [Synchronous & Asynchoronous](https://tech.peoplefund.co.kr/2017/08/02/non-blocking-asynchronous-concurrency.html) 85 | 86 | ## Closure(javascript) 87 | 88 | 클로저는 함수와 함수가 선언된 어휘적 환경의 조합이다. 89 | 클로저를 이용하여 Private method 등을 흉내낼 수 있다. 90 | 91 | - [Closure](https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Closures) 92 | - [Closure2](http://meetup.toast.com/posts/86) -------------------------------------------------------------------------------- /Interview/sorting/bubleSort.js: -------------------------------------------------------------------------------- 1 | const arr = [5, 4, 3, 2, 1]; 2 | 3 | function bubleSort(arr) { 4 | const copied = arr.slice(); 5 | let swapped; 6 | do { 7 | swapped = false; 8 | for (let i=0; i < copied.length-1; i++) { 9 | if (copied[i] > copied[i+1]) { 10 | [copied[i], copied[i+1]] = [copied[i+1], copied[i]] 11 | swapped = true; 12 | } 13 | } 14 | } while (swapped); 15 | return copied; 16 | } 17 | 18 | console.log(bubleSort(arr)) -------------------------------------------------------------------------------- /Interview/sorting/heapSort.js: -------------------------------------------------------------------------------- 1 | const arr = [5, 4, 3, 2, 1]; 2 | 3 | function heapify(unsorted, index, heapSize) { 4 | let largest = index; 5 | const leftIndex = 2 * index + 1; 6 | const rightIndex = 2 * index + 2; 7 | if (leftIndex < heapSize && unsorted[leftIndex] > unsorted[largest]) largest = leftIndex; 8 | if (rightIndex < heapSize && unsorted[rightIndex] > unsorted[largest]) largest = rightIndex; 9 | if (largest != index) { 10 | [unsorted[largest], unsorted[index]] = [unsorted[index], unsorted[largest]]; 11 | heapify(unsorted, largest, heapSize) 12 | } 13 | } 14 | 15 | function heapSort(unsorted) { 16 | const length = unsorted.length; 17 | for (let i = Math.floor(length)-1; i > 0; i--) { 18 | heapify(unsorted, i, length); 19 | } 20 | for (let i = length-1; i > 0; i--) { 21 | [unsorted[0], unsorted[i]] = [unsorted[i], unsorted[0]]; 22 | heapify(unsorted, 0, i); 23 | } 24 | return unsorted; 25 | } 26 | 27 | console.log(heapSort(arr)) -------------------------------------------------------------------------------- /Interview/sorting/insertionSort.js: -------------------------------------------------------------------------------- 1 | const arr = [5, 4, 3, 2, 1]; 2 | 3 | function insertionSort(arr) { 4 | const copied = [...arr]; // copy 5 | for (let i = 1; i < copied.length; i++) { // key는 2번 element부터 시작 6 | for (let j = i; j > 0 && copied[j] < copied[j-1]; j--) { // 비교는 Key값부터 시작하고 key값부터 왼쪽으로 비교하면서 swap 7 | [copied[j], copied[j-1]] = [copied[j-1], copied[j]] 8 | } 9 | } 10 | return copied; 11 | } 12 | 13 | console.log(insertionSort(arr)) -------------------------------------------------------------------------------- /Interview/sorting/mergeSort.js: -------------------------------------------------------------------------------- 1 | const unsortedArr = [5, 4, 3, 2, 1]; 2 | 3 | function merge(leftArr, rightArr) { 4 | const sortedArr = []; 5 | while (leftArr.length && rightArr.length) { 6 | if (leftArr[0] <= rightArr[0]) { 7 | sortedArr.push(leftArr.shift()); 8 | } else { 9 | sortedArr.push(rightArr.shift()); 10 | } 11 | } 12 | 13 | while (leftArr.length) 14 | sortedArr.push(leftArr.shift()); 15 | while (rightArr.length) 16 | sortedArr.push(rightArr.shift()); 17 | 18 | return sortedArr; 19 | } 20 | 21 | function mergesort(arr) { 22 | if (arr.length < 2) { 23 | return arr; 24 | } else { 25 | const midpoint = Math.floor(arr.length / 2); 26 | const leftArr = arr.slice(0, midpoint); 27 | const rightArr = arr.slice(midpoint, arr.length); 28 | return merge(mergesort(leftArr), mergesort(rightArr)); 29 | } 30 | } 31 | 32 | console.log(mergesort(unsortedArr)); -------------------------------------------------------------------------------- /Interview/sorting/quickSort.js: -------------------------------------------------------------------------------- 1 | /* 2 | - quick sort - 3 | unstable하다. 4 | O(nlogn) 단, Pivot이 계속 (1, n-1) 개수로 나뉠 경우 O(n^2)까지 속도가 떨어진다. 5 | 이미 정렬되어 있는 배열이 그 예가 될 수 있다. 6 | 그래서 pivot을 매번 random하게 정하는 randomize quicksort는 좀더 O(nlogn)의 근사치에 가까워진다. 7 | 구현이 쉽고 빨라서 가장 많이 이용하는 정렬 알고리즘이라고 한다. 8 | */ 9 | 10 | function quick(arr, left, right) { 11 | function positioning(arr, left, right) { 12 | let i = left; 13 | let j = right; 14 | const pivot = arr[left]; 15 | 16 | while (i < j) { 17 | while (arr[j] > pivot) { 18 | j--; 19 | } 20 | while (i < j && arr[i] <= pivot) { 21 | i++; 22 | } 23 | [arr[i], arr[j]] = [arr[j], arr[i]]; 24 | } 25 | [arr[left], arr[i]] = [arr[i], arr[left]]; 26 | 27 | return j; 28 | } 29 | 30 | if (left < right) { 31 | const position = positioning(arr, left, right); 32 | quick(arr, left, position - 1); 33 | quick(arr, position + 1, right); 34 | } 35 | return arr; 36 | } 37 | 38 | const unsortedArr = [5,4,3,2,1]; 39 | console.log(quick(unsortedArr, 0, unsortedArr.length - 1)) -------------------------------------------------------------------------------- /Interview/sorting/selectionSort.js: -------------------------------------------------------------------------------- 1 | const arr = [5, 4, 3, 2, 1]; 2 | 3 | function selectionSort(arr) { 4 | const copied = [...arr]; 5 | for (let i = 0; i < copied.length; i++) { 6 | let key = i; 7 | for (let j = i+1; j < copied.length; j++) { 8 | if (copied[j] < copied[key]) key = j; 9 | } 10 | [copied[i], copied[key]] = [copied[key], copied[i]]; 11 | } 12 | return copied; 13 | } 14 | 15 | console.log(selectionSort(arr)) -------------------------------------------------------------------------------- /Network/IPAndDNS.md: -------------------------------------------------------------------------------- 1 | # IP주소와 DNS 2 | ## IP 3 | - 컴퓨터 네트워크에서 장치들이 서로를 인식하고 통신을 하기 위해서 사용하는 특수한 번호. 4 | 5 | ### IPv4 6 | - ![IPv4](./images/ipv4.png) 7 | - 크기가 32비트인 주소값으로 대게 `dotted-decimal notation`을 이용해 표기한다. 8 | - dot으로 구분된 각 숫자는 8비트씩(octet) 나타낼 수 있으며 0~255의 범위를 나타낸다. 9 | 10 | #### Class 11 | - IP 주소는 `Network ID`와 `Host ID`로 이루어져 있다. 12 | - IPv4는 5개의 클래스로 나누어져 있는데 각각 A, B, C, D, E Class이다. 13 | - A Class는 처음 8bit(1byte)가 Network ID이며, 나머지 24bit(3Byte)가 Host ID이다. `(0.0.0.0 ~ 127.255.255.255)` 14 | - B Class는 처음 16bit(2byte)가 Network ID이며, 나머지 16bit(2Byte)가 Host ID이다. `(128.0.0.0 ~ 191.255.255.255)` 15 | - C Class는 처음 24bit(3byte)가 Network ID이며, 나머지 8bit(1Byte)가 Host ID이다. `(192.0.0.0 ~ 233.255.255.255)` 16 | - D Class는 Multicast(한 번의 송신으로 메시지나 정보를 여러 컴퓨터에 동시에 전송하는 것, 즉 그때 이용되는 IP)이다. 17 | - E Class는 예약된 IP주소들로 미래에 쓰기위해 남겨두었다. 18 | 19 | ### Private address (비공개 주소) 20 | - 직접 인터넷에 연결되지 않고 NAT(Network Address Translation)을 이용해 인터넷에 접속되는 사설망 21 | - 대표적으로 `192.168.0.0`이 있으며 홈 라우터에 의해 `192.168.0.0 ~ 192.168.0.255/24`까지 할당 된다. 22 | 23 | ### IPv6 24 | - IPv4의 32비트에서 128비트(16 octet)으로 증가하여 더 많은 IP주소를 할당할 수 있는 주소 25 | - IPv4의 주소가 모자라게되면서 IPv4는 더 많은 주소를 네트워크에 할당하기 위해 `Network Fragmentation`이 지속적으로 증가하게되어 라우터에 많은 부담을 주고있어 26 | 이를 해결하기위해 IPv6가 새로 설계되었다. 27 | 28 | ## DNS 29 | - Domain Name Service 30 | - Host의 도메인 이름을 네트워크 주소로 바꾸거나 그 반대의 변환을 수행할 수 있도록 하기위해 개발됨 (www.example.com -> 10.124.12.45 혹은 그 반대) 31 | - Socket Library의 `리졸버`를 호출하여 도메인 이름으로부터 네트워크 주소를 받아온다. 32 | - DNS Name Server: DNS 데이터베이스 레코드를 저장하는 물리적 서버 33 | - 리졸버 호출 -> 리졸버가 DNS 서버에 `조회 메시지` 보냄 -> DNS 서버에서 응답 메시지 받음 34 | - 조회 메시지 35 | - Name : 서버나 메일 배송 목적지와 같은 이름 36 | - Class : 인터넷 이외의 네트워크를 구분하기위해 설계되었지만 지금은 인터넷 이외엔 소멸되어 항상 `IN`이 적혀있음 37 | - Type 38 | - 타입에 따라 클라이언트에 회답하는 정보의 내용이 달라짐 39 | - **A** Type: 도메인 이름에서 IP 주소를 조사 40 | - **MX** Type: 메일 주소를 조사 41 | - **PTR** Type: IP 주소에서 도메인 이름을 조사 42 | - **CNAME** Type: 이름에 alias를 붙임 43 | - **NS** Type: 리졸버가 요청한 DNS 서버에 조회메시지에 알맞는 정보가 없다면 다른 DNS 서버의 IP를 NS TYPE과 함께 회답함 44 | - **SOA** Type: 도메인 자체의 속성 정보를 등록 45 | - 조회 메시지에 해당하는 Name, Class, Type이 모두 맞는 것을 DNS 서버에서 찾아서 회신함 46 | 47 | ### 도메인의 계층 48 | - www.example.co.kr 49 | - kr 도메인 -> co 도메인 -> example 도메인 -> www 도메인 50 | - Kr이 가장 상위 도메인이다. 51 | - co는 kr의 서브도메인이며 example은 co의 서브도메인이다. 52 | - 서브도메인은 127단계까지 가능함 53 | 54 | ### DNS에서 등록한 정보를 찾아내는 방법 55 | `www.example.co.kr`를 브라우저에 입력 56 | 57 | 0. DNS 캐시와 hosts파일에 도메인 정보가 있는지 확인 (있으면 여기서 끝나고 없으면 1번으로) 58 | 1. 가장 가까운 DNS 서버(로컬 DNS 서버)에 `www.example.co.kr` 도메인 정보 요청 59 | 2. 로컬 DNS 서버엔 `www.example.co.kr`에 대한 정보가 없기 때문에 루트 DNS 서버에 다시 질의 60 | 3. 루트 DNS 서버는 `www.example.co.kr`에 대한 정보가 없지만 `kr 도메인`을 관리하고 있는 서버 정보를 알려줌 61 | 4. 로컬 DNS 서버는 `www.example.co.kr`에 대한 정보를 `kr 도메인`을 관리하고 있는 서버에 질의 62 | 5. kr 도메인을 관리하고있는 DNS 서버는 `www.example.co.kr`에 대한 정보가 없지만 `co 도메인`을 관리하고 있는 서버 정보를 알려줌 63 | 6. recursive하게 도메인을 질의하여 `example 도메인`을 관리하는 DNS 서버까지 도달하면 `www.example.co.kr`에 대한 정보를 알 수 있음 64 | 7. 로컬 DNS 서버는 `www.example.co.kr`의 IP 정보를 사용자의 PC에 알려줌 65 | 66 | - DNS 캐시는 정확도를 위해 일정 시간이 지나면 파기한다. 67 | - 리졸버에 의해 IP 번호를 받아오면 DNS 캐시에 의한 정보인지 DNS 서버 회답인지도 알 수 있다. 68 | -------------------------------------------------------------------------------- /Network/WebBrowser.md: -------------------------------------------------------------------------------- 1 | # HTTP 2 | - **HTTP Protocol**: 클라이언트와 서버가 주고받는 메시지의 내용이나 순서를 정한 것 3 | - **URL**: Uniform Resource Locator ex) `http://~~~~~` 4 | - **URI**: Uniform Resource Indetifier ex) `/dir/file.html` 5 | 6 | ## HTTP 기본 개념 7 | ![http](./images/http.png) 8 | 9 | ## HTTP Message 10 | ### HTTP Request Message 11 | ``` 12 | <메서드><공백><공백> // 리퀘스트 라인(Request Line) 13 | <필드명>:<필드값> /* 여기서부터 메시지 헤더 14 | . 15 | . 16 | . 한 행에 한 개의 헤더 필드 17 | . 18 | . 19 | <공백 행> 공백 행까지 포함해서 메시지 헤더 */ 20 | <메시지 본문> // 클라이언트에서 서버에 송신하는 Data(Form data 등) 21 | ``` 22 | ### HTTP Response Message 23 | ``` 24 | <공백><스테이터스 코드><공백><응답 문구> // 스테이터스 라인(Status Line) 25 | <필드명>:<필드값> /* 여기서부터 메시지 헤더 26 | . 27 | . 28 | . 한 행에 한 개의 헤더 필드 29 | . 30 | . 31 | <공백 행> 공백 행까지 포함해서 메시지 헤더 */ 32 | <메시지 본문> // 서버에서 클라이언트로 송신하는 데이터, 바이너리 데이터로 취급 33 | ``` 34 | -------------------------------------------------------------------------------- /Network/images/http.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/Network/images/http.png -------------------------------------------------------------------------------- /Network/images/ipv4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/Network/images/ipv4.png -------------------------------------------------------------------------------- /OS/CPUScheduling.md: -------------------------------------------------------------------------------- 1 | # CPU 스케줄링 2 | - 메모리에 여러개의 프로세스를 올려놓고(다중 프로그래밍), CPU의 가동시간을 적절히 나누어(시분할) 각각의 프로세스에게 분배하여 실행되도록 한다. 3 | - 여러 프로세스들이 번갈아가며 사용해야하는 자원이 있을경우 주어진 시점에서 어떤 프로세스가 이 자원을 사용할 수 있도록 해줄 것인가를 결정하는것. 4 | 5 | ## 스케줄링의 단계 6 | - 요구되는 시점으로 구분함 7 | - 장기(Long-term) 8 | 1. 어느 작업을 커널에 등록시켜 프로세스로 만들어 줄 것인가(Job Scheduling) 9 | 2. 일괄 처리: 작업이 들어오면 디스크에두고 일괄처리 큐에서 대기후 장기 스케줄러를 거쳐 프로세스가 되도록 함 10 | 3. 시분할: 사용자의 접속시도를 허용할지 말지 결정 11 | 4. 다중 프로그래밍의 정도를 조절 12 | 5. 수행 횟수가 적고 대부분 `FIFO(First In First Out)`방식을 사용 13 | - 중기(Medium-term) 14 | - 보류 상태의 프로세스들 중에서 어느 프로세스에게 메모리를 할당해 줄 것인가 (Swapping) 15 | - 단기(Short-term) 16 | - 준비상태의 프로세스중에서 어느 프로세스에게 CPU를 할당할지 결정 17 | - 프로세스 스케줄러 or Dispatcher에 의해 수행 18 | 19 | ## 스케줄링의 목적과 기준 20 | - 사용자 관점: 응답시간 21 | - 시스템 관점: 처리량 22 | - 동시에 만족시키긴 힘들다 23 | - CPU 연산 > 입출력 : CPU-Bound 프로세스 24 | - CPU 연산 < 입출력 : I/O-Bound 프로세스 25 | 26 | ## 스케줄링 기법들 27 | - 스케줄링이 가동되어야 할 때 28 | 1. 프로세스가 실행에서 대기상태로 (입출력 요청) 29 | 2. 프로세스가 실행에서 준비로 (시간종료같은 인터럽트) 30 | 3. 프로세스가 대기에서 준비로 (입출력 종료) 31 | 4. 프로세스가 수행을 마치고 종료 32 | 33 | - 비선점(Nonpreemptive) 방식 34 | - 한 프로세스가 CPU를 할당 받았을 때 스스로 반환 할 때까지 계속 사용하도록 허용함 35 | - 선점(Preemptive) 방식 36 | - CPU를 할당받아 실행중인 프로세스로부터 CPU를 빼앗아 다른 프로세스에게 할당 가능 37 | 38 | ### FCFS(First Come First Service) 39 | - ![FCFS](./images/FCFS.png) 40 | - 비선점 방 41 | - 준비큐에 들어온 순서대로 처리 42 | - 어떤 순서대로 처리될지 예측 가능성이 높다 43 | - 평균 응답시간 계산 44 | - | 프로세스 | 도착 시간 | CPU 요구량 | 45 | |----|---|-----| 46 | | P1 | 0 | 100 | 47 | | P2 | 0 | 10 | 48 | | P3 | 0 | 10 | 49 | | P4 | 0 | 10 | 50 | - P1 -> P2 -> P3 -> P4 순서대로 준비 큐에 들어왔다고 가정 51 | - 평균 응답시간 = (100+110+120+130)/4 = 115초 52 | - P4 -> P3 -> P2 -> P1 순서대로 준비 큐에 들어왔다고 가정 53 | - 평균 응답시간 = (10+20+30+130)/4 = 47.5초 54 | ### SPN(Shortest Process Next) 혹은 Shortest Job First 55 | - CPU 요구량이 적은 것 부터 처리 56 | - 비선점 방식 57 | - CPU 요구량이 높은것은 무한대기 할 수도 있음 58 | - 어떤 순서대로 처리될지 예측 힘듦 59 | - 무한대기 가능성을 낮추기위해 에이징(Aging)을 이용하기도 함(대기가 오래될 수록 우선순위를 높여줌) 60 | - 평균 응답시간 계산 61 | - | 프로세스 | 도착 시간 | CPU 요구량 | 62 | |----|-----|----| 63 | | P1 | 0 | 10 | 64 | | P2 | 0.5 | 5 | 65 | | P3 | 1 | 2 | 66 | - P1 -> P3 -> P2 순서대로 처리된다 67 | - P1이 가장 먼저 도착 후 CPU를 10초 동안 사용했으므로 P2, P3는 이미 도착해 있고 이때는 CPU의 요구량이 적은 P3부터 처리된다. 68 | - 평균 응답시간 = (10+(12-1)+(17-0.5))/3 = 12.5초 69 | 70 | ### SRT(Shortest Remaining Time) 71 | - SPN을 선점 방식으로 운영 72 | - CPU 요구량이 작은게 많이 들어오면 Context Switching 비용이 많이 든다. 73 | - 임계 값을 두어 선점을 못하게 해서 Context Switching이 덜되게 개선 가능하다. 74 | - 평균 응답시간 계산 75 | - | 프로세스 | 도착 시간 | CPU 요구량 | 76 | |----|-----|----| 77 | | P1 | 0 | 10 | 78 | | P2 | 0.5 | 5 | 79 | | P3 | 1 | 2 | 80 | - P1 -> P2 -> P3 -> P2 -> P1 순서대로 처리됨 81 | - CPU를 할당하지 않고 대기했다가 처리하는게 더 빠를 수도 있음 82 | - 1초 대기 -> P3 -> P2 -> P1 순서대로 처리되고 평균 응답 시간을 계산해보면 더 빠르다. (Context Switching도 덜 발생) 83 | 84 | ### HRRN(Highest Response Ratio Next) 85 | - SPN과 SRT 방식의 약점인 수행시간이 긴 프로세스의 무한대기 현상을 방지하기 위한 기법 86 | - 응답률이 가장 높은 프로세스에게 높은 우선순위를 부여한다. 87 | - 비선점 방식 88 | - 응답률 = (대기시간 + CPU 요구량)/CPU 요구량 89 | 90 | ### Round-Robin(라운드 로빈) 91 | - ![round-robin](./images/round-robin.png) 92 | - FCFS 스케줄링을 기반으로하여 CPU를 할당하되 각 프로세스는 한번에 쓸 수 있는 CPU 시간(시간 할당량)이 지나면 시간종료 인터럽트에 의해 CPU를 빼앗긴다. 93 | - 선점 방식 94 | - FCFS에서 프로세스 하나가 CPU를 독점하는 단점을 방지하지만 Context Switch의 오버헤드를 감수해야함 95 | 96 | ### Multi-Level Queue(다단계 큐) 97 | - 정적 우선순위를 사용하는 스케줄링 98 | - 선점 방식 99 | - 우선순위 개수만큼 Queue가 있다. 100 | - 가장 우선순위가 높은 Queue부터 작업을 처리하다가 더 높은 우선순위가 들어오면 선점 방식으로 CPU를 빼앗아 할당함 101 | - 우선순위가 정적이므로 프로세스가 다른 우선순위 Queue에 들어갈 수 없다 102 | 103 | ### Multi-Level Feedback Queue(다단계 피드백 큐) 104 | - 동적 우선순위를 사용하는 스케줄링 105 | - 선점 방식 106 | - 우선순위 개수만큼 Queue가 존재 (CPU 할당량이 낮을수록 우선순위가 높다) 107 | - 최상위 단계의 준비큐부터 FCFS의 순서로 실행 후 해당 큐의 할당량이 끝나면 아래 준비큐에 들어감 108 | - 큐의 할당량을 다 사용할때까진 우선순위가 높은 큐에 CPU를 바로 빼앗기진 않는다. 109 | - 우선순위가 낮을수록 시간 할당량이 많다. 110 | - 마지막엔 결국 Round-Robin 방식이 됨 111 | - 입출력에의해 할당량을 채우지 못하고 CPU를 내놓게되면 입출력 Process를 한단계 높은 큐로 옮긴다. 112 | 113 | ### Fair-Share 스케줄링 114 | - ![Fair-Share](./images/fair.png) 115 | - 모든 프로세스를 한 그룹으로 두지 않고 여러그룹으로 두어 특정 프로세스가 CPU를 많이 사용했을 때 다른 그룹까지 피해가 가지 않도록 하는 방식 116 | - 그림을 보면 A 프로세스가 CPU를 많이 사용했지만 2그룹과 3그룹엔 영향이 없는 것을 볼 수 있다. 117 | 118 | ## 실시간(Realtime) 스케줄링 119 | - 실시간 시스템 120 | - 실행될 모든 프로세스들이 정해진 시간 내에 완료되어야하는 시스템 121 | - Hard Realtime 122 | - Deadline 내에 작업이 완료되지 않으면 치명적인 결과를 냄 (시스템 중지 등) 123 | - Soft Readtime 124 | - Deadline이 지나고 완료된 일은 가치가 점점 떨어짐 125 | - 정적 방법: 프로세스들의 특징과 개수를 알 때 유용 126 | - 동적 방법: 생성시간이나 특성을 모를경우 사용 127 | 128 | ### RM(Rate Monotonic) 알고리즘 129 | - 대표적인 정적 스케줄링 방식 130 | - 크기와 개수가 알려진 프로세스들이 주기적으로 발생하는 환경에서 사용 131 | - 주기에 반비례하게 우선순위 배정 132 | - ![rm](./images/rm.png) 133 | - 위 공식을 이용하여 스케줄링이 가능한지 여부를 알 수 있음 (T는 주기, C는 CPU 요구량) 134 | - 스케줄링 비용이 적은대신 새로운 프로세스가 추가되면 전체 스케줄링을 다시 해야한다. 135 | 136 | ### EDF(Earliest Deadline First) 알고리즘 137 | - 프로세스의 마감 시한이 가까울수록 우선순위를 높게 부여 138 | - 선점형 동적 스케줄링 139 | - ![edf](./images/edf.svg) 140 | - 위 공식을 이용하여 스케줄링이 가능한지 여부를 알 수 있음 141 | - 새로운 프로세스의 동적인 수용이 가능하지만 그럴때마다 가능한 스케줄을 찾아야하는 비용 발생 142 | 143 | ## Windows에서의 스케줄링 144 | - 스레드 단위로 CPU를 할당하는 우선순위에의한 선점 스케줄링 145 | - 우선순위 0~15 -> 일반 클래스 배정 : MFQ로 구현 146 | - 우선순위 16~31 -> 실시간 클래스 배정 : MQ로 구현 147 | - 우선순위 변동 148 | - 시간종료 인터럽트에의해 CPU를 빼앗기면 우선순위를 낮춤 149 | - 입출력 완료 인터럽트에의해 CPU를 빼앗기면 우선순위를 높임 150 | -------------------------------------------------------------------------------- /OS/Deadlock.md: -------------------------------------------------------------------------------- 1 | # 교착 상태(DeadLock) 2 | - 자원이 한정적인 상황에서 두 개 이상의 프로세스가 각자 먼저 확보한 자원을 가진 채 상대방의 자원을 필요로 할 경우, 3 | 외부로부터의 조치가 없는 한 이들은 아무 일도 못하고 계속 기다려야 할 것이고 이를 `교착 상태(DeadLock)`이라고 한다. 4 | - 교착 상태의 문제점 5 | 1. 해당 프로세스들이 더 이상 실행되지 못하여 사용자들에게 응답해주지 못함 6 | 2. 보유된 자원들이 교착 상태에 벗어나기 전까진 전혀 활용되지 못한다. 7 | 8 | ## 자원이란? 9 | - 물리적인 분류 10 | 1. 하드웨어 자원: 눈으로 보고 만질 수 있는 모든 자원(하드디스크, 메모리) 11 | 2. 소프트웨어 자원: 데이터, 메시지 등 12 | - 선점 가능성으로 분류 13 | 1. 선점 가능(preemptible) 자원: CPU, 메모리처럼 한 프로세스에 의해 사용도중 선점되어 다른 프로세스에게 할당(Allocation)해 주었다가 14 | 다시 원래 프로세스에게 돌려주어도 되는 자원 15 | 2. 선점 불가능(Nonpreemptible) 자원: 선점이 될 경우 자원을 빼앗긴 프로세스는 정상적인 진행을 포기해야하는 불이익을 받게되는 자원 16 | - 사용되는 방식에 따른 분류 17 | 1. 공유 가능(sharable) 자원: 한 프로세스에 할당된 자원을 동시에 다른 프로세스가 할당받아 같이 사용가능 18 | 2. 배타적 사용(Exclusive Use) 자원: 공유가능하지 않은 자원(CPU, 메모리, 테이프, 버퍼, 키보드, 모니터) 19 | - 재사용 가능 여부에 따른 분류 20 | 1. 순차적 재사용 가능(Serially Reusable) 자원: 먼저 할당된 자원이 사용 후 반납(Release)되었을 때 자원 자체는 계속 존재하여 또다른 프로세스에 할당 가능한 자원 (CPU, 메모리, 테이프, 하드디스크, 버퍼, 프로그램) 21 | 2. 소모성(Consumable) 자원: 사용 후 사라지는 자원 (signal, message) 22 | 23 | ## 프로세스가 자원에 취할 수 있는 행동 24 | 1. 필요한 자원에 대한 요청 25 | - 요청된 자원이 사용가능시 할당 받는다. 26 | - 사용 중인 자원에 요청시 해당 자원이 반납될 때까지 대기한다. 27 | 2. 사용이 끝난 자원 반납 28 | - System call로 자원을 반납한다. 29 | 30 | ## 교착 상태의 원인은? 31 | - 아래 4가지 원인을 모두 가지고 있어야만 데드락에 빠진다. 32 | - 한 개라도 해당시 데드락에 빠지지 않음. 33 | 34 | 1. 자원의 배타적인 사용(Mutual Exclusion Condition) 35 | 2. 자원의 부분 할당(Hold & Wait Condition) 36 | - 프로세스가 필요한 자원을 확보해나가다 이미 확보된 자원을 지닌채 대기에 빠짐 37 | 3. 자원의 선점 불가능성(Nonpreemptive Condition) 38 | - 자원의 선점 불가능성을 고수 할 경우 데드락에 빠질 수 있음 39 | 4. 자원에 대한 순환 대기 40 | 41 | ## 교착 상태 해결 방 42 | 1. 예방: 교착 상태를 아예 발생하지 않도록 함 43 | 2. 회피: 교착 상태를 피하도록 함 44 | 3. 복구: 교착 상태에 빠지도록 두었다가 후에 조치 45 | 46 | ### 예방 기법 47 | - 교착 상태가 아예 발상해지 않도록 할 수 있으나 자원낭비와 특정 프로세스의 무한 대기 가능성이 있다. 48 | 1. 자원의 배타적 사용 조건을 배제한다. 49 | - 모든 자원을 공유자원으로 두어 교착 상태 발생을 차단 50 | - 공유 가능한 자원이 될 수 없는 자원(프린트, 테이프 장치 등)이 있어 `실현 불가능` 51 | 2. 자원의 부분 할당을 배제 52 | - 부분 할당을 없애겠다 -> 모두 한번에 할당하겠다. 53 | - 즉 프로세스들이 자신이 필요한 모든 자원을 미리 할당 받아 실행한다. 54 | - 자원 낭비 및 무한 대기를 일으킬 수 있다. 55 | 3. 자원의 선점 불가능을 배제 56 | - 모든 자원이 선점 가능하도록 한다. 57 | - 어떤 프로세스는 계속 일을 마치지 못하고 선점당해 무한대기에 빠질 수 있다. 58 | 4. 자원의 환형 대기 상황을 배제 59 | - 자원 확보에 순서를 정하여 교착상태 예방 60 | - 자원 낭비 및 무한 대기 상태가 일어날 수 있음 61 | 62 | ### 회피 기법 63 | - 교착 상태로 가는 것을 막겠다는 점에서 예방과 다를 바 없지만 발생조건을 배제하는 방식이 아닌 다른 알고리즘을 이용하는 기법이다. 64 | - 안전 상태: 모든 프로세스가 유한(Finite) 시간 내에 정상 종료될 수 있는 상태, 교착 상태가 발생할 수 없는 상태 65 | - 불안전(Unsafe) 상태: 안전 상태가 아닌 경우, 교착 상태로 갈 가능성이 있고 그럴경우 방지책이 없다. 66 | - 즉 회피 기법이란 시스템이 안정 상태로만 가도록 지속적으로 제어해 나가는 것을 의미한다. 67 | - ![unsafe](./images/unsafe.png) 68 | 69 | #### Dijkstra의 은행가 Algorithm 70 | - 프로세스가 자원을 요구할 때 시스템이 자원을 할당한 후 안정 상태로 남아있는지 사전에 검사하여 교착상태를 회피하는 방법 71 | - 은행가 알고리즘이 제대로 동작하기위한 가정 72 | - 시스템 내의 프로세스 수가 고정되어 있어야 함 `(현실적으로 힘듦)` 73 | - 자원의 수 역시 고정되어 있어야 함 `(현실적으로 힘듦)` 74 | - 각 프로세스가 요구할 자원의 최대 개수가 알려져 있어야 함 `(현실적으로 힘듦)` 75 | - 각 프로세스는 할당 받은 자원을 사용 후 반드시 반납해야 함 76 | - 실제 계산해보기 77 | - | 프로세스 | 현재 보유량 | 최대 요구량 | 78 | |---|---|---| 79 | | P1 | 1 | 4 | 80 | | P2 | 4 | 6 | 81 | | P3 | 5 | 8 | 82 | - 자원 여유량은 `2` 83 | - 안전한 상태인가? 84 | - 시스템의 전체 자원 수: `1 + 4 + 5 + 2 = 12` 85 | - P2가 추가로 자원을 요구 할 경우 필요한 자원: `6 - 4 = 2` 86 | - 여유량이 2이므로 P2 프로세스를 성공적으로 종료 할 수 있고 이후 여유량은 `6` 87 | - 6개의 자원으로 P1, P3 어떤 프로세스든 커버 가능하다. 88 | - 현 상태에서 모든 프로세스가 정상적으로 종료할 수 있는 길이 적어도 1개 이상이므로 교착상태 회피 가능 -> 안전한 상태이다 89 | - P1, P3에서 자원을 먼저 요구 할 경우 불안전 상태가 되지만 은행가 알고리즘에 의해 P2를 먼저 실행하게되어 안전상태로 유지하는 것 90 | 91 | ### 탐지 기법 92 | - 교착 상태를 찾아낸다. (교착 상태의 발생을 허용) 93 | - OS에있는 탐지 프로그램이 탐지한다. 94 | - 탐지 프로그램이 알 수 있는 적당한 형태로 시스템이 표현되어 있어야 하는데, 이를 `자원 할당 그래프(Resource Allocation Graph, RAG)`라 부른다. 95 | - [RAG에 대한 설명](https://github.com/angrave/SystemProgramming/wiki/Deadlock,-Part-1:-Resource-Allocation-Graph) 96 | - RAG에 대한 그래프 제거법 혹은 그래프 탐색 방법으로 탐지 97 | 98 | ### 복구 기법 99 | - 교착 상태로부터 벗어나기 위한 방법 100 | - 프로세스 종료 방식 101 | - 교착 상태를 형성한 프로세스들 중 몇 개를 강제로 종료시켜 이들로부터 반납된 자원으로 복구 102 | - 종료비용을 따져서 종료하게 된다. 103 | - 종료비용이란 강제 종료되는 프로세스가 잃게되는 일의 양으로부터 산출한 비용 104 | 1. 종료 비용이 작은 것부터 순차적으로 종료 105 | 2. 교착 상태의 프로세스들의 모든 부분집합을 구하여 최소 종료비용의 부분집합 프로세스를 전부 종료 106 | - 교착 상태가 제거 되었는지 매번 확인해야하며 모든 부분집합에 대한 최소비용을 구하기가 복잡하다. 107 | 108 | - 자원의 선점에의한 방식 109 | - 필요한 자원을 가지고 있는 프로세스에게 강제로 빼앗아 할당 110 | - 프로세스 종료방식과 다른점은, 선점당하는 프로세스가 교착상태와 관계 없을 수 있다. 111 | - 강제 종료의 낭비를 줄이기위해 `검사점 지정(Checkpointing)`과 `재시작(Reset)`을 사용 할 수 있다. 112 | -------------------------------------------------------------------------------- /OS/Memory.md: -------------------------------------------------------------------------------- 1 | # 메모리 관리 2 | - 메모리는 실행될 프로그램을 위한 적재 장소 3 | 4 | ## 메모리의 구성은? 5 | - 고려사항 6 | 1. 다중 프로그래밍 정도(Degree) -> 한번에 하나의 프로그램? 여러개의 프로그램?이 메모리에 있게 할 것인가. 7 | 2. 메모리의 분할(고정 or 정적 분할, 가변 or 동적 분할) 8 | 3. 메모리 할당을 연속적 or 비연속적으로 할 것인가. 9 | 10 | ## 메모리 관리는? 11 | - 적재 기법(Fetch Strategy): 프로세스에게 언제 메모리를 할당해줄 것인가. 12 | 1. `요구(Demand) 적재` -> 대부분 이걸 채택함 13 | 2. 예상(Anticipatory) 적재 14 | 15 | - 배치 기법(Placement strategy) 16 | - 프로세스들을 메모리 공간 어디에 적재할 것인가. 17 | 18 | - 교체 기법(Replacement Strategy) 19 | - 메모리 공간이 부족할 경우 새로 적재돼야 할 프로세스를 위해 이미 메모리에 있는 프로세스 중 어떤 것을 골라 디스크로 보내고 공간을 확보 할 것인가에 요구되는 기법 20 | 21 | - 할당 기법(Allocation Strategy) 22 | - 프로세스에게 메모리 공간을 얼마 정도로 줄 것인가. 23 | 24 | ## 단일 프로그래밍 25 | - 한 번에 하나의 프로세스만이 메모리에 적재되고 실행이 종료되면 다음 프로세스가 적재되는 시스템 26 | - 메모리의 크기가 적재할 프로그램의 크기보다 크거나 같으면 문제가 없지만 그렇지 않을경우 `Overay`방식을 써야함. 27 | 1. Overay란 프로그램의 일부만 먼저 적재하여 실행시킨 다음 나머지 부분을 다시 적재하여 실행을 이어가는 방식이다. 28 | 2. 프로그램 실행 중 커널 영역을 침범하지 못하도록 해야한다. 29 | 3. 경계 레지스터(Boundary Register)에 커널과 프로그램의 경계 주소값을 넣어두고, 프로그램이 참조하는 메모리의 주소값이 경계를 넘으면 트랩으로 중지시킴 30 | - 메모리의 빈공간 및 CPU, 다른자원의 낭비가 많다. 31 | 32 | ## 고정 분할에서의 다중 프로그래밍 33 | - 메모리를 여러개의 분할로 나누어 놓고, 각 분할에는 하나의 프로세스만을 수용하도록 함으로써 다중 프로그래밍을 구현하는 방식이다. 34 | - 고정 분할은 분할의 개수와 크기가 변하지 않으므로 다중 프로그래밍 정도의 최대치는 분할의 개수와 같다. 35 | - 장점: 관리가 쉽고 편리함 36 | - 단점: 유연하게 대처하지 못함 37 | - 프로그램들이 컴파일될 때 주소 지정이 이루어지는 경우 메모리 할당은 `Absolute Loader`에 의해 언제나 지정된 분할에 들어간다. 38 | - 특정 분할에 쏠림이 있을 때, 비어 있으나 활용되지 못하는 분할의 낭비를 막기위해 재배치(Relocatable) 번역과 로더를 사용하여 39 | 비어있는 어느 분할로도 들어갈 수 있게 해주어 메모리 낭비를 줄여야 한다. 40 | - 분할 크기의 다양성, 재배치 가능함에도 고정 분할은 아직 문제점을 가지는데 41 | 1. 나뉘어진 분할보다 더 큰 프로그램의 수용문제 -> Overay로 해결해야한다. 42 | 2. 메모리 보호문제를 동반한다. -> 분할의 상한, 하한을 두어 메모리를 관리해야한다. 43 | - 메모리 공간의 단편화로 메모리 낭비가 심하다. 44 | - 내부(Internal) 단편화: 분할내에 프로세스를 수용하고 남는 공간이 생기는 경우 45 | - 외부(External) 단편화: 분할의 크기 자체가 작아서 프로세스들을 수용하지 못하는 경우 46 | 47 | ## 가변 분할에서의 다중 프로그래밍 48 | - 분할의 시기와 개수 그리고 크기가 사전에 정해진 바 없이 프로세스를 수용할 때, 그 크기만큼 메모리 공간을 할당해 줌을 말한다. 49 | - 관리가 복잡해지고 오버헤드는 감수해야 한다. 50 | - 가변 분할 관리를 위해 메모리에서 사용중인 공간이나 빈 공간에 대한 정보가 필요하다. 51 | ![memory-fit](./images/memory-fit.png) 52 | - free를 탐색해 적재가 가능한 빈 공간을 찾을 때 어떤 노드를 찾을 것인가? 53 | 54 | ### 최초 적합(First-fit) 55 | - free list에서 요구되는 크기보다 더 큰 공간을 가지고 제일 먼저 발견되는 노드에 할당하는 방법 56 | 57 | ### 최적 적합(Best-fit) 58 | - free list를 끝까지 탐색 후 요구되는 크기보다 크되, 가장 적은 차이인 노드에 할당 59 | - Hole이 생김 60 | - Hole: 빈 공간이지만 크기가 아주 작아서 실제로 할당 될 가능성이 희박하고 결과적으로 낭비되는 공간을 Hole이라고 한다. 61 | 62 | ### 최악 적합(Worst-fit) 63 | - 최적 적합의 반대 (차이가 가장 큰 노드에 할당) 64 | - 남는 공간을 크게 만들어보려는 목적 65 | 66 | ### 최초, 최적, 최악 해보기 67 | ``` 68 | 1. 크기가 10 MByte인 process A의 적재 69 | 2. 크기가 20 MByte인 process B의 적재 70 | 3. 크기가 15 MByte이 process C의 적재 71 | 4. Process C의 메모리 반납 72 | 5. Process A의 메모리 반납 73 | 6. 크기가 50 MByte인 process D의 적재 74 | 7. 크기가 10 MByte인 prcoess E의 적재 75 | 8. process B의 메모리 반납 76 | ``` 77 | 78 | - 초기 free: `100 Mbyte` 79 | 80 | #### 최초 적합 81 | 1. free -> `90 MByte`, used -> `A(10 MByte)` 82 | 2. free -> `70 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` 83 | 3. free -> `55 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` -> `C(15 MByte)` 84 | 4. free -> `55 MByte` -> `15 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` 85 | 5. free -> `55 MByte` -> `15 MByte` -> `10 MByte`, used -> `B(20 MByte)` 86 | 6. free -> `5 MByte` -> `15 MByte` -> `10 MByte`, used -> `B(20 MByte)` -> `D(50 MByte)` 87 | 7. free -> `5 MByte` -> `5 MByte` -> `10 MByte`, used -> `B(20 MByte)` -> `D(50 MByte)` -> `E(10 MByte)` 88 | 8. free -> `5 MByte` -> `5 MByte` -> `10 MByte` -> `20 MByte`, used -> `D(50 MByte)` -> `E(10 MByte)` 89 | 90 | #### 최적 적합 91 | 1. free -> `90 MByte`, used -> `A(10 MByte)` 92 | 2. free -> `70 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` 93 | 3. free -> `55 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` -> `C(15 MByte)` 94 | 4. free -> `55 MByte` -> `15 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` 95 | 5. free -> `55 MByte` -> `15 MByte` -> `10 MByte`, used -> `B(20 MByte)` 96 | 6. free -> `5 MByte` -> `15 MByte` -> `10 MByte`, used -> `B(20 MByte)` -> `D(50 MByte)` 97 | 7. free -> `5 MByte` -> `15 MByte`, used -> `B(20 MByte)` -> `D(50 MByte)` -> `E(10 MByte)` 98 | - 최초 적합과 다르게 15 MByte의 빈 공간 대신 마지막 10 MByte의 빈 공간을 골랐다. 99 | 8. free -> `5 MByte` -> `15 MByte` -> `20 MByte`, used -> `D(50 MByte)` -> `E(10 MByte)` 100 | 101 | #### 최악 적합 102 | 1. free -> `90 MByte`, used -> `A(10 MByte)` 103 | 2. free -> `70 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` 104 | 3. free -> `55 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` -> `C(15 MByte)` 105 | 4. free -> `55 MByte` -> `15 MByte`, used -> `A(10 MByte)` -> `B(20 MByte)` 106 | 5. free -> `55 MByte` -> `15 MByte` -> `10 MByte`, used -> `B(20 MByte)` 107 | 6. free -> `5 MByte` -> `15 MByte` -> `10 MByte`, used -> `B(20 MByte)` -> `D(50 MByte)` 108 | 7. free -> `5 MByte` -> `5 MByte` -> `10 MByte`, used -> `B(20 MByte)` -> `D(50 MByte)` -> `E(10 MByte)` 109 | - 최초 적합과 똑같은 결과가 되었지만 이는 똑같은 메커니즘으로 동작 한 것이 아니고 우연의 일치로 15 MByte의 빈 공간이 110 | 최악 적합의 대상이 되었다. 111 | 8. free -> `5 MByte` -> `5 MByte` -> `10 MByte` -> `20 MByte`, used -> `D(50 MByte)` -> `E(10 MByte)` 112 | 113 | ## 메모리 병합 114 | - Hole이 많이 생기다보면 언젠간 작게 분할된 메모리 공간을 병합해야 할 일이 생긴다. 115 | 116 | ### 인접한(Adjacent) 빈 공간의 병합(coalescing) 117 | - 프로세스가 반납할 때마다 실행되고, 인접한 공간이 비어있지 않다면 병합하지 않는다. 118 | 119 | ### 빈 공간 전부의 통합(compaction) 120 | - 사용중인 공간들을 메모리의 한쪽 편으로 밀착시켜 옮기고, 흩어져 있던 빈 공간들을 전부 합쳐 하나의 큰 공간으로 만듦 121 | - 사용중인 공간의 재배치 또한 일어나므로 재배치시 모든 프로그램의 실행이 중단된다. 122 | - 상당한 시간이 소요된다. 123 | 124 | ## 고정과 가변의 절충인 Buddy 메모리 관리 125 | - 프로세스 적재요구가 있을 때 메모리는 요구한 크기보다 크되 차이가 가장 작게나는 2^n 크기로 분할되어 할당된다. 126 | - `같은 크기`로 분할된 `인접`해 있는 공간을 `Buddy`라고 한다. 127 | - 프로세스의 메모리 반납시 Buddy가 사용중이 아니라면 병합하는 방식 128 | ![Buddy](./images/buddy.png) 129 | 130 | 131 | ### Buddy 시스템 예제 132 | #### 시나리오 133 | ``` 134 | 1. 크기가 100 KByte인 process A의 적재 135 | 2. 크기가 240 KByte인 process B의 적재 136 | 3. 크기가 64 KByte인 process C의 적재 137 | 4. 크기가 256 KByte인 process D의 적재 138 | 5. process B의 메모리 반납 139 | 6. process A의 메모리 반납 140 | 7. 크기가 75 KByte인 process E의 적재 141 | 8. process C의 메모리 반납 142 | 9. process E의 메모리 반납 143 | 10. process D의 메모리 반납 144 | ``` 145 | #### 해보기 146 | ![Budy-example](./images/budy-example.jpeg) 147 | - (a) 비어있는 1MB의 메모리 148 | - (b) 크기가 100 KByte인 process A의 적재를 위해 2^n 크기로 나누어진 메모리 149 | - 128 KB로 나누어진 분할에 100 KB의 process A가 적재되어 28 KB 크기의 Hole이 발생 150 | - (c) Process B, C, D의 적재 151 | - (d) Process B의 메모리가 반납되었지만 버디인 분할이 비어있지 않아 병합되지 않았다. 152 | - 이때 B가 적재되어있던 256 KB 분할의 버디는 A와 C가 적재되어있는 256KB의 분할이다. 153 | - (e) Process A의 메모리가 반납, 반납으로 생긴 128 KB짜리 분할에 process E가 적재되었다. 154 | Process C의 메모리가 반납, Buddy인 바로 아래 64KB의 빈 분할과 병합 되었다. 155 | - (f) Process E의 메모리가 반납, Buddy인 바로 아래 128KB의 빈 분할과 병합되어 256KB짜리 분할을 만들고, 바로 아래 256KB buddy또한 비어있으므로 최종 512KB로 병합되었다. 156 | - 그림에는 없지만 process D의 메모리가 반납 된 후엔 병합되어 다시 1MB의 메모리로 만들어 질 것이다. 157 | 158 | #### 버디 메모리주소 구하기 159 | - 크기가 2^k이고 메모리의 시작주소가 x인 공간이 있을 때 160 | 버디가 되는 공간의 메모리 시작주소는 `x mod 2^k+1`의 결과값이 0일때는 `x + 2^k`, 2^k일 때는 `x - 2^k`이다. 161 | -------------------------------------------------------------------------------- /OS/ProcessAndThread.md: -------------------------------------------------------------------------------- 1 | # Process와 Thread 2 | ## 프로세스(Process) 3 | - 시스템에의해 일거리 단위로 서로 명확하게 구분되는 일 4 | - 수행중인 프로그램 5 | 6 | ### 프로세스 제어플록(PCB) 7 | - 프로세스가 만들어진다는건 `PCB`가 만들어진다는 것과 같다. 8 | - 기본적으로 메모리에 저장된다. 9 | - PCB 구성요소 10 | - 프로세스 번호(PID) 11 | - 프로세스 상태(Status) 12 | - 우선순위(Priority) 13 | - 프로그램 카운터 값(PC): 다음에 실행될 명령어의 주소가 들어있음 14 | - 메모리 포인터 15 | - Context Data 16 | - 할당받은 자원 목록 17 | - 계정 정보: CPU를 사용한 시간 등 18 | - 입출력 정보 19 | 20 | ### 프로세스의 상태와 변화 21 | ![status](./images/status.png) 22 | - 준비 상태 23 | - CPU를 할당 받기위해 기다리고있는 상태 (CPU만 받으면 바로 실행가능) 24 | - 준비상태의 여러 프로세스들은 메모리에 적재되어있음 25 | - 순서에따라 CPU를 할당받으면 실행상태가 되는데 이때 CPU를 할당받는 순서를 정하는 것을 `CPU 스케쥴링`이라고 한다. 26 | - 실행 상태 27 | - CPU를 할당 받아 실행중인 상태 28 | - CPU를 할당하는 것을 `Dispatch`라고 한다. 29 | - 대기 상태 30 | - 프로세스가 실행되다가 입출력 처리를 요청하거나, 바로 확보될 수 없는 자원을 요청하면 CPU를 양도하고 요청한 일이 완료되기를 기다리며 대기하는 상태 31 | - 종료 상태 32 | - 프로세스가 종료될때 아주 잠시 거치는 상태 33 | - 프로세스는 할당되었던 모든 자원들이 회수되고 PCB만 커널에 남는다 34 | - 운영체제가 프로세스의 흔적과 PCB를 삭제하면 프로세스는 완전히 삭제된다 35 | - 보류 상태 36 | - 프로세스가 메모리를 빼앗기고 디스크로 나감(Swapped Out) 37 | - 프로세스가 메모리로 복귀됨(Swapped In) 38 | - 프로세스가 메모리로 복귀했다가 나가고 하는 일련의 과정을 Swapping이라고 함 39 | - 보류 준비 상태 40 | - 생성된 프로세스가 바로 메모리를 받지 못할 때 41 | - 준비, 실행 상태에서 메모리를 잃게 될 때 42 | - 보류 대기 상태 43 | - 대기 상태일때 메모리 공간을 잃은 상태 44 | 45 | ## 스레드(Thread) 46 | - 프로세스는 큰 틀이고, 세분된 작은 일 하나 하나는 `스레드`이다. 47 | - 프로세스는 자원을 소유하고, 스레드는 스케쥴링의 단위가 된다. 48 | - 프로세스가 가지는 자원을 스레드가 서로 공유한다. 49 | - 다중 스레딩에서 프로세스란 보호자와 자원 할당의 단위가 된다. 50 | - 한 프로세스 내 스레드간의 통신은 메모리와 파일을 공유하기 때문에 커널의 개입이 필요없다 (프로세스간의 통신은 커널이 필요) 51 | 52 | ### 스레드 상태의 동기화(Synchronization) 53 | - 자원을 공유하기때문에 오류를 야기할 수 있는 상호간의 간섭이나, 데이터의 파괴등을 방지하기위한 스레드 실행의 동기화가 필요 54 | 55 | ### 스레드의 종류 56 | 1. 사용자 레벨 스레드 57 | - 스레드 라이브러리에 의해 관리 58 | - 커널은 스레드의 존재를 모른다 59 | - 특정 스레드의 대기가 프로세스 내의 모든 스레드의 대기를 초래 60 | - CPU가 프로세스 단위로 할당되어 다중처리 환경이 주어져도 스레드 단위의 다중처리가 불가능함 61 | 2. 커널레벨 스레드 62 | - 모든 스레드의 관리를 커널이 관리 63 | - 다중처리 환경에서 한 프로세스 내의 다수의 스레드는 병렬처리가 가능함 64 | - 같은 프로세스에 속한 스레드간 스위칭도 커널개입이 필요해 Context Switching이 잦다. 65 | -------------------------------------------------------------------------------- /OS/Synchronization.md: -------------------------------------------------------------------------------- 1 | # 병행 프로세스와 동기화 2 | - 비동기적이다 3 | - 병행 프로세스들이 서로간에 어떤 상태에 있는지, 어떤 자원을 가지고 있는지, 어디까지 실행됐는지 등에 대해 4 | 모른체 실행되고 있음을 뜻함 5 | - 비동기 상황에서 공유자원에 대한 접근이 제대로 처리되지 않으면 의도치 않은 결과가 발생할 수 있음 6 | 7 | ## Mutual Exclusion(상호배제, 뮤텍스) 8 | - 프로세스들이 공유데이터에 대해 서로 접근을 시도하는 상황을 `Race Condition`이라 한다. 9 | - 이러한 경쟁관계에 있는 프로세스들로 인해 상호배제, Dead Lock(교착상태), Starvation(기아상태) 같은 문제가 발생한다. 10 | - 임계자원: 두 개 이상의 프로세스가 동시에 사용할 수 없는 자원 11 | - 임계영역: 임계자원에 대해 접근하고 실행하는 프로그램내의 코드 부분 12 | - 상호배제: 한번에 하나의 프로세스만이 임계영역에 들어가야 함 13 | - 상호배제의 의무는 일반적으로 프로그래머에게 있으나 운영체제에서는 모니터와 같은 도구를 지원해줌 14 | 15 | ## 상호배제를 위한 소프트웨어 기법 16 | - 소프트웨어 기법이란 병행하는 프로세스들에게 상호배제를 책임지도록 한 기법 17 | - 이 기법들을 시도할 때 꼭 지켜져야할 것 18 | 1. 상호배제가 지켜져야 함 19 | 2. 임계영역에 있지 않은 프로세스가 다른 프로세스의 임계영역 진입을 막아서는 안됨 20 | 3. 비어있는 임계 영역은 진입을 바로 허용하되, 특정 프로세스의 진입시도가 계속 무산되어 기아를 겪으면 안됨 21 | 22 | ### Peterson Algorithm 23 | - 두 개의 프로세스만 상호배제를 할 수 있음 24 | ``` c 25 | void p0() { 26 | while (true) { 27 | flag[0] = true; 28 | turn = 1; 29 | while (flag[1] && turn == 1); /* do nothing */ 30 | ; /* 임계 영역을 뜻함 */ 31 | flag[0] = false; 32 | ; 33 | } 34 | } 35 | 36 | void p1() { 37 | while (true) { 38 | flag[1] = true; 39 | turn = 0; 40 | while (flag[0] && turn == 0); /* do nothing */ 41 | ; /* 임계 영역을 뜻함 */ 42 | flag[1] = false; 43 | ; 44 | } 45 | } 46 | 47 | Begin /* main */ 48 | int turn = 0; 49 | bool flag[2]; /* 초기값은 모두 false */ 50 | parbegin /* 이 사이에 실행 되는 것은 처리기에 따라 다르게 실행되지만 병렬로 처리된다고 가정함 */ 51 | p0(); /* 즉 P0와 P1은 동시에 실행되고 있음 */ 52 | p1(); 53 | parend 54 | End 55 | ``` 56 | 57 | ### Lamport - Bakery Algorithm 58 | - n개의 프로세스에서 상호배제가 가능한 알고리즘 59 | ``` c 60 | do { 61 | choosing[i] = true; 62 | number[i] = max(number[0], number[1],..., number[n-1]) + 1; 63 | choosing[i] = false; 64 | for (j = 0; j < n; j++) { 65 | while (choosing[j]) ; 66 | while ((number[j] != 0) && ((number[j], j) < (number[i], i))); 67 | } 68 | ; 69 | number[i] = 0; 70 | ; 71 | } while (1); 72 | ``` 73 | 74 | ### 소프트웨어 기법을 통한 상호배제의 단점 75 | - 실행시 부하가 크다 76 | - 프로그래머가 상호배제에대한 책임을 떠맡아야하므로 실수로인한 오류가 있을 수 있다. 77 | - 임계영역의 중복 진입을 막기위해 while을 계속 도는데 CPU낭비다.(`Busy wait` 혹은 `Spin lock`이라고 부름) 78 | 79 | ## 상호배제를 위한 하드웨어 기법 80 | ### 인터럽트 금지를 사용한 기법 81 | - 한 프로세스가 임계영역일때 CPU를 뺴앗기지 않도록 인터럽트를 발생시키지 않는다. 82 | - 임계영역의 처리가 끝날때까지 모든 인터럽트를 금지하므로 시스템의 효율적인 운용이 불가능함 83 | - 인터럽트는 처리기 단위라 단일이 아닌 다중처리 시스템에선 임계영역 중복진입을 못 막을 수도 있다. 84 | 85 | ### 하드웨어 명령어를 사용한 기법 86 | - `testandset`을 이용한 기법 87 | ``` c 88 | boolean testandset(boolean &target) { /* 프로시저 처럼 표현해 놨지만 사실은 원자성을 가진 기계명령어임 */ 89 | boolean rv = target; 90 | target = true; 91 | return rv; 92 | } 93 | 94 | cont int n = ...; /* 프로세스 개수 */ 95 | boolean lock; 96 | void P(int i) { 97 | while (true) { 98 | while (testandset(lock)); 99 | ; 100 | lock = false; 101 | ; 102 | } 103 | } 104 | void main() { 105 | lock = false; 106 | parbegin 107 | P(1), P(2), ..., P(n); 108 | parend; 109 | } 110 | ``` 111 | - `exchange` 혹은 `swap`을 이용한 기법 112 | ``` c 113 | void exchange(boolean &r, boolean &m) { /* 프로시저 처럼 표현해 놨지만 사실은 원자성을 가진 기계명령어임 */ 114 | boolean temp = r; 115 | r = m; 116 | m = temp; 117 | } 118 | 119 | cont int n = ...; /* 프로세스 개수 */ 120 | boolean lock; 121 | void P(int i) { 122 | while (true) { 123 | key = true; 124 | while (key = true) do exchange(key, lock); 125 | ; 126 | lock = false; 127 | ; 128 | } 129 | } 130 | void main() { 131 | lock = false; 132 | parbegin 133 | P(1), P(2), ..., P(n); 134 | parend; 135 | } 136 | ``` 137 | 138 | - 장점: 한 프로그램 내에서 서로다른 변수를 사용하여 여러개의 임계영역을 지원한다. 139 | - 단점: Busy wait, 차례가 없어서 어떤 프로세스는 기아를 겪을 수 있다. Dead Lock 위험이 있음 140 | 141 | ## Semaphore(세마포어) 142 | - Dijkstra가 1965년에 제안한 개념 143 | - 세 개의 특수한 명령들만 접근할 수 있게 허용되는 변수 144 | - Binary Semaphor, Integer Semaphore 등이 있다. 145 | - Indivisible 명령: 초기화 명령, P 명령(wait, down), V 명령(signal, up) 146 | 147 | ``` 148 | // S는 세마포어 변수 149 | P(S): if (S > 0) then S = S - 1; 150 | else S > 0 조건이 만족될 때까지 큐에서 대기; 151 | V(S): if (큐에서 대기중인 프로세스가 존재) then 그 중의 한 프로세스를 준비 또는 실행 상태로 만듦; 152 | else S = S + 1; 153 | ``` 154 | - 세마포어에 대한 명령들은 각각 분리되지 않고 수행될 수 있도록 구현한다. 155 | - 같은 세마포어에 대해 동시에 실행되지 못한다. 156 | - 세마포어를 활용하면 프로세스간의 동기화도 쉽게 구현이 가능하다. 157 | 158 | ## producer-consumer problem(생산자-소비자 문제) 159 | - `생산자`는 데이터를 만들어 버퍼에 저장하고 `소비자`는 버퍼에 있는 데이터를 꺼내 소비하는 `프로세스`를 말한다. 160 | - 버퍼 161 | - 공유자원을 의미 162 | - 접근(저장, 소비)이 상호배제 되어야 한다. 163 | - 버퍼가 꽉참 (생산자 대기), 버퍼 비어있음(소비자 대기) => 동기화 164 | - 세마포어를 이용한 기법은 운영체제 수준에서 임계 영역으로의 진입을 기다리는 프로세스들을 대기 상태로 전환 165 | 시키므로써 CPU낭비를 줄일 수 있음 166 | - 단 프로세스를 대기 상태로 전환하는 비용이 발생하고, 임계영역이 짧을 경우 busy wait을 사용하는게 더 반응이 167 | 빠르며, 대기중인 프로세스들의 다음 차례 선택에대한 기준이 없어서 기아를 유발할 수 있음 168 | ``` c 169 | semaphore s = 1; /* */ 170 | semaphore f = 0; 171 | semaphore e = n; /* buffer size */ 172 | 173 | void producer() { 174 | while (true) { 175 | produce data V; 176 | P(e); 177 | P(s); 178 | append data V; 179 | V(s); 180 | V(f); 181 | } 182 | } 183 | 184 | void consumer() { 185 | while (true) { 186 | p(f); 187 | p(s); 188 | take data W; 189 | V(s); 190 | V(e); 191 | consume data W; 192 | } 193 | } 194 | 195 | void main() { 196 | parbegin 197 | producer(), consumer(); 198 | parend 199 | } 200 | ``` 201 | 202 | ## Eventcounter와 Sequencer를 사용한 기법 203 | - Eventcounter, Sequencer도 특별한 명령들에 의해서만 접근이 가능한 변수들이다. 204 | - 초기값은 0으로 그 값이 감소하지 않는다. 205 | - ![sequencer and Eventcounter](./images/sequencer.png) 206 | - Sequencer에 대한 명령은 비분리로 이루어져야 하지만 나머지는 비분리로 이루어지지 않아도 좋다. 207 | - 임계영역의 진입을 시도하는 프로세스들에게 순번표를 부여해 기아문제를 해결 208 | - 은행으로치면 ticket(S)로 번호표를 뽑고 await(E,v)로 차례가 올때까지 대기, read(E)로 현재 번호를 확인하고, 209 | advance(E)로 은행원이 차례번호를 올린다. 210 | 211 | ## Monitor(모니터) 212 | - ![monitor](./images/monitor.png) 213 | - 모니터란 공유데이터들과 이들에 대한 임계영역들을 관리하는 소프트웨어 구성체이다. 214 | - 모니터로의 진입은 프로시저의 호출로 가능하고, 한 번에 하나 이하의 프로세스만이 모니터 내에 있게 함으로써 215 | `상호배제`를 자연스럽게 실현한다. 216 | 217 | ## The Dining-Philosophers Problem (식사하는 철학자 문제) 218 | ![dining-philosophers](./images/dining.png) 219 | - 상호배제나 동기화 그리고 기아와 교착 상태를 설명해주는 문제 220 | ``` 221 | 5명의 철학자가 앉아있고, 식탁에는 5접시의 스파게티와 5개의 포크가 놓여있다. 222 | 철학자들은 비동기적으로 먹거나 생각하는 일을 반복하는데, 223 | 스파게티를 먹기 위해서는 자신의 오른쪽과 왼쪽에 있는 포크 두 개가 있어야 한다. 224 | 철학자들은 서로 대화하거나, 들고있는 포크를 빼앗을 수 없다. 225 | ``` 226 | - 결국 `포크`가 공유 자원이 되며, 철학자들의 정상적인 식사를 보장하는 것이 문제의 핵심 227 | 228 | ### 첫번째 해결법과 문제점 229 | - 왼쪽 포크를 집은다음 오른쪽 포크를 집을 수 있게 하자 230 | ``` 231 | philosopher i: 232 | while (true) { 233 | think; 234 | P(fork[i]); // 왼쪽 포크 집기 235 | P(fork[(i+1) % 5]); // 오른쪽 포크 집기 236 | eat; 237 | V(fork[i]); // 왼쪽 포크 내려놓기 238 | V(fork[(i+1) % 5]); // 오른쪽 포크 내려놓기 239 | } 240 | ``` 241 | - 모든 철학자가 왼쪽 포크를 집고 오른쪽 포크를 기다리는 DeadLock에 걸릴 수 있음 242 | 243 | ### 두번째 해결법과 문제점 244 | - 왼쪽 포크와 오른쪽 포크를 한번에 집을 수 있게 하자 245 | ``` 246 | philosopher i: 247 | while (true) { 248 | think; 249 | P(fork[i] and fork[(i+1) % 5]); 250 | eat; 251 | V(fork[i] and fork[(i+1) % 5]); 252 | } 253 | ``` 254 | - DeadLock은 발생하지 않지만 특정 철학자(쓰레드)가 기아 상태에 빠질 수 있음 255 | 256 | ### 완전한 해결법 257 | 1. 포크의 개수가 철학자의 수보다 많도록 세팅 (철학자의 수를 줄이거나..) 258 | 2. 홀수 번호의 철학자는 왼쪽 포크를 먼저 집고 짝수 번호의 철학자는 오른쪽 포크를 먼저 집는다. 259 | -------------------------------------------------------------------------------- /OS/WhatIsOS.md: -------------------------------------------------------------------------------- 1 | # OS 2 | ## OS란? 3 | - 컴퓨터의 사용자와 하드웨어 사이에서 가교역할을 하는 프로그램 4 | - 사용자 인터페이스와 자원관리를 위한 프로그램의 집합 5 | 6 | ## OS 역사 7 | 1. 1세대 - 진공관 8 | - IBM 701부터 운영체제 1세대로 본다 (일괄처리 시스템의 등장) 9 | 2. 2세대 - 트랜지스터 10 | - CPU를 할당 받을 다수개의 작업(Multi program)이 같이 주기억장치에 있다 (다중 프로그래밍 시스템) 11 | - 여러개의 처리장치(Multi processor)를 장착하여 동시에 여러작업을 병렬로 처리 (다중 처리 시스템) 12 | 3. 3세대 - 직접회로 13 | - 일괄처리, 시분할, 실시간작업 모두 지원 (Multi-mode) 14 | - TCP/IP 표준 발표, 근거리 통신망(LAN)이 이 시기 즈음 탄생 15 | - 1969년 UNIX 출현 16 | 4. 4세대 - 고밀도 직접회로 17 | - 컴퓨터 사용의 범용화 18 | - 입출력 장치의 다양화 19 | - 저장장치의 대용량화 20 | - 데이터 통신의 발전 21 | - 정보산업 출현 22 | - 마이크로 프로세서의 등장 -> 가격의 범용화 23 | * 마이크로 프로세서: 하나의 칩에 연산, 제어, 레지스터들을 넣은 것 24 | 25 | ## 운영체제의 5가지 구성요소 26 | - 크게 `Kernel`과 `Utility-Program`으로 나눈다. 27 | - ![components-of-os](./images/components-of-os.png) 28 | 29 | ### Kernel 30 | - 운영체제의 핵심 31 | - 컴퓨터가 처음 부팅될 때 주기억 장치에 적재되어 시스템종료(Shutdown)이 되기 전까지 계속 주 기억장치에 적재되어있는 프로그램 32 | - 빈번하게 실행되는 프로그램을 디스크에 둘 경우 주 기억장치와 디스크간의 입출력이 너무 빈번하게 일어나기 때문에 성능 저하가 있다. 즉 필수적으로 자주 쓰이는 프로그램을 33 | 메모리에 상주시키는데 이 프로그램을 Kernel이라고 한다. 34 | - Kernel보다 더 빠른 실행이 필요하고 높은 수준의 보호가 필요한건 마이크로 프로그래밍하여 `ROM`이나 `PLA` 같은 칩으로 만들기도 하며 이를 `펌웨어(생긴건 하드웨어 내부적으론 프로그램)`라고 한다. 35 | 36 | ## System call이란? 37 | - ![system call](./images/system-call.png) 38 | - Kernel 영역에 있는 프로그램만 할 수 있는 것들을(Disk I/O, Memory access) 유저 수준에서 사용하길 원할 때 System call을 하여 원하는 결과물을 얻을 수 있다. 39 | 40 | ## OS의 목적 41 | - 사용자의 편리성과 자원의 효율적 사용 42 | 43 | ## 부팅 44 | - 전원 ON -> 커널이 메모리에 올라옴(Bootstrap Loader, 부트 프로그램 등) -> 장치준비, 레지스터 초기화 -> 사용자 입력 대기 45 | 46 | ## 레지스터 47 | 1. CPU는 여러개의 레지스터를 가지고 메모리보다 빠르지만 용량이 작다. 48 | 2. 시스템과 사용목적에따라 8비트, 16비트, 32비트등의 크기를 가진다. 49 | 3. CPU는 PSW(Program Status Word)라는 현재상태를 저장하는 레지스터가 있다. 50 | 51 | ## 명령어 처리 52 | - 명령어를 읽어 처리기에 있는 레지스터로 가져오는 것을 말함 (Fetch) 53 | 54 | ## 인터럽트(Interrupt) 55 | - 운영체제가 자원을 효율적으로 관리하기위해 각 자원의 상황을 알아야 하는데 이를 매번 조사할 수 없으니 인터럽트라는 것을 이용한다. 56 | - 각 자원들은 인터럽트를 통해 자신의 상태변화를 CPU에 알려줘 CPU는 폴링 방식처럼 주기적으로 시간을 들이지 않아도 각 자원의 상황을 알 수 있다. 57 | - 즉 CPU가 처리해야 될 일들이 있을때 하드웨어 및 소프트웨어는 인터럽트를 통해 CPU에게 알릴 수 있고 처리 된다. 58 | - 인터럽트는 크게 2가지로 `하드웨어 인터럽트`와 `소프트웨어 인터럽트(트랩)`으로 나눈다. 59 | - 하드웨어 인터럽트 -> 하드웨어 수준에서 일어나는 인터럽트로 CPU외부의 디스크나 마우스, 키보드의 입출력 등 CPU의 처리가 필요한 상황일 때 발생한다. 60 | - 트랩 -> 소프트웨어 수준에서 일어나는 인터럽트로 프로그램의 예기치 못한 종료나, CPU의 처리가 필요한 상황일 때 발생한다. (e.g. system call) 61 | 62 | ### 인터럽트의 처리 63 | - CPU는 인터럽트가 들어오면 실행중이던 프로그램을 잠시 메모리에 돌려놓고 인터럽트 처리 루틴을 실행한다. 64 | - 인터럽트를 처리하는 과정에서 실행중이던 프로그램의 값을 잃어버릴 수 있으므로 인터럽트 처리 전에 PSW, PC 레지스터의 값등을 시스템 스택에 저장한다. 65 | - 인터럽트의 처리가 끝나면 PC나 PSW 정보를 CPU에 되돌리고 작업중이던 프로그램을 이어서 처리할 수 있다. 66 | - 이러한 일련의 과정을 `Context Switching`이라고 한다. 67 | 68 | ### 중첩된 인터럽트의 처리 69 | - 하나의 인터럽트가 끝난 뒤 다음 인터럽트를 처리하는 `순차적 처리` 혹은 Context Switching을 `중첩하여 처리`할 수 있다. 70 | - 우선순위가 더 높은 인터럽트가 들어 왔을 때 중첩하여 처리하기도 한다. 71 | 72 | ## 기억 장치의 계층적 구조 73 | - ![기억 장치의 계층적 구조](./images/disk.png) 74 | - Access Time, 용량, 가격(bit당 단가)의 차이로 분류 가능 75 | - 속도가 높으면서 가격이 비싼게 있고, 속도가 느리고 가격이 싸며 용량이 높은 것들이 있으므로 용도에 맞게 저장장치를 계층적으로 잘 구성해야한다. 76 | 77 | ## I/O 방식 78 | 1. Programmed I/O 79 | - CPU가 입력을 지시 후 컨트롤러 버퍼를 계속 확인한다. 80 | - 인터럽트가 필요없는대신 다른 CPU 작업을 못한다. 81 | 2. Interrupt-driven I/O 82 | - Programmed I/O와 다르게 CPU를 다른작업에 활용 가능 83 | - 잦은 Interrupt가 단점이다 (잦은 Context Switching이 발생) 84 | 3. Direct Memory Access(DMA) 85 | - CPU대신 입출력 작업을 해줄 Channel이라는 Satellite processor를 이용하는 방식 86 | - CPU는 입출력할 데이터의 시작 주소와 크기등을 Channel에 알려준다. 87 | - 한번의 입출력(Block)단위로 CPU에게 인터럽트하므로 Interrupt-driven I/O보다 인터럽트가 적다. 88 | 89 | ## Hardware 구성에 따른 입출력 90 | 1. Isolated I/O(독립적 입출력) 91 | - 입출력 장치들이 입출력 버스(I/O Bus)를 통해 CPU와 연결되어 있는 경우 92 | - I/O Bus를 통해 해당장치의 지정, 데이터, 입출력을 구분해주는 제어 값이 전달됨 93 | - 입출력 명령어가 Instruction set에 추가되어 제어로직이 복잡해지고, I/O Bus를 장착하는데 추가 비용이 있다. 94 | 2. Memory-mapped I/O(메모리 주소지정 입출력) 95 | - 입출력 장치들이 메모리와 함께 Memory Bus에 연결됨 96 | - 입출력 명령어가 따로 없고 메모리 명령어를 사용한다. 97 | - 메모리에 추가적인 공간을 차지하는게 단점이다. 98 | -------------------------------------------------------------------------------- /OS/images/FCFS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/FCFS.png -------------------------------------------------------------------------------- /OS/images/buddy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/buddy.png -------------------------------------------------------------------------------- /OS/images/budy-example.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/budy-example.jpeg -------------------------------------------------------------------------------- /OS/images/components-of-os.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/components-of-os.png -------------------------------------------------------------------------------- /OS/images/dining.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/dining.png -------------------------------------------------------------------------------- /OS/images/disk.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/disk.png -------------------------------------------------------------------------------- /OS/images/edf.svg: -------------------------------------------------------------------------------- 1 | 2 | {\displaystyle U=\sum _{i=1}^{n}{\frac {C_{i}}{T_{i}}}\leq 1,} 3 | 15 | 44 | -------------------------------------------------------------------------------- /OS/images/fair.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/fair.png -------------------------------------------------------------------------------- /OS/images/memory-fit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/memory-fit.png -------------------------------------------------------------------------------- /OS/images/monitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/monitor.png -------------------------------------------------------------------------------- /OS/images/rm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/rm.png -------------------------------------------------------------------------------- /OS/images/round-robin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/round-robin.png -------------------------------------------------------------------------------- /OS/images/sequencer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/sequencer.png -------------------------------------------------------------------------------- /OS/images/status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/status.png -------------------------------------------------------------------------------- /OS/images/system-call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/system-call.png -------------------------------------------------------------------------------- /OS/images/unsafe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qkraudghgh/coding-interview/8926967e5220f4ee50289cd7d86e597336cca0f4/OS/images/unsafe.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Coding Interview 2 | 3 | - 개인적으로 공부한 내용을 정리한 것입니다. 틀린요 내용이 있을 수 있으며 틀린 내용이 있으면 이슈로 남겨주세요 4 | 5 | ## Data Structure 6 | 7 | - [Array](./DataStructure/Array/Array.md) 8 | - [LinkedList](./DataStructure/LinkedList/LinkedList.md) 9 | - [Stack](./DataStructure/StackAndQueue/Stack.md) 10 | - [Queue](./DataStructure/StackAndQueue/Queue.md) 11 | - [Tree](./DataStructure/Tree/Tree.md) 12 | - [Priority-Queue](./DataStructure/StackAndQueue/PriorityQueue.md) 13 | - [Heap](./DataStructure/Tree/Heap.md) 14 | - [Map and HashTable](./DataStructure/Map/Maps.md) 15 | 16 | ## OS 17 | 18 | > OS는 [OS? Oh Yes!](http://www.aladin.co.kr/shop/wproduct.aspx?ItemId=4412844)라는 책을 보며 공부하고 궁금한 부분은 추가하여 작성중입니다. 19 | - [OS란?](./OS/WhatIsOS.md) 20 | - [프로세스와 스레드](./OS/ProcessAndThread.md) 21 | - [CPU 스케줄링](./OS/CPUScheduling.md) 22 | - [병행 프로세스와 동기화(뮤텍스, 세마포어)](./OS/Synchronization.md) 23 | - [교착 상태(Deadlock)](./OS/Deadlock.md) 24 | - [메모리 관리](./OS/Memory.md) 25 | 26 | ## Network 27 | 28 | - [HTTP란?](./Network/WebBrowser.md) 29 | - [IP와 DNS](./Network/IPAndDNS.md) 30 | 31 | ## Interview 32 | 33 | - sorting 34 | 1. [Insertion Sort](./Interview/sorting/insertionSort.js) 35 | 2. [Selection Sort](./Interview/sorting/selectionSort.js) 36 | 3. [Buble Sort](./Interview/sorting/bubleSort.js) 37 | 4. [Merge Sort](./Interview/sorting/mergeSort.js) 38 | 5. [Heap Sort](./Interview/sorting/heapSort.js) 39 | 6. [Quick Sort](./Interview/sorting/quickSort.js) 40 | 41 | - Interview 예상 문제 개인적인 풀이 42 | > [https://github.com/JaeYeopHan/Interview_Question_for_Beginner](https://github.com/JaeYeopHan/Interview_Question_for_Beginner)에서 문제 발췌 43 | 1. [week1](./Interview/question/week1.md) 44 | 2. [week2](./Interview/question/week2.md) 45 | 3. [week3](./Interview/question/week3.md) 46 | 47 | - [경험했던 면접 질문 및 답](./Interview/question/previous_interview.md) --------------------------------------------------------------------------------