2016년 7월 25일 월요일

Quick sort

퀵소트(quick sort)는 데이터를 순서를 구분할 수 있는 두 개의 영역으로 나누는 작업(partition)을 반복하여 정렬하는 알고리즘이다. 퀵소트의 핵심인 partition의 여러 가지 구현 방식 중, 별도의 메모리 할당 없이 partition을 수행하는 것을 소개한다.
데이터의 영역을 1) 보다 작은 값이 모여 있는 영역, 2) 보다 큰 값이 모여 있는 영역, 3) 구분되지 않은 값이 모여 있는 영역으로 나누고, 구분되지 않는 영역의 길이가 0이 될 때까지 아래의 단계를 반복한다 (처음 시작할 때는 보다 작은 값들의 영역과 보다 큰 값들의 영역의 길이는 각각 0, 0이고,  partition이 끝난 후에는 구분되지 않은 값들의 영역의 길이가 0이다).

  • 구분되지 않은 영역의 첫번째 값이 기준값보다 크거나 같은 경우, 해당 값을 보다 큰 값의 영역으로 변경
  • 구분되지 않은 영역의 첫번째 값이 기준값보다 작은 경우, 보다 큰 값이 모여 있는 영역의 첫번째 값과 구분되지 않는 영역의 첫번째 값을 서로 바꿔, 해당 값을 보다 작은 값의 영역으로 변경
+-----------------------+----------------------+-------------------------------+ 
 |      보다 작은 값들      |       보다 큰 값들        |        구분되지 않은 값들          |
+-----------------------+----------------------+-------------------------------+ 

기준값을 정하는 것이 정렬 성능에 영향을 주게 되는데, 아래의 구현에서는 데이터의 가장 마지막 값을 기준값으로 사용한다.

======================================================


package main

import "fmt"

func QuickSort(data []int) {
    size := len(data)
    QuickSortUtil(data, 0, size - 1)
}

func QuickSortUtil(data []int, from int, to int) {
    if from >= to {
        return
    }
    pivot := Partition(data, from, to)
    QuickSortUtil(data, from, pivot - 1)
    QuickSortUtil(data, pivot + 1, to)
}

func Partition(data []int, from int, to int) int {
    refVal := data[to]
    untouched, lastSmall := from, from - 1

    for ; untouched < to; untouched++ {
        if data[untouched] < refVal {
            lastSmall++;
            data[lastSmall], data[untouched] = data[untouched], data[lastSmall]
        }
    }
    lastSmall++
    data[lastSmall], data[to] = data[to], data[lastSmall]

    return lastSmall

}

func main() {
    dataSet := make([][]int, 6)
    dataSet[0] = []int{4, 3, 2, 6, 5, 7, 1}
    dataSet[1] = []int{1, 2, 3, 4, 5, 6, 7}
    dataSet[2] = []int{7, 6, 5, 4, 3, 2, 1}
    dataSet[3] = []int{1, 1, 1, 1, 1, 1, 1}
    dataSet[4] = []int{1}
    dataSet[5] = []int{}

    for _, data := range dataSet {
        QuickSort(data)
        for _, elem := range data {
            fmt.Printf("%d ", elem)
        }
        fmt.Println()
    }
}

잔돈 만드는 방법 (Coin change)

숫자(N)와 숫자의 집합(C = {C1, C2, C3, ...}이 주어졌을 때, C의 숫자들을 중복으로 사용하여 N을 만드는 방법의 수를 구해보자.  잔돈 문제로 바꾸어서 표현하면, 각각 값어치가 C1, C2, C3, ... 인 동전이 무한대로 주어질...