凪瀬 Blog
Programming SHOT BAR

目次

Blog 利用状況
  • 投稿数 - 260
  • 記事 - 0
  • コメント - 48909
  • トラックバック - 192
ニュース
広告
  • Java開発者募集中
  • 経歴不問
  • 腕に自信のある方
  • 富山市内
  • (株)凪瀬アーキテクツ
アクセサリ
  • あわせて読みたい
凪瀬悠輝(なぎせ ゆうき)
  • Java技術者
  • お茶好き。カクテル好き。
  • 所属は(株)凪瀬アーキテクツ
  • Twitter:@nagise

書庫

日記カテゴリ

 

前回の続きです。 このシリーズ、ソースを見るのが面倒なのか、 難易度が高そうに見えるのか、いまひとつ利便性が見えないからか、非常にアクセス数が少ないです。
しかし、2次元のMapで集計処理をやろうなどという奇特な人が検索で引っ掛けてきた場合を思うと書かずにはいられません。

リハッシュ

ハッシュテーブルは内部の配列サイズに対して格納データが多くなると、同じインデックスに格納されるデータが増えます。 そうなると単方向リストを辿ることになりますから目的のデータへの到達にコストがかかるようになります。

そのため、用意した配列に対しある割合を超えるデータ数が格納された際に、内部の配列を大きくしてやり、 データを移してやる処理を行います。これをリハッシュ(rehash)といいます。なんだか蛇の脱皮のようですね。

Javaの標準APIの場合、HashMapを デフォルトコンストラクタで インスタンスを生成すると内部の配列サイズが16、負荷係数0.75で初期化されます。

これは、16の配列サイズに対し0.75を超えるデータが格納されたとき、つまり12個を超える場合にリハッシュされることを意味します。 リハッシュ処理は非常に重たい処理であるため、最初から格納するデータ数が分かっている場合は、 サイズを指定して初期化することが望ましいのです。

    /**
     * リハッシュ処理。
     * 配列サイズを1.5倍に拡大
     */
    private void rehash() {
        int xSize = (int) (this.map.length * EXT_RATE + 1);
        int ySize = (int) (this.map[0].length * EXT_RATE + 1);
        TableEntry<KX, KY, V>[][] newMap = createTableEntryArray(xSize, ySize);

        for (TableEntry[] entrys : this.map) {
            for (TableEntry<KX, KY, V> entry : entrys) {
                if (entry == null) {
                    continue;
                }
                this.putImpl(newMap, entry.getKeyX(), entry.getKeyY(), entry.getValue());

                TableEntry<KX, KY, V> nextEntry = entry.getNext();
                while (nextEntry != null) {
                    this.putImpl(newMap, nextEntry.getKeyX(),
                            nextEntry.getKeyY(), nextEntry.getValue());
                    nextEntry = nextEntry.getNext();
                }
            }
        }

        this.map = newMap;
    }

このHashTableMapではリハッシュ処理で内部の配列を1.5倍に拡大します。1.5倍といっても縦横のサイズを1.5倍ずつにするので面積的には2.25ですね。 そして格納されているデータをループで回して格納位置を再設定しなおすというわけです。

いかがだったでしょうか。
「データ構造とアルゴリズム」と言われるようにデータ構造はアルゴリズムとともに車輪の両輪となるものです。 データ構造はアルゴリズムと比べると鑑みられることが少ないのが寂しいところですが、 基礎知識として興味を持ってもらいたいものです。

投稿日時 : 2007年9月27日 19:29
コメント
  • # re: データ構造を考える - 2次元のMap その4
    さかもと
    Posted @ 2007/09/27 20:48
    >難易度が高そうに見えるのか、いまひとつ利便性が見えないからか

    ちっ!違いますっ!
    ちゃんと読んでます!!!


    わかんないけど・・・。


  • # re: データ構造を考える - 2次元のMap その4
    凪瀬
    Posted @ 2007/09/28 8:57
    このシリーズ、アクセス数が各エントリで50以下なんですね。2007/09/28時点。

    エントリのタイトルと概要から「開かない」という選択をされている方が多いことが伺えます。
    エントリのターゲット層が狭いのは仕方ないのですが、
    やはり書きたいことが書きたいのが人情というもので…。
  • # re: データ構造を考える - 2次元のMap その4
    IIJIMAS
    Posted @ 2007/09/28 12:46
    すごく興味あるんですが、余裕が(時間的にも、心にも)ないので…

    内容読むだけなら、アップ時にブログのトップページから見れるので、そこから読んでる場合は開かないのではないでしょうか。
  • # re: データ構造を考える - 2次元のMap その4
    凪瀬
    Posted @ 2007/09/28 13:44
    > 余裕が(時間的にも、心にも)ないので…

    よくわかりますw
    わたしもかつのりさんのblogとか、コード書いて検証しつつ読みたいようなエントリとかあって、時間なくて反応できずにいるのがいくつもある…。

    コメントのつきにくい話題のエントリはblogのトップで読んでそれっきりという人も多いのではないでしょうかね。
  • # re: データ構造を考える - 2次元のMap その4
    States
    Posted @ 2007/10/07 15:39
    面白いと思うんですが、少しインターフェイスが冗長のような気がします。
    テーブルをマップのマップのように捕らえ、xView()やyView()のようなメソッドでイテレータやサブリストのような内部クラスのビューを返してやれば、
    XやY方向についてのメソッドをいちいち定義しなくてもよくなるかと思います。

    で、実際にやってみようと思ったら内部クラス地獄に陥って訳がわかんなくなっちゃいました^^;
  • # re: データ構造を考える - 2次元のMap その4
    凪瀬
    Posted @ 2007/10/08 13:59
    貴重な意見をありがとうございます。

    このネタは独自のものなのでインターフェースなども自分がえいやっで作ってしまっていますからあまり洗練されていないのは確かです。

    X方向とY方向でメソッド定義が冗長な感じになってしまうのが嫌なのですが、引数でXかYを示すenumを渡すなどの作りでは、型安全な形で定義できないのですよね。

    どうしてもreturnする型が階層構造を持つデータ型になってしまうので、内部クラス地獄ですw

    「ジェネリクスと内部クラス」シリーズのエントリがあるのですが
    http://blogs.wankuma.com/nagise/archive/2007/08/10/89866.aspx
    こういうところに生きているんですね
タイトル
名前
Url
コメント