[정렬 알고리즘] 두 배열의 원소 교체 4. 계수 정렬로 풀어보기

doyeonjeong_·2023년 1월 16일
0

Algorithm

목록 보기
7/8

📝 계수 정렬 (Counting Sort)

가장 작은 데이터와 큰 데이터를 모두 담을 수 있는 빈 배열을 생성한 후,
각 데이터에 맞는 인덱스에 몇개나 있는지 Count하여 새로운 배열을 만드는 정렬이다.

1️⃣ 순서

1. 가장 작은 데이터와 가장 큰 데이터의 범위를 담을 배열을 생성한다.
2. 배열을 1번 순회하여 아까 만든 배열의 index에 count 한다.

2️⃣ 코드

var array = [5, 7, 9, 0, 3, 1, 6, 2, 4, 8]

func countSort(_ array: inout [Int]) -> [Int] {
    let maxValue = array.max() ?? 0                             // 1. 가장 큰 값을 구한다
    var countArray = [Int](repeating: 0, count: maxValue + 1)   // 2. 가장 큰 값 + 1 크기의 배열을 만든다
    for value in array {
        countArray[value] += 1                                  // 3. 순회하며 해당 값이 있는 index에 count한다
    }
    var sortedArray = [Int]()
    for (index, count) in countArray.enumerated() {             // 4. count만큼 index의 값을 append하여 정렬한다
        for _ in 0..<count {
            sortedArray.append(index)
        }
    }
    return sortedArray
}

print(countSort(&array))

3️⃣ 정리

  • 안정성 : Stable Sort
    - 각 원소끼리 비교하지 않기 때문에 안정성을 가진다.
  • 제자리성 : In-place
    - 기존 배열 이외의 메모리를 거의 사용하지 않는다.
  • 시간 복잡도
    - 최선 : 𝛰(𝛮) 𝛮이 𝛫보다 클 경우
    - 최악 : 𝛰(𝛮 + 𝛫)
  • 장점 : 퀵 정렬의 평균 속도보다 빠를 수 있음. (단, 데이터의 차이가 1,000,000 미만인 경우에 적합)
  • 단점 : 추가적인 메모리가 많이 필요할 수 있다.

[문제] 두 배열의 원소 교체

N개의 원소로 이뤄진 두 배열 A, B가 있다. 최대 K번의 바꿔치기 연산을 할 수 있다. 바꿔치기 연산을 수행하여 만들수 있는 배열 A의 원소 합의 최댓값을 구하여라.

입력 조건
1. 첫째줄에는 N, K가 주어진다. (1 ≤ K ≤ N ≤ 100,000)
2. 둘째줄부터 각각 배열 A, B의 원소들이 주어진다. 모든 원소는 10,000,000보다 작은 자연수이다.

입력 예

5 3
1 2 5 4 3
5 5 6 6 5

출력 예

26

🌀 풀이

// 계수 정렬
func ascendingCountSort(_ array: inout [Int]) -> [Int] {
    let maxValue = array.max() ?? 0
    var countArray = [Int](repeating: 0, count: maxValue + 1)
    for value in array {
        countArray[value] += 1
    }
    var sortedArray = [Int]()
    for (index, count) in countArray.enumerated() {
        for _ in 0..<count {
            sortedArray.append(index)
        }
    }
    return sortedArray
}

func descendingCountSort(_ array: inout [Int]) -> [Int] {
    let maxValue = array.max() ?? 0
    var countArray = [Int](repeating: 0, count: maxValue + 1)
    for value in array {
        countArray[value] += 1
    }
    var sortedArray = [Int]()
    for (index, count) in countArray.enumerated().reversed() {
        for _ in 0..<count {
            sortedArray.append(index)
        }
    }
    return sortedArray
}

계수 정렬은 데이터의 범위가 제한적일 때 효과적인데, 현재 문제 기준으로는 적합하지 않다.
다만, 주어진 예시의 범위가 좁기 때문에 임의로 0부터 7까지로 제한한 후 적용시켜 보았다.

입력 배열에서 각 값이 몇 개 있는지 계수하여 각 값을 인덱스로 하는 countArray를 만들고, 그 다음 countArray를 이용하여 정렬된 배열을 만든다.

주의할 점은 입력 배열에서 최대 값이 maxValue라 가정하고 countArray를 생성하므로 countArray에 없는 값이 입력되면 이 함수는 제대로 작동하지 않는다.

드디어...!

정렬 시리즈가 끝이 났다 🥲🥲🥲
하지만 ... 다음은 이진 탐색 ... 갈길이 멀다.


🫥 글의 복잡성을 줄이기 위해 공통 input과, K번 바꾸기 연산은 첫 글에만 명시했습니다! 궁금하다면 여기를 눌러주세요.

profile
블로그 이사중 🚚 byukbyak.tistory.com

0개의 댓글