web-dev-qa-db-ja.com

辞書ではなくHashSetを使用するのはなぜですか?

キャッシュされたパスのリストをA *アルゴリズムに実装しようとしています。現在、キャッシュされたパスは次のようなリストに保存されています。

readonly List<CachedPath> _cachedPaths = new List<CachedPath>();

このリストに対して実行される操作は次のとおりです。

FirstOrDefaultは、特定の条件を満たす要素を取得します

var cached = _cachedPaths.FirstOrDefault(p => p.From == from && p.To == target && p.Actor == self);

削除して要素

_cachedPaths.Remove(cached);

追加

_cachedPaths.Add(new CachedPath {
                    From = from,
                    To = target,
                    Actor = self,
                    Result = pb,
                    Tick = _world.WorldTick
                });

注:クラスCachedPathのGetHashCodeとEqualsは、From、To、およびActorによってのみオーバーライドされるため、これらの同じ属性を持つ2つのインスタンスは、同じハッシュと同等性を持ちます。

'HashSet'でのクイックルックアップ(含む)、挿入、および削除がO(1)(私が間違っていない場合))であることを考えると、これらの操作を行うために 'HashSet'を使用することを検討しました。唯一の問題はFirstOrDefaultです。これを取得するには、コレクション全体を列挙する必要がありました。

この問題を考慮して、From、To、およびActorのハッシュでインデックス付けされた辞書の使用も検討しました。

Dictionary<int, CachedPath> cachedPath

繰り返しますが、私が間違っていない場合、DictionaryはO(1)の挿入、削除、およびKeyによる取得も提供します。これにより、DictionaryはHashSet + = O(1)要素検索機能。

私は何かが足りないのですか?より多くの操作をサポートするという意味で、DictionaryはHashSetよりも優れていますか?

前もって感謝します。

DictionaryHashSetよりも優れているのではなく、ただ違うだけです。

  • アイテムの順序付けられていないコレクションを保存する場合は、HashSetを使用します。
  • 「キー」と呼ばれるアイテムのセットを「値」と呼ばれるアイテムの別のコレクションに関連付ける場合は、Dictionaryを使用します

HashSetは値が関連付けられていないDictionaryと考えることができます(実際、HashSetは舞台裏でDictionaryを使用して実装されることがあります)が、このように考える必要はありません。2つをまったく異なるものとして考えることもうまくいきます。

あなたの場合、次のようにアクターごとに辞書を作成することで、パフォーマンスを向上させることができる可能性があります。

Dictionary<ActorType,List<CachedPath>> _cachedPathsByActor

このようにして、線形検索はアクターに基づいてサブリストをすばやく選択し、ターゲットごとに線形検索します。

var cached = _cachedPathsByActor[self].FirstOrDefault(p => p.From == from && p.To == target);

または、3つの項目すべてを考慮する等価比較子を作成し、キーと値の両方としてDictionaryを使用してCachedPathを使用し、そのカスタム IEqualityComparer<T> キー比較者として:

class CachedPathEqualityComparer : IEqualityComparer<CachedPath> {
    public bool Equals(CachedPath a, CachedPath b) {
        return a.Actor == b.Actor
            && a.From == b.From
            && a.To == b.To;
    }
    public int GetHashCode(CachedPath p) {
        return 31*31*p.Actor.GetHashCode()+31*p.From.GetHashCode()+p.To.GetHashCode();
    }
}
...
var _cachedPaths = new Dictionary<CachedPath,CachedPath>(new CachedPathEqualityComparer());
...
CachedPath cached;
if (_cachedPaths.TryGetValue(self, out cached)) {
    ...
}

ただし、このアプローチでは、辞書にFromTo、およびActorが同一のアイテムが最大で1つあることを前提としています。

17
dasblinkenlight

ハッシュセットは、追加を実行するときに例外をスローしません。代わりに、追加の成功を反映するブール値を返します。

また、ハッシュセットはkeyValueペアを必要としません。ハッシュセットを使用して、一意の値のコレクションを保証します。

10
Scott Nimrod