Asymptotic Notation 알아야 한다
Recursive function의 시간 복잡도
a ≥ 1, 한 문제를 나눌 때 생성되는 하위 문제의 수
b > 1, 입력 크기를 나누는 비율
f(n): 하위 문제를 나누고 병합하는 데 드는 추가 비용
Master Theorem ; f(n)과 재귀비용(n^(log_b a)) 수준 비교하여 시간 복잡도 판단
Algorithm이 주어질 때 분석하는 방법은 알아야 한다
(Big O 설명 by Nomad Coder)
알고리즘 speed는 time으로 할 수 없음 왜냐면 machine dependent하니까
Big O를 쓰면 시간 복잡도를 빠르게 설명할 수 있음
linear search는 n개면 n번의 step 필요하니까 O(n) 라고 씀
만약 정해진 횟수를 도는 function이면, O(1) 이렇게 쓸 것 ; 몇 번 돌듯 그냥 ‘1’ 이라고 Logic 형태만 표현하는거임
→ constant time algorithm이라고 하고 n size에 무관하다는 뜻이지, n이 엄청 클 때를 상정하는 듯?
binary search는 n이 10에서 20으로 두 배가 되어도 step++일 뿐임. O(log n)이라는 뜻이지
→ 물론 binary search는 sorting이 추가로 필요하긴 하지
Complexity Analysis ; T(n) = 3n^2 + 2n + 8 → T(n) ∈ Θ(n^2) ; 이런식으로 포함 관계를 표기함
Tree, Data Structucture이며 Algorithm이고 Graph임
Binary Tree
BST, Binary Search Tree
AVL
모든 Data Structure는 array와 pointer로 만들 수 있다
항목 | array | pointer |
---|---|---|
메모리 구조 | 정적인 연속된 공간 | 동적인 공간에 주소로 저장 |
addressing | index - direct | address - indirect |
장점 | index로 직접 addressing해서 빠름; O(1) | 메모리 동적 할당해서 낭비 없음 |
공간이 연속적이라 캐시 활용도 좋음 | 참조호출돼서 데이터 구조 유연하게 씀(linked list, tree 등) | |
단점 | 정적 할당으로 공간 비효율 | 메모리 해제 안해주면 공간 낭비되고 디버깅 복잡 |
전체 구조에 영향 줘서 삽입 삭제 어려움 | Segmentation fault 등 안정성 문제 있음 |
Graph
그래프는 뭐 멀티미디어 같은데서만 쓰이는 요엉가 아니라, NLP 등 연산에 관계가 활용되는 모든 분야에서 중요
Graph 탐색 Algorithm
DFS (Depth-First Search, 깊이 우선 탐색)
가능한 깊이 들어가다가 더 이상 진행할 수 없으면 backtrack (LIFO 형태의 stack이 낫지)
Stack 기반, 재귀 호출로 구현
Cycle 탐지, Tree 구조 추출과 Component 탐색에 주로 활용
DFS로 Cycle 찾기 (기본 Idea)
→ 이미 방문한 노드를 다시 방문했을 때 그것이 부모가 아닌 경우
→ 이렇게 Cycle 다 구해서 길이를 계산하고, 가장 긴 Cycle의 길이를 갱신
BFS (Breadth-First Search, 너비 우선 탐색)
Shortest path
가장 쉽고 직관적이고 좋은데 negative edge 있으면 안됨 (거리나 시간에 잘 맞음)
대표적인 greedy algorithm(미래는 모르겠고 지금 기준만 보고 최적 선택 - 다익스트라랑 잘 맞음)
→ 당시 노드에서 최선의 선택을 했기 때문에, 재방문은 안하고 neg. edge있으면 결과가 달라져서 illegal
항상 shortest path에서 답을 찾아줌 (BFS 기반)
시간 복잡도는 O(n^2)
start와 dest. 까지의 shortest path 구하는 것도 의미 있긴 한데, 종합적인 map 필요할 수 있음
→ Start에서 모든 Node까지의 shortest path를 동시에 찾는 것. 물론 노드 많아지면 개느림
이거 Matrix로 결과 도출할 수 있는건데, 꽤 많이 쓰이는 듯 함
시간 복잡도는 O(n^3)
Sorting