LoginSignup
1
0

More than 1 year has passed since last update.

小さいサイズの辞書は線形探索でいいかも

Last updated at Posted at 2021-09-05

これは何?

C++ で辞書(key-value pair)がほしい場合。

とりあえず std::unordered_mapstd::map を使うと思う。

状況によっては boost::container::flat_map を使うこともあると思う。

でも、要素数が少ない場合は線形探索のほうが速かったりするんじゃないの? と思って測ってみた。

登場人物

std::map

中身は赤黒木。ポインタをたどって要素を探す。

std::unordered_map

中身は Hashテーブル。ハッシュ値でスロットを特定する。スロット内はよく知らない。

boost::container::flat_map

中身は整列済みの配列のようなもの。二分探索で要素を探す。
挿入は遅いけど、探索は速いという評判。

線形探索

中身は vector。先頭から普通に探す。

調査内容

キーのバイト数 K、コンテナに入れる要素数 E、試行回数 T を決める。
コンテナを 16個、キーを 16個作る。
作ったキーをキー、値を適当な 64bit整数 にしてコンテナに値を入れる。コンテナに入れる要素数は 16個とも E。
以下の操作を行う時間を測る
合計のための変数 sum を用意する

  • T 回、以下の操作をする
    • 使うキーとコンテナを乱数で決める
    • 上記で決まったコンテナにキーを渡して値を得る。
    • 得られた値を sum に加算する

コンパイラは、 Apple clang version 12.0.5 (clang-1205.0.22.11) / x86_64-apple-darwin20.6.0。
コンパイルオプションに -O2 -std=c++17 を入れている。
ハードウェアは手元の MacBook Pro。

調査結果

以下グラフは、横軸がコンテナサイズ。縦軸が処理時間(秒)。
対数目盛注意。

key is uint32 × 1.png

key is uint32 × 2.png

key is uint32 × 4.png

key is uint32 × 16.png

key is uint32 × 256.png

試行回数は key のサイズで適当に変えている。例えば key が uint32 × 1 の場合は 4194304回、key が uint32 × 256 の場合、16384回施行している。

感想

グラフを見ると分かる通り、キーのサイズで様子が違う。キャッシュに乗るかどうかが勝負なのかな。

unordered_map で、要素数が増えると却って速くなる部分があって謎だけど調べていない。

あと

  • キーのバイト数が少ないと線形が有利。
  • unordered_map が速い。flat_map は意外と振るわない。
  • キーが 32bit ぐらいで unordered_map との比較なら、10〜30 個ぐらいまでは線形有利。
  • キーが 32bit ぐらいで map との比較なら、30〜100 個ぐらいまでは線形有利。

辺り。
もちろん処理系とかキャッスサイズとか色々で変わるのでこの実験結果の汎用性はあまりないと思う。

この調査では map がいまいちな感じだけど、比較がハッシュ値の計算より安いケースでは map が圧勝したりするので、ケースバイケースということではある。

まとめ

存在しないキーで探索する割合とか、キャッシュの効き具合とか、時間に影響を与える条件がたくさんあるので、一般的で公平なベンチマークは存在しないと思う。

要素数が少ないとわかっているときは線形も悪くないなと思ったけど、std::linear_map みたいなのがないので実装するとしたら手作りになるからめんどくさい。どっかに作っておこうかな。それとももうどっかにあるのかなぁ。

あと、要素数が少ない場合は線形で、要素数が多くなると Hashテーブルになる、みたいな対応をするといつでも速くなるかもとも思った。うまくやる方法はあるのだろうか。

実験に使ったコードを github に置いた。

1
0
3

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
1
0