LoginSignup
0
0

More than 5 years have passed since last update.

go で counting sort やってみる

Posted at

counting sort

ソートアルゴリズムの1つ
メモリに心配なければ早そう O(n+k)

x(n) の配列

制約

すべてのx[i]に対して

0 <= x[i] < k

が成り立つ前提

なので配列内でとりうる値の範囲がわかっていないと利用できない

kが大きくなればなるほど分布を保持する配列のメモリ割り当てが必要

n = 10
k = 5

において下記配列を並び替えてみる

x(10) = [3, 4, 2, 1, 0, 0, 4, 3, 4, 2] # len = 10

① すべてのx(n) の要素に対して出現回数を求める。結果をカウント配列countMapに格納する

package counting_sort

import "fmt"

func counting_sort(x []int, k int) {
    countMap := make([]int, k)
    // create map
    for _, val := range x {
        countMap[val]++
    }
    fmt.Printf("countMap: %#v\n", countMap)
}

test でデバッグ

package counting_sort

import (
    "reflect"
    "testing"
)

func Test_counting_sort(t *testing.T) {
    type args struct {
        x []int
        k int
    }
    tests := []struct {
        name string
        args args
        want []int
    }{
        {
            name: "ok_0",
            args: args{
                x: []int{3, 4, 2, 1, 0, 0, 4, 3, 4, 2},
                k: 5,
            },
            want: []int{0, 0, 1, 2, 2, 3, 3, 4, 4, 4},
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            counting_sort(tt.args.x, tt.args.k)
            if !reflect.DeepEqual(tt.args.x, tt.want) {
                t.Errorf(`
                name: %v,
                act. %v
                exp. %v
            `, tt.name, tt.args.x, tt.want)
            }
        })
    }
}
=== RUN   Test_counting_sort
=== RUN   Test_counting_sort/ok_0
# countMap: []int{2, 1, 2, 2, 3}
--- FAIL: Test_counting_sort (0.00s)
    --- FAIL: Test_counting_sort/ok_0 (0.00s)
        /Users/kouhei/go/src/github.com/smith-30/algo/counting_sort/main_test.go:31: 
                            name: ok_0,
                            act. [3 4 2 1 0 0 4 3 4 2]
                            exp. [0 0 1 2 2 3 3 4 4 4]

FAIL
FAIL    github.com/smith-30/algo/counting_sort  0.018s
Error: Tests failed.

② countMapのvalueを、keyがxのインデックスの最大値を示すように更新する

言葉で説明しにくいのでコードを参照ください、、

package counting_sort

import "fmt"

func counting_sort(x []int, k int) {
    countMap := make([]int, k)
    // create map
    for _, val := range x {
        countMap[val]++
    }

    // change countMap's value.
    var prev int
    for k, val := range countMap {
        prev += val
        countMap[k] = prev
    }
    fmt.Printf("countMap: %#v\n", countMap)
}

このようになります

countMap: []int{2, 3, 5, 7, 10}

ステップ1でのkeyに対する出現個数から、keyに対するvalueがxにおけるインデックスの最大番号となるようにしている
例えば、最後の10はkeyが4なので、4の値がxの10番目にはあるというと。

③ countMapを使ってxの値を配列 resultに詰める(resultがsort後の配列)

package counting_sort

func counting_sort(x []int, k int) []int {
    result := make([]int, len(x))
    countMap := make([]int, k)

    // ① create map
    for _, val := range x {
        countMap[val]++
    }

    // ② change countMap's value.
    var prev int
    for k, val := range countMap {
        prev += val
        countMap[k] = prev
    }

    // ③ while decreasing a, put the value of x in result.
    for _, val := range x {
        countMap[val]--
        result[countMap[val]] = val
    }

    return result
}

countMapの値を減らすことで次にきたvalueをどのインデックスに詰めればよいかを実現しています。

処理の計算量的には
①でO(n)
②でO(k)
③でO(n)

なのでO(2n+k) ?
O(n+k) って書いてあったけどどうしてなんだろ、、?

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0