[하루에 한번] 자료구조, 알고리즘 학습-1
[하루에 한번] 자료구조, 알고리즘 학습-1
시간복잡도와 공간복잡도에 대해 설명해 주세요.
Big-O, Big-Theta, Big-Omega에 대해 설명해 주세요.
- Big-O : 최악의 경우를 상정한 시간복잡도 계산방법
- Big-Theta
- Big-Omega
다른 것을 사용하지 않고, Big-O를 사용하는 이유가 있을까요?
- Big-O 표기법이 최악을 상정하는 만큼, 예외 상황을 통제할 수 있기 때문에 사용합니다.
O(1)은 O(N^2)보다 무조건적으로 빠른가요?
- 상수 시간이나 실제 구현 방식에 따라 작은 입력에서는 성립하지 않을 수 있습니다.
링크드 리스트에 대해 설명해 주세요.
일반 배열과 링크드 리스트를 비교해 주세요.
- 데이터 저장 방식
- 배열은 연속적인 메모리 공간에 데이터를 저장합니다.
- 반면 링크드 리스트는 흩어져 있는 메모리 공간에 데이터를 저장하나, 다음 노드의 주소를 지니고 있습니다.
- 삽입/삭제/접근에 대한 성능
- 위와 같은 저장 방식의 차이점을 이유로 배열은 중간 데이터에 대한 삽입, 삭제가 어렵고 접근이 빠릅니다.
- 반면 링크드 리스트는 중간 데이터에 대한 삽입, 삭제가 쉽고 접근이 느립니다. (= 처음부터 따라가야해서)
링크드 리스트를 사용해서 구현할 수 있는 다른 자료구조에 대해 설명해 주세요.
- 스택, 큐, 데큐, 해시 테이블, 그래프, LRU 캐시, 원형 큐
스택과 큐에 대해서 설명해 주세요.
스택 2개로 큐를, 큐 2개로 스택을 만드는 방법과, 그 시간복잡도에 대해 설명해 주세요.
- 첫번째 스택에 저장된 데이터를 pop()을 통해서 두번째 스택으로 옮긴 후 두번째 스택에서 pop()을 진행하면 FIFO 형태가 완성된다. 시간복잡도는 O(1).
- 하나의 요소를 넣을 때마다 빈 큐에 넣고 기존에 저장된 데이터들을 뒤로 붙힌다. (그러면 빈 큐와 데이터가 저장된 큐 두 가지가 생성됨). 시간복잡도는 input은 O(N), output은 O(1).
시간복잡도를 유지하면서, 배열로 스택과 큐를 구현할 수 있을까요?
- 배열의 끝까지 가면 다시 처음으로 돌아가는 원형 큐를 활용하면 됩니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class CircularQueue {
int[] arr;
int front = 0;
int rear = 0;
int size = 0;
CircularQueue(int capacity) {
arr = new int[capacity];
}
void enqueue(int value) {
if (size == arr.length) {
System.out.println("큐가 가득 찼습니다.");
return;
}
arr[rear] = value;
rear = (rear + 1) % arr.length;
size++;
}
int dequeue() {
if (size == 0) {
System.out.println("큐가 비었습니다.");
return -1;
}
int value = arr[front];
front = (front + 1) % arr.length;
size--;
return value;
}
}
Prefix, Infix, Postfix에 대해 설명하고, 이를 스택을 활용해서 계산하는 방법에 대해 설명해 주세요.
- Prefix, Infix, Postfix는 각각 전위, 중위, 후위를 뜻하며 연산자의 위치에 따라 다르게 불립니다.
1
2
3
4
5
6
7
8
9
10
11
# example
(3 + 4) * 5
# Prefix
* + 3 4 5
# Infix
(3 + 4) * 5
# Postfix
3 4 + 5 *
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import java.util.*;
public class Calculator {
public static int calPrefix(String expression) {
// * + 3 4 5
Deque<Integer> deque = new ArrayDeque<>();
String[] tokens = expression.trim().split("\\s+");
for (int i = tokens.length - 1; i >= 0; i--) {
Stirng token = tokens[i];
if (isOp(token)) {
int left = deque.pop();
int right = deque.pop();
int result = calc(left, right, token);
deque.push(result);
} else {
deque.push(Integer.parseInt(token));
}
}
return deque.pop();
}
public static int calPostfix(String expression) {
// 3 4 + 5 *
Deque<Integer> deque = new ArrayDeque<>();
String[] tokens = expression.trim().split("\\s+");
for (String token : tokens) {
if (isOp(token)) {
int right = deque.pop();
int left = deque.pop();
int result = calc(left, right, token);
deque.push(result);
} else {
deque.push(Integer.parseInt(token));
}
}
return deque.pop();
}
private static boolean isOp(String token) {
return token.equals("+") || token.equals("-") || token.equals("*") || token.equals("/");
}
private static int calc(int left, int right, String op) {
switch (op) {
case "+":
return left + right;
case "-":
return left - right;
case "*":
return left * right;
case "/":
return left / right;
default:
throw new IllegalArgumentException("Not Supply: " + op);
}
}
}
Deque는 어떻게 구현할 수 있을까요?
- Deque는 양 옆이 각각 출입구의 역할이 가능한 형태의 자료구조입니다.
- 이는 여러 가지 방법(스택 2개, 큐 2개, 양방향 링크드 리스트 등)이 있지만 가장 권장되는 방법은 원형 배열을 활용한 구현입니다.
출처
This post is licensed under CC BY 4.0 by the author.