/****************************/ /* ハッシュ法 */ /* coded by Y.Suganuma */ /****************************/ import java.io.*; import java.util.*; /*****************************************/ /* クラス List(衝突リスト,二分探索木) */ /*****************************************/ class List { String st; List left, right; // コンストラクタ List () { } List (String s) { st = new String(s); } /***************************************/ /* データの追加 */ /* dt : Listクラスのオブジェクト */ /* return : =1 : 追加 */ /* =0 : 同じデータが存在 */ /***************************************/ int add(List dt) { List lt = this; int k, sw = -1; // トップ if (lt.st == null) { lt.st = dt.st; sw = 1; } // トップでない else { while (sw < 0) { k = (dt.st).compareTo(lt.st); // 同じデータがある if (k == 0) sw = 0; // 大きい else if (k > 0) { if (lt.right == null) { lt.right = dt; sw = 1; } else lt = lt.right; } // 小さい else { if (lt.left == null) { lt.left = dt; sw = 1; } else lt = lt.left; } } } return sw; } /***************************************/ /* データの削除 */ /* st : 文字列 */ /* return : =1 : 削除した */ /* =0 : 削除できなかった */ /***************************************/ int del(String st) { List lt, lt1 = this, lt2 = this, dt; int k, rl = 0, sw = 0; if (lt2.st != null) { while (sw == 0 && lt2 != null) { k = st.compareTo(lt2.st); // 削除 if (k == 0) { sw = 1; if (lt2.right == null) { // 子供無し if (lt2.left == null) { if (rl == 0) lt2.st = null; else { if (rl > 0) lt1.right = null; else lt1.left = null; } } // 右無し else { if (rl == 0) { lt2.st = (lt2.left).st; lt2.right = (lt2.left).right; lt2.left = (lt2.left).left; } else { if (rl > 0) lt1.right = lt2.left; else lt1.left = lt2.left; } } } else { // 左無し if (lt2.left == null) { if (rl == 0) { lt2.st = (lt2.right).st; lt2.left = (lt2.right).left; lt2.right = (lt2.right).right; } else { if (rl > 0) lt1.right = lt2.right; else lt1.left = lt2.right; } } // 左右あり else { dt = lt2.left; if (rl == 0) { lt = lt2.right; lt2.st = lt.st; lt2.right = lt.right; lt2.left = lt.left; } else { if (rl > 0) lt1.right = lt2.right; else lt1.left = lt2.right; } lt1.add(dt); } } } // 次のデータ else { lt1 = lt2; if (k > 0) { lt2 = lt2.right; rl = 1; } else { lt2 = lt2.left; rl = -1; } } } } return sw; } /***********************************/ /* データの探索 */ /* st : 文字列 */ /* return : =1 : 見つかった */ /* =0 : 見つからない */ /***********************************/ int search(String st) { List lt = this; int k, sw = 0; if (lt.st != null) { while (sw == 0 && lt != null) { k = st.compareTo(lt.st); // 見つかった if (k == 0) sw = 1; // 次のデータ else if (k > 0) lt = lt.right; else lt = lt.left; } } return sw; } } /***********************************/ /* クラス Hash(ハッシュテーブル) */ /***********************************/ class Hash { private int size; // ハッシュテーブルの大きさ private List table[]; // 衝突リスト // ハッシュ関数 // s : 文字列 int hash(String s) throws UnsupportedEncodingException { int hash = 0, g; int i1, len; byte bs[] = s.getBytes("ASCII"); len = bs.length; for (i1 = 0; i1 < len; i1++ ) { hash = (hash << 4) + bs[i1]; // 左に4ビットシフトし文字を加える g = hash & 0xf0000000; // ビット毎のAND if (g != 0) { hash ^= g >> 24; // 排他的論理和 hash ^= g; } } hash = hash & 0x7fffffff; return hash % size; } // コンストラクタ Hash(int sz) { int i1; size = sz; table = new List [size]; for (i1 = 0; i1 < size; i1++) table[i1] = new List(); } // データの追加 // str : データ(文字列) // return : =1 : 追加 // =0 : 同じデータが存在 int add(String str) throws UnsupportedEncodingException { List lt = new List(str); return table[hash(str)].add(lt); } // データの削除 // str : データ(文字列) // return : =1 : 削除した // =0 : 削除できなかった int del(String str) throws UnsupportedEncodingException { return table[hash(str)].del(str); } // データの探索 // str : データ(文字列) // return : =1 : 見つかった // =0 : 見つからない int search(String str) throws UnsupportedEncodingException { return table[hash(str)].search(str); } } /****************/ /* main program */ /****************/ public class Test { public static void main (String[] args) throws IOException { int i1, k, n = 0, ct = 0, sw; String st, s[] = new String [100000]; Hash H = new Hash (3000000); long tm1, tm2, tm3; Random rn = new Random((long)12345); System.out.printf("ハッシュ法\n"); tm1 = System.currentTimeMillis(); while (ct < 2000000) { k = rn.nextInt(); st = Integer.toString(k); sw = H.add(st); if (sw > 0) { ct++; if (n < 100000) { s[n] = st; n++; } } } tm2 = System.currentTimeMillis(); System.out.printf(" 保存: %d ms\n", tm2-tm1); for (i1 = 0; i1 < n; i1++) H.search(s[i1]); tm3 = System.currentTimeMillis(); System.out.printf(" 探索: %d ms\n", tm3-tm2); System.out.printf(" データ数: %d\n", ct); } }
ハッシュ法 保存: 1963 ms 探索: 42 ms データ数: 2000000