삽입 정렬

Last updated - 2023년 04월 26일 Edit Source


    # 삽입정렬 개념

    삽입정렬 (Insertion Sort) : 새로운 원소를 이전까지 정렬된 원소 사이에 올바르게 삽입시키는 알고리즘

    • 0번째 인덱스는 앞에 숫자가 없어서 정렬의 시작은 1번째 인덱스임
      • 1번째 인덱스부터 시작해서 앞의 원소들과 비교하며 삽입할 위치를 지정하고, 원소를 한칸씩 뒤로 다 땡기고 지정된 자리에 삽입하는 알고리즘
      • 들어갈 위치가 있는 것으로 보아 선택정렬과 유사해보이지만, 더 효율적임
      • 백준 줄세우기 문제가 삽입정렬임
    • 시간복잡도 : $O(n^2)$
      • 최선 : $O(n)$ (이미 정렬된 경우 + 최적화), 평균 : $O(n^2)$, 최악 : $O(n^2)$
      • 외부 루프를 n-1번 도는 동안, 각 자리에 와야하는 값을 구하기 위해 n-1, n-2, … , 1번 비교
      • $T(n) = (n-1) + (n-2) + … + 1 = (n-1) * \frac{n}{2}$
    • 공간복잡도 : $O(1)$
      • 교환(swap)을 통해 정렬이 수행되므로, 추가적인 배열 공간 필요없음
      • 만약, 새로운 배열을 만들어서 거기 삽입하면, 그때는 공간복잡도 $O(n)$
    • 안정성&제자리성 : 안정 정렬(Stable-sort), 제자리 정렬(In-place sort)
      • 비교대상의 원소가 새로운 원소보다 클 때만 한자리 뒤로 이동시키니까 당연히 처음 순서가 유지되니까 → 안정
      • 기존 배열 이외의 추가적인 메모리를 거의 사용하지 않고 배열 안에서 교환 → 제자리



    # 삽입정렬 - 단순 반복


     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
    
    import java.util.Arrays;  
      
    public class Insertion {  
        private static void insertionSort(int[] arr) {  
            // 0번 인덱스는 앞에 숫자가 없으니까 1번 인덱스부터 시작  
            for (int i = 1; i < arr.length; i++) {  
                // 뒤에서부터 동작하는 이유는, 앞에서부터 값을 땡기면  
                // 그 값만 뒤로 복사돼서 그럼  
                for (int j = i - 1; j >= 0; j--) {  
                    if (arr[j] > arr[j + 1])  
                        swap(arr, j, j + 1);  
                }  
            }  
        }  
      
        private static void swap(int[] arr, int preIndex, int currentIndex) {  
            int temp = arr[preIndex];  
            arr[preIndex] = arr[currentIndex];  
            arr[currentIndex] = temp;  
        }  
      
        public static void main(String[] args) {  
            int[] arr = {3, 2, 1, 8, 4, 5, 7, 12, 3};  
            System.out.println("Before Sorting: " + Arrays.toString(arr));  
            insertionSort(arr);  
            System.out.println("After Sorting: " + Arrays.toString(arr));  
        }  
    }
    



    # 삽입정렬 - 최적화 반복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
    
    import java.util.Arrays;  
      
    public class Insertion {  
        private static void insertionSort(int[] arr) {  
            for (int i = 1; i < arr.length; i++) {  
                int j = i - 1;  
                // while 안에다가 비교 작업을 넣어버렸음  
                while (j >= 0 && arr[j] > arr[j + 1]) {  
                    swap(arr, j, j + 1);  
                    j--;  
                }  
            }  
        }  
      
        private static void swap(int[] arr, int preIndex, int currentIndex) {  
            int temp = arr[preIndex];  
            arr[preIndex] = arr[currentIndex];  
            arr[currentIndex] = temp;  
        }  
      
        public static void main(String[] args) {  
            int[] arr = {3, 2, 1, 8, 4, 5, 7, 12, 3};  
            System.out.println("Before Sorting: " + Arrays.toString(arr));  
            insertionSort(arr);  
            System.out.println("After Sorting: " + Arrays.toString(arr));  
        }  
    }
    
    • while문을 만들면서 안에다가 비교작업을 넣은 이유
      • 삽입될 숫자보다 작은 숫자들은 이미 정렬 해놓았기 때문에 비교가 무의미해서
      • 예를 들어, [1, 2, 3, 5]가 있고 4를 추가하는 상황이면 3이 4보다 작다는 사실만 파악하면 됨. 이 이상의 대소 비교는 무의미



    # 삽입정렬 - 최적화 반복2


     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    
    import java.util.Arrays;  
      
    public class Insertion {  
        private static void insertionSort(int[] arr) {  
            for (int i = 1; i < arr.length; i++) {  
                int current = arr[i];  
                int j = i - 1;  
                while (j >= 0 && arr[j] > current) {  
                    arr[j + 1] = arr[j];  
                    j--;  
                }  
                arr[j + 1] = current;  
            }  
        }  
      
        public static void main(String[] args) {  
            int[] arr = {3, 2, 1, 8, 4, 5, 7, 12, 3};  
            System.out.println("Before Sorting: " + Arrays.toString(arr));  
            insertionSort(arr);  
            System.out.println("After Sorting: " + Arrays.toString(arr));  
        }  
    }
    
    • 사실 swap 작업도 필요 없음
    • 앞의 값이 정렬 범위에 추가시킨 값보다 크면 앞의 값을 뒤로 밀고 제일 작은거 만나는 순간 그 뒤에 추가된 값을 꽂으면 됨



    # 삽입정렬 - 재귀 구현


     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
    
    import java.util.Arrays;  
      
    public class Insertion {  
        private static void insertionSort(int[] arr) {  
            // 0번 인덱스는 앞에 숫자가 없으니까 1번 인덱스부터 시작  
            insertionSort(arr, 1);  
        }  
      
        private static void insertionSort(int[] arr, int start) {  
            // 배열의 마지막 방까지 재귀호출  
            if (start < arr.length) {  
                // 현재 숫자는 1부터 시작  
                int currentNum = arr[start];  
                // 삽입할 곳의 인덱스는 0부터 시작하니까 start - 1            
                int targetIndex = start - 1;  
      
                // 현재 숫자를 비교 대상들과 비교하여 삽입할 위치 찾기  
                // 뒤에서부터 동작하는 이유는, 앞에서부터 값을 땡기면 그 값만 뒤로 복사돼서 그럼  
                while (targetIndex >= 0 && currentNum < arr[targetIndex]) {  
                    // 더 큰 값들을 오른쪽으로 이동  
                    arr[targetIndex + 1] = arr[targetIndex];  
                    targetIndex--;  
                }  
      
                // 현재 숫자를 삽입할 위치에 삽입  
                arr[targetIndex + 1] = currentNum;  
                // 다음 원소에 대해 재귀적으로 정렬 수행  
                insertionSort(arr, start + 1);  
            }  
        }  
      
        public static void main(String[] args) {  
            int[] arr = {3, 2, 1, 8, 4, 5, 7, 12, 3};  
            System.out.println("Before Sorting: " + Arrays.toString(arr));  
            insertionSort(arr);  
            System.out.println("After Sorting: " + Arrays.toString(arr));  
        }  
    }
    

    Comment