• 締切済み

ハッシュについて教えて下さい

現在出来るだけ高速に大量の英単語の登録(検索)を行いたいと考えています。 現在は受け付ける文字の種類を進数にして桁上げして、クローズドで(最初にがっぽり配列を用意してその中のどこかに入れる形式で)計算しています。 例えば0~9の文字のみ受け付ける仕様だとすると、文字の種類は10種類なので、「192」という文字列なら、 1*10^2 + 9*10^1 + 2*10^0 = 192番地に登録 といった感じです。今回大小アルファベットを含むので10→62で計算しています。 しかしこの方法では、62進数が膨大な数になるため、配列に上限があることから、完全なユニークな数値が生成出来ません。 ある程度ハッシュ値がぶつかってしまいます。 完全にユニークな数値は無理でしょうが、出来るだけ衝突は避けたいと考えています。 そこで、もっと効率よいハッシュ値を求めるMurMurHash 2.0というアルゴリズムを聞いたのですが、HPを見ても何が何だかよくわかりません; HPにてMurmurHash2.cppが公開されているので、もしご存知の方がいらっしゃればそのアルゴリズムを教えていただけないでしょうか。 http://www.google.co.jp/search?hl=ja&rlz=1C1GGLS_jaJP302JP303&q=MurMurHash+2.0&btnG また、高速な文字列登録(検索)を行う為の方法があれば教えて下さい。 よろしくお願いいたします。

  • dixq
  • お礼率25% (69/268)

みんなの回答

  • prophetok
  • ベストアンサー率44% (13/29)
回答No.3

#2 unsigned int k = *(unsigned int *)data; と switch文内にbreak文がないことを見落としていました。 以下は嘘です。ちゃんと全バイトを評価しています。 すいません。 評価するデータは並び順に4バイト中1バイト ただし、4バイト中1バイトしか評価していないので、英単語では同じハッシュ値を返すケースが多くなることが予想されます。

  • prophetok
  • ベストアンサー率44% (13/29)
回答No.2

勉強のため実用性(実装の効率も含む)を度外視して、自分で作ってみるという理解でいいですか? もし、実用を考えているのであれば、既存のライブラリを利用することをおすすめします。 さて、ハッシュ値なのですが MurmurHash2.cppの unsigned int MurmurHash2 ( const void * key, int len, unsigned int seed ) の中身をみれば一目瞭然、評価するデータは並び順に4バイト中1バイト ・桁あふれを起こさせる ・評価するデータを下位ビットに反映させる を繰り返してハッシュ値を求めていますね。 ハッシュ値はある意味疑似乱数なので、こうすることで万遍なく値が散らばるんでしょうね。 演算に使っているm,rは // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well. の通り、試行錯誤で選んだものと思います。 ただし、4バイト中1バイトしか評価していないので、英単語では同じハッシュ値を返すケースが多くなることが予想されます。 素直に全バイトを評価する以下のようなハッシュ関数を使った方が無難かと思います。 unsigned int hash(char *s) { unsigned int h = 0; for (;*s != '\0'; s++) { h = h * 137 + *s; } return h % 1987; } 自分でハッシュ法を実装するとなると、コリジョン時の処理とか結構大変ですよ。少なくとも中級以上の知識と経験がないとかなり苦労すると思います。がんばってください。

  • prophetok
  • ベストアンサー率44% (13/29)
回答No.1

既存のライブラリ(STLやMFCのMAP)を使わない理由はあるのですか? 自前のコードでハッシュマップを作成する必然性がありますか?

dixq
質問者

お礼

ご回答ありがとうございます。 今回はピュアCのみで機能は一から作りたかったので、このように考えました。 また、ハッシュ値はどのように計算するのが一番効率的なのか?ということも同時に考えたかったのです・・。

関連するQ&A

  • パスワードのハッシュ化について

    ユーザー登録させるようなwebサイトを作ることになりました。 ググッたところパスワードはハッシュ化させDBへ、っていうのが通常らしいんで、 sha256を使って変換しようと思います。 質問(1)ハッシュ化させる元の文字列には文字数など何か制限はないんでしょうか。 質問(2)ハッシュ化させるときにくっつけるsaltは何桁くらいにするのが一般的なんでしょうか。 教えてください。

  • 結果を10進数表記するハッシュ計算ツール

    ブラウザ上で動作するMD5等のハッシュ計算ツールは色々ありますが、 題名の通り「計算したハッシュ値を16進数ではなく10進数表記してくれる計算ツール」をご存知ないでしょうか? 16進数表記のハッシュ値を出してから、何らかの方法で10進数表記に変換すれば良い話なのですが その手間を省き、一度の変換で文字列から10進数の数値にできれば便利だなぁと思っております。 ブラウザ上で動作するものであればベストですが、別にそうでなくても構いません。 ただ、できればフリーウェアに限らせてください。 よろしくお願いします。

  • 文字列をハッシュにしなければならないのですが

    C言語にさ ファイルの中にある、3バイトunicodeの漢字文字列郡をハッシュテーブルに格納してハッシュを作りたいんですが、取っ掛かりすらつかない状況です。 とりあえず、配列から3バイトの16進数にして、後はその文字列分の16進数を足して、それを割ってキーをつくりテーブルにいれる、としようとしています。 配列から3バイトの16進数にする int joint(char a, char b, char c){ int join = 0; join = a<<8; join = (0x0000FF00 & join) + (0x000000FF & b); join = join<<8; join = (0x00FFFF00 & join) + (0x000000FF & c); return join; } このように16進数にするのですが、最初の取っ掛かりとしてのハッシュについては、どうやったらハッシュテーブルに格納でくるのかいまいちわからないのです。誰かわかりやすく教えてください。

  • 数値・文字列を決まった範囲の数値に変換・割り当てる(ハッシュする?)方

    数値・文字列を決まった範囲の数値に変換・割り当てる(ハッシュする?)方法について ハッシュ関数を使えば、ある文字列・数値を何らかの法則で暗号のように変換できることは分かったのですが、その変換される結果の範囲を決まった数値として指定することは可能なのでしょうか。 例えば『文字列を「1~95」の数値のどれかに割り当てたい』という感じです。 ランダムでなく、何度やっても同じ結果にしたいのです。 また、範囲は例では「1~95」としていますが、「1~230」「1~500」など自由に変更したいと思っています。 ※以前質問した占いに関連するものでして、結果の数が定まっていないため、 結果の数に応じて、元となるデータから占い結果に割り当てるということをやりたいと思っています。 ご教示いただけますようお願いします。

    • ベストアンサー
    • PHP
  • Perlでハッシュや配列で重複するキーについて

    ハッシュで重複するキーが値となるので、このハッシュはabdの3つのキーしか存在しないということでしょうか? %a = ('a'=>1, 'b'=>2, 'a'=>3, 'd'=>4); また、配列の場合はabadと4つ数になるということでしょうか? @a = ('a','b','a','d'); この場合配列で、重複する値を抽出するアルゴリズムが知りたいです。

    • ベストアンサー
    • Perl
  • ハッシュ法でのデータ管理について教えてください

    ハッシュ法でのデータ管理をするプログラムを作りたいんですが長いことPASCALに触ってなかったせいか全く分かりません。 どなたか教えていただけないでしょうか??問題の概要は以下のようなものです。 表に登録するデータについては、キーは英数字からなる長さ8までの文字列でデータ本体は整数(型名はintegerでよい)です。 ハッシュ表のサイズは11とします。 ハッシュ関数は文字列xの各文字のASCIIコードの総和を11で割った余りとします。 さらにメニュー表示として入力した文字により行う操作を決定します。 どの文字がどのような操作を行うのかは以下のとおりです。 's' の場合: ハッシュ表に登録されている全レコードを,ハッシュ関数値毎に(キーの値とデータの両方を)すべて表示します. 'r' の場合: さらに「キーの値」と「データ」を入力し,すでに同じキーをもつデータがあれば「二重登録」として検出し,そうでなければ,そのレコードをハッシュ表に登録します. 'e' の場合: さらに「キーの値」を入力し,そのキーをもつデータがハッシュ表に登録されているならば, そのデータを表示します.さらに削除するかどうかを入力させて,削除する選択をした場合にはそのレ コードを削除します.そのキーをもつデータがハッシュ表にない場合には「そのキーをもつレコードが ないこと」を出力しますが,ハッシュ表には操作を加えません. 'i' の場合: ハッシュ表に登録されている全レコードを,キーの値が小さい順に表示します.ここで「キー の値の順」とは,文字列の辞書順のことを意味します.Pascal では,文字列a,b に対して,a がb より 辞書的順序が先(小さい) ときには「a<b」で表現できます. 'd' の場合: 「'i' の場合」の逆で,キーの値が大きい順に表示します. 'q' の場合: プログラムを終了します.具体的には,実行文部の最後の「end.」の直前までジャンプし ます. 長くなってすいません。ちょっとしたヒントでもいいので教えていただければ幸いです。

  • ハッシュ関数

    ハッシュ関数について悩んでいます. ハッシュ関数の例として以下Wikiの引用です http://ja.wikipedia.org/wiki/%E3%83%8F%E3%83%83%E3%82%B7%E3%83%A5%E9%96%A2%E6%95%B0 unsigned int hash(char *s) { unsigned int h = 0; for (;*s != '\0'; s++) { h = h * 137 + *s; } return h % 1987; } このハッシュ関数において, 「hの更新計算で用いる137という数は、2(7乗)+2(3乗)+2(0乗) というものであり、乗法した後にも2進数表現の下位の桁にも 情報が残るようになっている。そのため前の方の文字の情報が 桁あふれによって失われることはない。」 と記述されているのですが,私が考えてしまうのは以下の通りです. 「最終的にハッシュ値は合計を1987で割った余りになるのだから, 下位の桁(1~1987)に情報を残さなければならない. それぞれのsの上位から下位までの情報を合計の数値の下位に 残すのであれば,137は掛けるのではなく割るべき.」 もちろん私の考え方が間違っているのはわかりますが, なぜ137を掛けるのかを理解できません. どなたかわかりやすくご教授いただけたら幸いです.

  • c言語でハッシュを作るらしいのですが...

    c言語でハッシュを作るんですが、勉強不足のためいまいち理解が追いついていないのが現状です。昔の字体を、今の字体に変換するために下記の記述のあるファイル読み込むんですが、この2,3列目が昔の字体で、この文字があったら1列目の今の字体へのポインタを返すように配列に入れたいんです。誰かやり方をおしえてくれませんか?、 没,沒,歿 壱,壹,弌 奇,竒,綺 協,恊,叶

  • ハッシュテーブルを使って効率の良い文字の置換がしたい場合

    はじめまして。 実はいまハッシュテーブルを利用して複数の外字をそれぞれ対応する文字に変換するJavaのプログラムを考えています。 ただ、その方針までは決まったのですが、実装方法で躓いています。 今のところ、文字列をIndexOfで探して、ある外字がでてきたらハッシュテーブルを見にいってその外字に対応する文字に変換し、また続けてその文字を探していくという方式しか考え付いてないのですが、この方法だと外字一種類ごとに文字列を検索することになってしまい、不幸率のような気がしてきました。なにか他にもっといい方法はあるでしょうか?

    • ベストアンサー
    • Java
  • 初心者なんですが、モジュールが良くわからなくて,,,

    c言語で文字列のハッシュモジュールを作ることになったんですが、そもそもモジュールの知識がほぼないのでどう書けばいいか、よくわかりません。 例えば、文字列の配列が渡されてハッシュを作るのですが、そもそもそこらへんの渡し方をどのように書けばいいのかもわかりません。誰かわかりやすく教えてください。

専門家に質問してみよう