web-dev-qa-db-ja.com

ハッシュマップとアレイのパフォーマンス

配列のインデックスがわかっている場合は、配列またはHashMapを使用する方が(パフォーマンス面で)良いですか?例の「オブジェクト配列/マップ」は単なる例であり、実際のプロジェクトでは別のクラスによって生成されるため、個々の変数を使用できないことに注意してください。

ArrayExample:

SomeObject[] objects = new SomeObject[2];
objects[0] = new SomeObject("Obj1");
objects[1] = new SomeObject("Obj2");

void doSomethingToObject(String Identifier){
    SomeObject object;
    if(Identifier.equals("Obj1")){
        object=objects[0];
    }else if(){
        object=objects[1];
    }
    //do stuff
}

HashMapExample:

HashMap objects = HashMap();
objects.put("Obj1",new SomeObject());
objects.put("Obj2",new SomeObject());

void doSomethingToObject(String Identifier){
    SomeObject object = (SomeObject) objects.get(Identifier);
    //do stuff
}

HashMapの方がはるかに良く見えますが、これを優先するため、私は本当にこれに対するパフォーマンスが必要です。

編集:そうですね、それはアレイです。提案はまだ歓迎されています

編集:言及するのを忘れていました。Array/ HashMapのサイズは常に同じです(6)

編集: HashMapの方が速いようです配列:128msハッシュ:103ms

使用するサイクルが少ない場合、HashMapは2倍の速さでした

テストコード:

import Java.util.HashMap;
import Java.util.Random;

public class Optimizationsest {
private static Random r = new Random();

private static HashMap<String,SomeObject> hm = new HashMap<String,SomeObject>();
private static SomeObject[] o = new SomeObject[6];

private static String[] Indentifiers = {"Obj1","Obj2","Obj3","Obj4","Obj5","Obj6"};

private static int t = 1000000;

public static void main(String[] args){
    CreateHash();
    CreateArray();
    long loopTime = ProcessArray();
    long hashTime = ProcessHash();
    System.out.println("Array: " + loopTime + "ms");
    System.out.println("Hash: " + hashTime + "ms");
}

public static void CreateHash(){
    for(int i=0; i <= 5; i++){
        hm.put("Obj"+(i+1), new SomeObject());
    }
}

public static void CreateArray(){
    for(int i=0; i <= 5; i++){
        o[i]=new SomeObject();
    }
}

public static long ProcessArray(){
    StopWatch sw = new StopWatch();
    sw.start();
    for(int i = 1;i<=t;i++){
        checkArray(Indentifiers[r.nextInt(6)]);
    }
    sw.stop();
    return sw.getElapsedTime();
}



private static void checkArray(String Identifier) {
    SomeObject object;
    if(Identifier.equals("Obj1")){
        object=o[0];
    }else if(Identifier.equals("Obj2")){
        object=o[1];
    }else if(Identifier.equals("Obj3")){
        object=o[2];
    }else if(Identifier.equals("Obj4")){
        object=o[3];
    }else if(Identifier.equals("Obj5")){
        object=o[4];
    }else if(Identifier.equals("Obj6")){
        object=o[5];
    }else{
        object = new SomeObject();
    }
    object.kill();
}

public static long ProcessHash(){
    StopWatch sw = new StopWatch();
    sw.start();
    for(int i = 1;i<=t;i++){
        checkHash(Indentifiers[r.nextInt(6)]);
    }
    sw.stop();
    return sw.getElapsedTime();
}

private static void checkHash(String Identifier) {
    SomeObject object = (SomeObject) hm.get(Identifier);
    object.kill();
}

}

23
Timotheus

HashMapは下の配列を使用するため、配列を正しく使用するよりも速くなることはありません。

Random.nextInt()は、arrayを使用して配列をテストしても結果にバイアスがかかる場合でも、テストしているものより何倍も遅くなります。

配列のベンチマークが非常に遅い理由は、配列へのアクセス自体ではなく、等しい比較によるものです。

HashTableは通常、HashMapよりもはるかに低速ですが、これは同じことを実行しますが、同期も行われるためです。

マイクロベンチマークの一般的な問題は、何もしないコードの削除に非常に優れているJITです。注意しないと、コードが何も実行しないようにJITを十分に混乱させたかどうかをテストすることになります。

これが、C++システムを実行するマイクロベンチマークを記述できる理由の1つです。これは、Javaがより単純な言語であり、推論しやすく、したがって何も役に立たないコードを検出するためです。これは、Javaが「何も役に立たない」はC++よりもはるかに高速です;)

32
Peter Lawrey

インデックスがわかっている場合の配列はより高速です(HashMapは、背後でリンクリストの配列を使用します。これにより、実行する必要があるハッシュ操作は言うまでもなく、配列アクセスよりもオーバーヘッドが少し増えます)

そしてFYI HashMap<String,SomeObject> objects = HashMap<String,SomeObject>();はそれを作るので、キャストする必要はありません

4
ratchet freak

示されている例では、HashTableが勝つと思います。配列アプローチの問題は、スケーリングしないことです。テーブルに3つ以上のエントリが必要で、doSomethingToObjectの条件分岐ツリーが手に負えなくなって遅くなると思います。

2
sehe

論理的には、HashMapは間違いなくあなたのケースに適しています。配列の場合は(アルゴリズムで)文字列の比較を何回か行う必要があるため、パフォーマンスの観点からもメリットがありますが、HashMapでは、負荷係数が高すぎない場合はハッシュコードを使用するだけです。多くの要素を追加する場合は、配列とHashMapの両方のサイズを変更する必要がありますが、HashMapの場合は、要素も再配布する必要があります。この使用例では、HashMapが失われます。

2
Alex Gitelman

決して、決して、if if/else if/else if/else if/else if/else if/else if else if that else if。何度も繰り返したのは、Javaインタプリタがそのようなコードブロックにヒットしたときに行うように感じさせるためです。

他に複数ある場合は、ハッシュマップまたはスイッチ/ケースのいずれかを使用します(Java 7では文字列でそれを実行でき、Java 6列挙型を使用する必要があります)読み取り専用チェックのさらに優れたソリューションは、guavaなどのフレームワークからのImmutableMapです。書き込みを許可していないため、読み取りは高度に最適化されています。

0
Ajax

配列は通常、コレクションクラスよりも高速です。

PS。投稿でHashTableについて言及しました。 HashTableはHashMapよりもパフォーマンスがさらに悪い。 HashTableについてのあなたの言及はタイプミスだったと思います

「HashTableの方がはるかによく見えます」

0
Basanth Roy

例は奇妙です。重要な問題は、データが動的かどうかです。もしそうなら、そのようにプログラムを書くことはできません(配列の場合のように)。つまり、配列とハッシュ実装の比較は公平ではありません。ハッシュ実装は動的データに対して機能しますが、配列実装は機能しません。

静的データ(6つの固定オブジェクト)しかない場合、配列またはハッシュはデータホルダーとして機能します。静的オブジェクトを定義することもできます。

0
BlueGuitar