들어가며
Insertion Sort는 O(n^2)의 시간복잡도를 가진 정렬 알고리즘이다. 내가 알고 있는 O(n^2)의 시간복잡도를 가진 알고리즘은 버블소트, 셀렉션소트, 인서션소트 이 세 가지인데, 이 중 가장 효율적인 알고리즘이기도 하다.
Code
public void insertionSort(int[] arr) {
if(arr.length < 1) {
return;
}
for(int i = 1; i<arr.length; i++) {
int target = arr[i];
int subIdx = i - 1;
while(subIdx >= 0 && arr[subIdx] > target) {
arr[subIdx + 1] = arr[subIdx];
subIdx--;
}
arr[subIdx + 1] = target;
}
}설명
정렬되지 않은 배열이 하나 있다고 가정하자.
int [] arr = {2, 3, 1, 5, 4}이 배열의 첫번째 값만 확인해보자.
int [] arr = {2}이렇게 놓고 보면, 위의 배열은 정렬되어 있는 상태이다.
그러면 여기서 3까지 고려해 보자.
int [] arr = {2, 3}이 상태도 역시 정렬되어 있는 상태이다. 그러면 다음 값을 생각해 보자.
int [] arr = {2, 3, 1}1을 고려대상으로 삼은 상황에서, 이미 앞의 두 수 (2,3)은 정렬되어 있는 상태이다. 이제 1을 자기 왼쪽에 있는 값과 비교하여, 자기 왼쪽에 있는 값이 더 크다면 그 값을 오른쪽으로 한칸 움직인다.
3 > 1 이므로
int [] arr = {2, 1, 3}2 > 1 이므로
int [] arr = {1, 2, 3}이제 이 상황에서 5를 생각해 보자.
int [] arr = {1, 2, 3, 5}3 < 5 이므로 값의 변화는 없다.
마지막 수인 4를 고려해보자.
int [] arr = {1, 2, 3, 5, 4}5 > 4 이므로 4를 왼쪽으로 한칸 움직인다.
int [] arr = {1, 2, 3, 4, 5}위와 같은 과정을 거쳐, 배열을 정렬할 수 있다.
시간 복잡도
O(n^2) 이다. 최악의 경우를 고려해 보면, 배열이 역정렬되어 들어온 경우이다.
int [] arr = {5, 4, 3, 2, 1}이렇게 되면,
- 맨 처음에는 배열을 한 개 탐색 (1) 하고 4를 5의 위치에 집어넣는 연산(c)을 수행해야 한다.
- 그 다음에는 배열을 두 개 탐색 (2) 하고 3을 배열의 맨 처음에 놓는 연산(c)을 수행해야 한다.
이런 과정을 거치다 보면, 마지막에는 n-1개의 배열을 탐색해야 한다.
그러므로 시간복잡도의 총합은 1+2+…+ n - 1 이고, 이는 n(n-1)/2이므로 O(n^2)이다.
selection sort VS insertion sort
이 두 알고리즘은 insertion sort가 조금 더 효율적인데, 그 이유는 selection sort는 최소값을 찾기 위해 전 배열을 모두 찾아야 하기 때문이다. 즉, 항상 1+2+…+n-1 의 연산이 요구된다. 반면에 insertion sort는 최악의 경우에만 1+2+…+n-1이기 때문에 insertion sort가 조금 더 빠르다.