LoginSignup
5
2

More than 5 years have passed since last update.

Fortranで連想配列を書いた話

Last updated at Posted at 2019-02-22

概要

  • FortranはC++等に比べて出来ることが限られていて変なプログラムを書きづらいのが美点。
  • 個人的に色々不満はあるが、一番は連想配列が無いこと。
    • C++でいうstd::map, Pythonでいうdictみたいなやつ。
  • 仕事上Fortranを避けては通れないし、仕方がないので自分で書いた。

設計

実用的な連想配列の実装は大きく分けて二通り1、平衡二分木とハッシュテーブルが候補に挙がる。それぞれの特徴を比較するとこんな感じだ。

平衡二分木 ハッシュテーブル
概要 高さが要素数の対数程度になるような木を作る キーにハッシュ関数を適用したものをインデックスとして配列にアクセス
挿入、削除、探索 O(log N) やや速い O(1) 速い
k番目のキーにアクセス できる できない
留意点 単純な実装だとメモリ上非連続 キーが長い時はハッシュ関数が遅い2
その他 好き あまり好きじゃない3

私のユースケースでは順序でアクセスする必要は低そうだが、本能に従って実装は平衡二分木を採用した。

木の選定と実装

あまり実装が重い木は正しく実装する自信が無いので、秋葉大先生の資料に倣ってtreapを採用した。親子関係はheap、左右関係は二分探索木になっていて、ランダムに優先度を割り振ることで確率的に平衡が保たれる。

複数のキーや値の型を使いたい。最近のFortranはポリモーフィズムにも対応しているらしいが、実装が複雑になりそう4なのでプリプロセッサで対応した。

測定

  • マイクロベンチマークでは、要素数200以上で線形探索より速かった。
    • 大体std::mapと同程度。
    • 線形探索が案外速い。Treapは毎ノード挿入時にメモリ確保が必要なので、その辺が遅そう。
    • 趣味に走らずハッシュテーブルで実装したらもう少し速かったかもしれない、という後悔が残った。
    • (追記) 後日ハッシュテーブルで実装したら2-3倍速い。大体std::mapstd::unordered_mapの違いくらいだ。
      • fnv-1a (32bit)だと、ハッシュ計算が全体の約半分を占めるのでxxhashやmurmurのような速いハッシュで書いたらもっと速くなりそうだ。

補遺

連想配列を使える競プロの問題例


  1. Trieという決定木アルゴリズムもある、らしい。 

  2. 平衡二分木で必要な大小比較は文字列の最後まで検証しなくても結果が分かることが多い。1000文字以上になるとstd::unordered_mapよりstd::mapの方が速くなる(比較記事)。実際そんなに長いキーが必要になるユースケースは私には無さそうだが。 

  3. 余分に配列を確保しておいてハッシュが衝突したら盥回しというのがちょっとね。 

  4. 複数の組み込み型のスーパークラス的なものを自分で書いてそのインスタンスへのポインタを扱えば良い、という認識だが使ったことは無い。 

5
2
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
5
2