为什么我要使用 HashSet 而不是 Dictionary?

Why would I use a HashSet over a Dictionary?

我正在尝试在 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
                });

注意:class CachedPath 的 GetHashCode 和 Equals 仅被 From、To 和 Actor 覆盖,因此具有这些相同属性的两个实例具有相同的散列和相等性。

鉴于 'HashSet' 中的快速查找(包含)、插入和删除是 O(1)(如果我没记错的话),我考虑使用 'HashSet' 来执行这些操作.唯一的问题是 FirstOrDefault,我必须枚举整个集合才能得到它。

考虑到这个问题,我考虑过使用由 From、To 和 Actor 的散列索引的字典:

Dictionary<int, CachedPath> cachedPath

再说一次,如果我没记错的话,Dictionary 还提供 O(1) 的插入、删除和 Key 检索。这让我想到 Dictionary 是一个 HashSet + O(1) 元素检索能力。

我错过了什么吗?在支持更多操作的意义上,Dictionary 真的比 HashSet 更好吗?

提前致谢。

哈希集在执行添加时不会抛出异常。相反,它 returns 一个反映添加成功的布尔值。

此外,哈希集不需要键值对。 我使用哈希集来保证唯一值的集合。

Dictionary 并不比 HashSet 好,只是不同而已。

  • 当你想存储一个无序的项目集合时,你使用 HashSet
  • 当您想要将一组名为 "keys" 的项目与另一组名为 "values"
  • 的项目相关联时,您可以使用 Dictionary

人们可以将 HashSet 视为没有关联值的 Dictionary(事实上,HashSet 有时在幕后使用 Dictionary 来实现)但是没有必要这样想:把两者想成完全不同的东西也行。

在你的情况下,你可以通过按演员制作字典来潜在地提高性能,如下所示:

Dictionary<ActorType,List<CachedPath>> _cachedPathsByActor

这样你的线性搜索会根据演员快速选择子列表,然后按目标线性搜索:

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

或者通过制作一个考虑所有三个项目的相等比较器,并使用 DictionaryCachedPath 作为键和值,并将自定义 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)) {
    ...
}

但是,这种方法假设字典中最多只有一个项目具有相同的 FromToActor