3

2セットのデータがあります。1 つは人で、もう 1 つはグループだとしましょう。人は複数のグループに属することができ、グループは複数の人を持つことができます。私の操作は、基本的にグループと人に対する CRUD です。人々のリストが異なるグループに属していることを確認する方法と同様に(これはよく呼び出されます)。

現在、水平方向にすべての人を表し、垂直方向にすべてのグループを表すバイナリ 0 と 1 のテーブルを作成することを考えています。

バイナリの各リストを追加し、バイナリのリストの「and」操作と比較することで、O(n) 時間でメソッドを実行できます。

例えば

Group   A    B    C    D
ppl1    1    0    0    1
ppl2    0    1    1    0
ppl3    0    0    1    0
ppl4    0    1    0    0

check (ppl1, ppl2) = (1001 + 0110) == (1001 & 0110)
               = 1111 == 1111
               = true

check (ppl2, ppl3) = (0110 + 0010) == (0110+0010)
               = 1000 ==0110
               = false

似たようなことをするデータ構造がすでにあるのではないかと思っているので、自分で書いて O(n) ランタイムを維持する必要はありません。

4

3 に答える 3

2

私はあなたの問題の詳細をすべて知っているわけではありませんが、私の本能は、あなたがここで物事を考えすぎている可能性があるということです. このデータ構造にいくつのオブジェクトを保存する予定ですか? ここに大量のデータを保存する場合は、データ構造ではなく実際のデータベースを使用することをお勧めします。ここで説明している操作の種類は、リレーショナル データベースが得意とする典型的な例です。MySQLPostgreSQLは、この種のことをスリープ状態で実行できる大規模なリレーショナル データベースの例です。より軽量なSQLiteが必要な場合は、おそらく興味深いでしょう。

このデータ構造に大量のデータを格納する必要がない場合は、シンプルなままにして、必要な処理を行うのに十分な速度が得られないことが確実な場合にのみ最適化することをお勧めします。最初のショットとして、Java のビルトイン List インターフェイスを使用してユーザーを格納し、Map を使用してグループを格納することをお勧めします。次のようなことができます。

// Use a list to keep track of People
List<Person> myPeople = new ArrayList<Person>();
Person steve = new Person("Steve");
myPeople.add(steve);
myPeople.add(new Person("Bob"));


// Use a Map to track Groups
Map<String, List<Person>> groups = new HashMap<String, List<Person>>();
groups.put("Everybody", myPeople);
groups.put("Developers", Arrays.asList(steve));

// Does a group contain everybody?
groups.get("Everybody").containsAll(myPeople); // returns true
groups.get("Developers").containsAll(myPeople); // returns false

これは間違いなく利用可能な最速のオプションではありませんが、追跡する膨大な数の People がなければ、おそらくパフォーマンスの問題に気付かないでしょう。通常のリストとマップを使用する速度が実現不可能になる特別な条件がある場合は、それらを投稿してください。それらに基づいて提案を行うことができます。

編集:

あなたのコメントを読んだ後、最初の実行であなたの問題を読み間違えたようです. グループを人にマッピングすることにはあまり関心がないようですが、代わりに人をグループにマッピングします。おそらく必要なのは、次のようなものです。

Map<Person, List<String>> associations = new HashMap<Person, List<String>>();

Person steve = new Person("Steve");
Person ed = new Person("Ed");

associations.put(steve, Arrays.asList("Everybody", "Developers"));
associations.put(ed, Arrays.asList("Everybody"));

// This is the tricky part
boolean sharesGroups = checkForSharedGroups(associations, Arrays.asList(steve, ed));

では、checkForSharedGroups メソッドをどのように実装するのでしょうか? あなたの場合、これを取り巻く数値はかなり低いので、単純な方法を試して、そこから始めます.

public boolean checkForSharedGroups(
                    Map<Person, List<String>> associations, 
                    List<Person> peopleToCheck){
    List<String> groupsThatHaveMembers = new ArrayList<String>();
    for(Person p : peopleToCheck){
        List<String> groups = associations.get(p);
        for(String s : groups){
            if(groupsThatHaveMembers.contains(s)){
                // We've already seen this group, so we can return
                return false;
            } else {
                groupsThatHaveMembers.add(s);
            }
        }
    }
    // If we've made it to this point, nobody shares any groups.
    return true;
}

この方法は、大規模なデータセットではおそらく優れたパフォーマンスを発揮しませんが、理解するのは非常に簡単です。独自のメソッドにカプセル化されているため、パフォーマンスの向上が必要になった場合の更新も簡単です。パフォーマンスを向上させる必要がある場合は、 Person の equals メソッドをオーバーライドすることを検討します。これにより、関連付けマップの検索が高速になります。そこから、オーバーライドされた equals メソッドを使用して、グループの String の代わりにカスタム タイプを確認することもできます。これにより、上記で使用した contains メソッドが大幅に高速化されます。

私がパフォーマンスについてあまり気にしていない理由は、アルゴリズムに関する限り、あなたが言及した数値が実際にはそれほど大きくないからです。このメソッドは、一致するグループが 2 つ見つかるとすぐに戻るため、最悪の場合、ArrayList.contains を存在するグループの数だけ呼び出すことになります。最良のシナリオでは、2 回呼び出すだけで済みます。checkForSharedGroups を非常に頻繁に呼び出す場合にのみパフォーマンスが問題になる可能性があります。

于 2013-06-24T19:00:13.907 に答える
0

HashTableを検討しましたか? 使用するすべてのキーがわかっている場合は、一定の時間を実現できる完全ハッシュ関数を使用できます。

于 2013-06-24T18:59:56.540 に答える
0

People と Group に 2 つの別個のエンティティを用意するのはどうでしょうか。Inside People には Group のセットがあり、その逆もあります。

class People{

Set<Group> groups;
//API for addGroup, getGroup

}

class Group{

Set<People> people;
//API for addPeople,getPeople

}

check(人物 p1, 人物 p2):

1) 両方の p1、p2 で getGroup を呼び出します
。2) 両方のセットのサイズを確認します
。3) 小さい方のセットを反復処理し、そのグループが (グループの) 他のセットに存在するかどうかを確認します。

これで、基本的に People オブジェクトを任意のデータ構造に格納できます。サイズが固定されていない場合は連結リスト、それ以外の場合は配列が望ましいです。

于 2013-06-24T19:04:51.080 に答える