1. Big O 표기법이란?
- 빅오는 입력값이 무한대로 향할때 함수의 상한을 설명하는 수학적 표기법입니다.
- 빅오는 점근적 실행 시간을 표기할 때 가장 널리 쓰이는 표기법입니다.
- 점근적 실행 시간: 입력값 n이 무한대로 향할 때 함수의 실행 시간 추이
- 아무리 복잡한 알고리즘도 입력의 크기가 작으면 금방 끝나기 때문에 입력의 크기가 커질수록 시간이 어떻게 증가하는지를 표현하는 방법입니다.
1.1 상한과 최악
- 빅오는 상한을 의미한다.
- 하한을 나타내는 빅 오메가(Ω)와 평균을 나타내는 빅 세타(Θ)도 있습니다.
- 상한과 최악을 혼동하는 경우가 있는데, 빅오는 최악의 경우를 설명하는 것이 아닙니다.
- 빅오 표기법은 함수를 적당히 정확하게 표현하는 방법일 뿐 최악의 경우/ 평균적인 경우의 시간 복잡도와는 관련이 없습니다.
- 빅오 표기법은 주어진(최선/최악/평균) 경우의 수행 시간의 상한을 나타냅니다.
- 즉 최악(최선, 평균)의 경우의 수행 시간이 이 표기법을 사용하여 나타낸 수행 시간보다 더 나쁠 수는 없다는 것을 의미합니다.
2. 빅오의 기본 규칙
2.1 상수항 제외
- 빅오는 입력 크기에 따른 증가율만 고려합니다
- 실제 연산 횟수나 상수 계수는 제외됩니다
2.1.1 상수항 제외 첫 번째 예시
def find_in_half(arr):
# O(n/2) -> O(n)
for i in range(len(arr) // 2):
if arr[i] == target:
return i
return -1
- O(n/2)는 O(n)으로 표기합니다
2.1.2 상수항 제외 두 번째 예시
def process_half_matrix(matrix):
n = len(matrix)
# O(n²/2) -> O(n²)
for i in range(n):
for j in range(i): # 대각선 아래 부분만 처리
process(matrix[i][j])
- O(n²/2)는 O(n²)으로 표기합니다
2.1.3 상수항 제외 세 번째 예시
def process_with_constants(arr):
# O(4n) -> O(n)
for i in range(len(arr)):
calculate_sum(arr[i]) # 1회 연산
find_average(arr[i]) # 1회 연산
update_max(arr[i]) # 1회 연산
check_threshold(arr[i]) # 1회 연산
- 반복문 내부에 4개의 연산이 있어도 O(4n)은 O(n)으로 표기합니다
- 상수 4는 증가율에 영향을 주지 않으므로 제외됩니다
2.2 비우세항 제외
- 가장 빠르게 증가하는 항만 남기고 나머지는 제외합니다
2.2.1 비우세항 제외 예시
def example_function(n):
# O(n² + n + 1) -> O(n²)
for i in range(n): # O(n)
for j in range(n): # O(n)
print(i, j)
for k in range(n): # O(n)
print(k)
print("done") # O(1)
- O(n² + n + 1)은 O(n²)으로 표기합니다
2.3 입력이 다르면 변수도 다르다
2.3.1 서로 다른 입력 크기의 예시
def compare_arrays(arr_a, arr_b):
# O(a + b): a와 b는 서로 다른 입력
for i in arr_a: # O(a)
print(i)
for j in arr_b: # O(b)
print(j)
def process_same_array(arr):
# O(2n) -> O(n): 같은 입력을 두 번 순회
for i in arr: # O(n)
print(i)
for j in arr: # O(n)
print(j)
- 서로 다른 입력 크기의 변수는 다른 변수로 표기합니다
- 같은 입력을 두 번 순회하는 경우에는 O(2n) 대신 O(n)으로 표기합니다
- 상수항은 제외합니다
2.4 단계의 합산과 곱
2.4.1 같은 레벨의 반복문 예시
def sequential_loops(n):
# O(n + n) = O(2n) -> O(n)
for i in range(n):
print(i)
for j in range(n):
print(j)
- 같은 레벨의 반복문은 합산하여 표기합니다
2.4.2 중첩된 반복문 예시
def nested_loops(n):
# O(n * n) = O(n²)
for i in range(n):
for j in range(n):
print(i, j)
- 중첩된 반복문은 곱하여 표기합니다