정렬되지 않은 부분을 쫙 돌면서 제일 작은애(혹은 제일 큰 애)를 선택해서 위치 바꾸기. 시간복잡도는 최선의 경우 최악의 경우 모두 O(n^2)
앞에서부터 둘씩 비교해서 큰 애를 뒤로 보낸다. 한 바퀴 돌 때마다 가장 큰 애가 맨 뒤로 가게 된다. 시간복잡도는 최선의 경우 최악의 경우 모두 O(n^2)
버블 정렬 같은경우엔 최선의 경우를 O(n)까지 줄이도록 개선하는 방법이 있다. 한바퀴돌았는데 스왑이 한번도 일어나지 않으면 탈출하는 것. 한바퀴(n)돌았는데 다 정렬되어 있는 상태라면 거기서 탈출이 가능할 것이다.
Repeat until no swaps
For i from 0 to n–2
If i'th and i+1'th elements out of order
Swap them
i번째 원소를 골랐을때...i-1부터 0까지 보면서 적절한 위치에 삽입한다. i-1까지는 정렬되어 있는 상태이므로, 상황에 따라 비교를 적게 할 수도 있다. 최선의 경우 (이미 정렬된 경우) 시간복잡도 O(n). 최악의 경우(역순정렬된 경우) 시간복잡도 O(n^2)
분할 정복 방식으로 설계된 정렬 방식. 시간복잡도 O(nlogn)
마찬가지로 분할 정복 방식. pivot이라는 값을 설정하고, 이값보다 크면 오른쪽으로, 작으면 왼쪽으로 보낸다.
피벗 설정을 어떻게 하느냐에 따라 성능이 다르다.
최악의 경우(이미 정렬된 경우) 시간복잡도 O(n^2)
평균적, 최선 시간복잡도 O(nlogn)
BigO란 알고리즘의 시간복잡도를 나타내는 표기법입니다.
dfs와 bfs 모두 그래프를 탐색하는 방법입니다. dfs는 현재 정점에서 갈 수 있는 점들까지 들어가면서 탐색하고, bfs는 현재 정점에 연결된 가까운 점들부터 탐색합니다.
bfs는 큐로 구현하고, dfs는 재귀함수 또는 스택으로 구현한다.
알고리즘 문제풀 때 그래프 문제인지는 알겠는데 bfs로 풀어야 하는지 dfs로 풀어야 하는지 헷갈릴 때가 많았다. 아래는 이를 구분할 수 있는 몇가지 특징들이다.
그래프는 연결되어 있는 객체간의 관계를 표현할 수 있는 자료구조입니다. 트리는 그래프의 일종입니다. 트리는 루트 노드를 가지며, 부모-자식 관계로 이루어져있고, 사이클을 가져선 안됩니다.
트리의 순회는 전위순회, 중위 순회, 후위 순회로 이루어진다. 얘네들은 dfs,bfs에 포함된다.
(문제 출처: 카카오 2018 필기시험)
스택은 후입선출(LIFO)로 마지막에 넣은 데이터가 가장 먼저 나오고, 큐는 선입선출(FIFO)로 먼저 넣은 데이터가 먼저 나갑니다.
HashMap과 Hashtable은 데이터를 키와 값으로 관리하는 자료구조입니다. HashTable은 동기화를 지원하고, HashMap은 동기화를 지원하지 않습니다.
HashTable이 동기화를 지원해 Thread-safe 하므로 멀티스레드 환경에서는 HashTable을 써야한다. 멀티스레드가 아니라면 HashMap이 성능이 더 좋으니까 HashMap 쓰는게 좋다.
재귀로 구현할 경우 시간복잡도는 O(2^n)입니다. 동적계획법과 반복으로 구현할 경우 시간복잡도는 O(n)입니다.
재귀
def fibo(n):
return fibo(n-1) + fibo(n-2) if n >= 2 else n
for n in range(1, 11):
print(n, fibo(n))
시간복잡도:O(2^n)
공간복잡도:O(2^n)
반복
def fibo(n):
if n < 2:
return n
a, b = 0, 1
for i in range(n-1):
a, b = b, a + b
return b
for n in range(1, 11):
print(n, fibo(n))
시간복잡도:O(n)
공간복잡도:O(n)
dp
if dp[k]!=-1:
return dp[k]
elif k==0:
return 0
elif k==1:
return 1
else:
dp[k]=Fibo(k-1)+Fibo(k-2)
시간복잡도:O(n)
공간복잡도:O(n)
array는 요소들을 인덱스를 통해 직접 접근할 수 있으므로 O(1) 시간만에 접근할 수 있습니다. LinkedList는 순차적으로 찾아야 하므로 특정 요소를 검색할 때 O(n)의 시간이 걸립니다.
요소 접근
배열: O(1)
연결리스트: O(n)
삽입,삭제
배열: O(n)
연결리스트: O(1)
크기
배열: 크기 고정
연결리스트: 크기 동적
삽입과 삭제가 번번히 이루어진다면, 연결리스트 사용이 좋음.
이미 만들어진 구조에서 데이터의 접근만 필요하면 배열이 좋음.
우선순위 큐는 우선순위가 먼저 나오는 자료구조입니다. 루트 노드에 우선순위가 높은 데이터를 위치시키는 자료구조인 힙을 이용하여 우선순위 큐를 구현합니다.
🔎 Heap이란?
예를 들어 위 그림은 루트에 젤 큰값이 오는 최대힙이다.
루트가 제일 큰 건 알겠는데 왼쪽 자식, 오른쪽 자식 배치는 조금 의문스러운데...그 이유는 일단 삽입할때 트리 끝에 냅다 위치시킨 다음 한칸 한칸 올라가며 자신의 자리를 찾기 때문이다.
Heap에서 insert, remove 할 시 시간복잡도는 O(logn)입니다.
🔎 재구조화(heapify)
삽입과 삭제 시 다시 최대 힙의 조건을 만족하도록 노드의 위치를 바꾸는 것을 재구조화(heapify)라고 한다. 힙에서 삽입,삭제 자체는 O(1) 시간이 걸리지만 이 재구조화에 O(logn) 시간이 걸린다.