ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Insertion Sort with Swift
    DataStructure + Algorithm/Basic Theories 2021. 10. 9. 03:30

    Insertion Sort 는, 단순한 Sorting Algorithms 중 경우에 따라 비교적 빠를 수 있는 Algorithm 입니다. 

    특히 대부분이 이미 정렬되어있는 경우 O(n) 까지 빨라질 수 있는데요, 그 원리를 하나하나 알아보겠습니다.

     

    Example 1

    첫 예시는 다른 Sorting 의 예시들처럼 아래 행렬을 가지고 차례차례 순서를 밟아보겠습니다.

     

    [4,3,5,2,1]

    1. 첫번째 element 인 4 를 먼저 하나의 상자에 넣습니다.

    [4]
    [4, 3, 5, 2, 1]

     

    2. 두번째 element 인 3 과 상자에 있는 수(4) 를 비교합니다. 3이 더 작으므로, 상자 안에 3을 넣을 때 상자의 앞쪽에 넣습니다.

    [3, 4]
    [3, 4, 5, 2, 1]

     

    3. 상자 [3, 4] 와 그 다음에 오는 element 5 를 비교합니다. 5 는 상자 뒤 끝 수 (가장 높은 수) 보다 높으므로, 상자의 뒤쪽 끝에 넣습니다.

    [3, 4, 5]
    [3, 4, 5, 2, 1]

     

    4. 상자 [3, 4, 5]와 다음 element 2 를 비교합니다. 5 부터 2 와 비교하기 시작했을 때, 2 는 5, 4, 3 보다 작으므로 상자의 앞쪽 끝에 넣습니다. 

    [2, 3, 4, 5]
    [2, 3, 4, 5, 1]

    이제 숫자가 1 하나 남았습니다.

    5. 위 방식과 동일하게, 상자 뒤쪽 수들과 비교하며 적당한 위치를 찾아서 넣습니다. 

     

    [1, 2, 3, 4, 5]
    [1, 2, 3, 4, 5]

    Insertion Sorting 이 끝났습니다!

     

    처음 배열 [4, 3, 5, 2, 1] 은 초기 상태가 거의 sorting 되지 않았기 때문에 5 를 상자에 넣는 과정 외에는 Bubble Sort, Selection Sort 와 과정의 수에 차이가 거의 없었음을 볼 수 있습니다.

     

     

    Example 2

    이제 거의 Sorting 되어있는 배열과 비교해보겠습니다.

     

    [2,3,4,5,1]

     

    1. 처음으로, 2 를 먼저 상자에 넣습니다.

    [2]
    [2, 3, 4, 5, 1]

     

    2. 다음 수 (3) 와 상자 내의 element (2) 값을 비교합니다. 다음 수가 상자의 수 (2) 보다 크므로, 상자의 뒤쪽 끝에 위치시킵니다.

    [2, 3]
    [2, 3, 4, 5, 1]

     

    3. 다음 수 (4) 와 상자 내의 뒤쪽 끝 element (3) 을 비교합니다. 다음 수가 상자 뒤쪽 끝 수보다 크므로, 상자의 뒤쪽 끝에 위치시킵니다.

    [2, 3, 4]
    [2, 3, 4, 5, 1]

     

    4. 다음 수 (5) 와 상자 내의 뒤쪽 끝 element (4) 을 비교합니다. 다음 수가 상자 뒤쪽 끝 수보다 크므로, 상자의 뒤쪽 끝에 위치시킵니다.

    [2, 3, 4, 5]
    [2, 3, 4, 5, 1]

     

    5.  다음 수 (1) 와 상자 내의 뒤쪽 끝 element (5) 을 비교합니다. 이번에는 다음 수가 더 작습니다. 상자의 다른 값들과도 차례로 비교합니다.

    5 > 1

    4 > 1

    3 > 1

    2 > 1 

    1 을 상자의 적당한 위치 ( 앞쪽 끝) 에 위치시킵니다.

    [1, 2, 3, 4, 5]
    [1, 2, 3, 4, 5]

    Insertion Sort 가 종료되었습니다 !

     

    두번째 예제에서는, 앞 4 개의 수가 모두 이미 정렬되어있었고, 따라서 한번씩만 비교를 하고 정렬을 시켜주었습니다.

    만약 [1, 2, 3, 4, 5] 를 Insertion Sort 시킨다고 한다면, 총 4 번의 과정만 거치면 정렬이 완료됩니다. ( O(n) )

     

     

     

     

    Implementation

    이제, Swift Code 로 Insertion Sort 를 만들어보겠습니다. 

    func insertionSort(arr: [Int]) -> [Int] {
        if arr.count == 0 { return arr }
        
        var box : [Int] = [arr[0]]
        var toBeCompared : Int
        
        for i in 1 ..< arr.count {
            toBeCompared = arr[i]
            
            boxLoop: for boxIndex in 0 ..< box.count {
                
                if box[box.count - 1 - boxIndex] < toBeCompared {
                    box.insert(toBeCompared, at: box.count - 1 - boxIndex + 1)
                    break boxLoop
                }
                
                if boxIndex == box.count - 1 {
                    box.insert(toBeCompared, at: 0)
                }
            }
        }
        
        return box
    }

    위 코드에서 설명과 다르게 보이는 것은 target Array 가 변하지 않는 것 입니다. insertionSort funtion 은 box 를 return 하기 때문에 기존 input array 의 변화 없이 box 만 값을 순서대로 추가시켜줍니다. 또한, 'boxLoop' 는 쓰이지 않아도 전혀 지장이 없지만, 내부 for statement 에서 나갈 때 혼동이 없도록 표기하였습니다. 

     

     

    box 는 새로 만들어나가서 마지막에 return 될 array ('상자') 이며

    toBeCompared (비교대상) 는 box 내 값들과 비교 후 box 에 삽입될 값을 의미합니다.

     

     

    1. 처음에 함수가 호출되면, empty array 가 아닌지 확인합니다. (arr.count == 0 ) 

    2. box 에 하나의 element arr[0] 을 갖는 [Int] 를 대입합니다.

    3. 첫번째 for statement 의 index 'i' 는 toBeCompared 의 index 에 대한 것입니다. ( 1, 2, ... arr.count - 1 )

    4. 두번째 for statement는 box 내 elementstoBeCompared 를 차례대로 (box 의 뒤쪽 element 부터 앞쪽까지) 비교하는 곳입니다. 

    5. 두번째 for statement 에서, toBeCompared 가 box 내 어떤 값보다 크다면 그 값의 뒤쪽에 삽입 후 boxLoop 를 종료합니다.

    6. 두번째 for statement 에서, toBeCompared 가 box 내 모든 값보다 크지 않다면, box 의 가장 앞에 삽입합니다. (boxIndex 가 boxLoop 의 마지막 값이므로 boxLoop 를 자동으로 종료하게 됩니다.) 

    7. 해당 과정을 끝까지 (target Array 의 index 마지막까지) 반복한 후 생성된 box 를 return 합니다.

     

     

    [4, 3, 5, 2, 1] array 를 이용해서 insertionSort function 을 테스트 해보았습니다.

    let testArr = [4,3,5,2,1]
    
    func insertionSort(arr: [Int]) -> [Int] {
        if arr.count == 0 { return arr }
        
        var count = 0
        var box : [Int] = [arr[0]]
        var toBeCompared : Int
        print("target Array: \(arr)\n")
        for i in 1 ..< arr.count {
            toBeCompared = arr[i]
            print("box: \(box)\n")
            boxloop: for boxIndex in 0 ..< box.count {
                count += 1
                print("compare \(box[box.count - 1 - boxIndex]) with \(toBeCompared)")
                if box[box.count - 1 - boxIndex] < toBeCompared {
                    
                    box.insert(toBeCompared, at: box.count - 1 - boxIndex + 1)
    
                    break boxloop
                }
                
                if boxIndex == box.count - 1 {
                    box.insert(toBeCompared, at: 0)
    
                }
            }
        }
        print("box: \(box)")
        print("count :\(count)")
        return box
    }
    
    insertionSort(arr: testArr)
    더보기

    //target Array: [4, 3, 5, 2, 1]
    //
    //box: [4]
    //
    //compare 4 with 3
    //box: [3, 4]
    //
    //compare 4 with 5
    //box: [3, 4, 5]
    //
    //compare 5 with 2
    //compare 4 with 2
    //compare 3 with 2
    //box: [2, 3, 4, 5]
    //
    //compare 5 with 1
    //compare 4 with 1
    //compare 3 with 1
    //compare 2 with 1
    //box: [1, 2, 3, 4, 5]
    //count :9

    위와 같은 코드로 실험을 진행했을 때, target Array 가 [4, 3, 5, 2, 1] 일 때는 9번, [2, 3, 4, 5, 1] 일 때는 7번 비교한다는 것을 알 수 있습니다. 

     

    array 의 크기가 커질수록 차이는 커지게 되고 크기를 9 로 한다고 하면 

    [1,2,3,4,5,6,7,8,9] 으로 정렬을 시행했을 때는 8번, ( best case) 

    [2,3,4,5,6,7,8,9,1] 으로 정렬을 시행했을 때는 15번,

    [9,8,7,6,5,4,3,2,1] 으로 정렬을 시행했을 때는 36번 비교하게 됩니다. (worst case)  

     

    'DataStructure + Algorithm > Basic Theories' 카테고리의 다른 글

    LinkedList  (0) 2021.10.13
    Stack, Queue With Swift  (0) 2021.10.12
    SelectionSort with Swift  (0) 2021.10.08
    Bubble Sort With Swift  (0) 2021.10.08
    Array Sorting Algorithms  (0) 2021.10.08
Designed by Tistory.