Performance 有没有办法对集合类型进行概率常数时间相等检查? 问题
我想知道如何对两种集合类型(列表、集合、映射等)进行有效比较。应该注意的是,期望的是结构平等,而不是基于引用的平等 通常,必须遍历集合的所有元素,并在它们之间运行比较,每次比较的成本为O(1),从而产生惊人的O(n)比较时间 这可能会影响使用冲突检查相当昂贵的列表哈希表或使用契约设计(例如,比较旧集合和新集合) 当前解决方案的方向 我想了很多方法来确定快速解决方案,但它们似乎都是概率/非确定性的。其思想是,如果一个人能够对所有可以存储和比较的元素使用某种唯一的散列。一个好的散列算法应该提供足够的焓值,这样碰撞的可能性很小 这种基于散列的比较技术可以通过使用某种列表头的固定时间比较(比如比较前10个元素)来加强。两个在开始时具有相同元素并使用良好哈希算法的列表在理论上应该提供某种程度的唯一比较 问题 是否有可能创建一种恒定时间比较(对某些类似时间的整数进行广义和专用比较),并且可以通过独特的哈希技术实现 更新Performance 有没有办法对集合类型进行概率常数时间相等检查? 问题,performance,algorithm,Performance,Algorithm,我想知道如何对两种集合类型(列表、集合、映射等)进行有效比较。应该注意的是,期望的是结构平等,而不是基于引用的平等 通常,必须遍历集合的所有元素,并在它们之间运行比较,每次比较的成本为O(1),从而产生惊人的O(n)比较时间 这可能会影响使用冲突检查相当昂贵的列表哈希表或使用契约设计(例如,比较旧集合和新集合) 当前解决方案的方向 我想了很多方法来确定快速解决方案,但它们似乎都是概率/非确定性的。其思想是,如果一个人能够对所有可以存储和比较的元素使用某种唯一的散列。一个好的散列算法应该提供足够的
为了澄清这个问题,我不需要一个完美的平等性检查,而是需要一个快速的“平等前”检查,作为一种加速事后真正平等性检查的方法。虽然许多哈希代码实现对集合比较有用,但我也对列表(有序)比较感兴趣。使用基于哈希的比较 散列(SetA)与散列(SetB) PS:在计算散列之前,需要对集合中的元素进行排序(或任何其他确定性排序)。散列可能匹配,但集合可能不匹配(由于散列冲突),但发生这种情况的可能性很低 PS:PS:我假设集合是静态的(或者几乎是静态的)。在这种情况下,您可以在创建集合本身的过程中预计算哈希。所以每次比较都是O(1)。否则,正如Groo提到的,使用基于XOR的哈希,这是非常有效的
后续:利用信息论可以证明,如果X和Y都可以取2^n的唯一值,则至少需要进行O(n)比较。这是绕不开的。散列所提供的是高效比较的能力 如果使用安全散列函数,则发生冲突的可能性非常小(如果使用最新的散列函数,则在发现冲突时可以撰写论文:-) 如果您的集合实现为一棵树,那么您可以维护一个从叶子到根的哈希计算,代价是一个常数因子乘以您必须执行的树更新的代价。不幸的是,计算安全散列的常量可能相当大。不幸的是,需要两个具有相同对象的集合才能具有相同的树结构。这适用于但不适用于典型的平衡树,因为历史或更新会影响树结构
完美散列函数通常被调优为适合于特定集合,这在您的情况下可能不起作用。如果散列函数映射到数字1..N,那么给定N+1个对象,将始终至少存在一次冲突。否,这在理论上是不可能的。:如果散列值为32位,则只能区分2^32个变体,但列表可以任意增长。使用相同的参数,在运行时可以用于此任务[用于集合]。每套装置还将连接一个布卢姆过滤器 如果两个过滤器相同-结构可能相同 如果两个过滤器不相同,则结构彼此肯定不同 正面:
没有假阴性。如果过滤器不同-结构也不同 反面:
你可能有误报。您需要进行额外的检查[完全遍历],以确保两个结构确实相同 请注意,误报率是布卢姆过滤器大小的函数-它越大-误报越少 另请注意:由于bloom筛选器实际上是位集,因此比较两个bloom筛选器可以非常有效地实现。这里是关于此主题的非常有用(详细)的讨论,包括几种集合类型的参考实现 一般来说,计算置换是一种二次运算。然而, 给定两个无序容器,它们使用相同的散列和 键等价函数,元素将被划分为 使比较更加有效的关键等价组
我花了几分钟时间用C#编写了这样一个集合类,来源如下。我使用了generic
System.Collections.ObjectModel.Collection
,因为它很容易覆盖其功能
我还没有测试过,但这应该是一个坚实的开端。请注意,UpdateHash
将索引考虑在内(使哈希函数稍微好一点),而模拟的HashedSet
将跳过这一部分
此外,由于异或运算符的可逆性,在添加/删除时重新计算散列需要O(1)
复杂性。如果需要更好的散列,这些操作将增长到O(n)
,因此我建议进行分析,然后决定什么是最好的
public class HashedList<T> : Collection<T>, IEquatable<HashedList<T>>
{
private int _hash;
private void UpdateHash(int index, T item)
{
_hash ^= index;
if (item != null)
_hash ^= item.GetHashCode();
}
#region Overriden collection methods
protected override void InsertItem(int index, T item)
{
UpdateHash(index, item);
base.InsertItem(index, item);
}
protected override void RemoveItem(int index)
{
UpdateHash(index, this[index]);
base.RemoveItem(index);
}
protected override void ClearItems()
{
_hash = 0;
base.ClearItems();
}
protected override void SetItem(int index, T item)
{
UpdateHash(index, this[index]);
UpdateHash(index, item);
base.SetItem(index, item);
}
#endregion
#region Value equality
public bool Equals(HashedList<T> other)
{
if (other == null)
return false;
if (object.ReferenceEquals(this, other))
return true;
if (other.Count != this.Count)
return false;
if (other._hash != this._hash)
return false;
return CompareElements(other);
}
private bool CompareElements(HashedList<T> other)
{
for (int i = 0; i < this.Count; i++)
{
if (this[i] == null)
{
if (other[i] != null)
return false;
}
if (this[i].Equals(other[i]) == false)
return false;
}
return true;
}
public override bool Equals(object obj)
{
var hashed = obj as HashedList<T>;
if (hashed != null)
return Equals(hashed);
return base.Equals(obj);
}
public override int GetHashCode()
{
return _hash;
}
#endregion
}
公共类HashedList:集合,IEquatable
{
私有整数散列;
私有void UpdateHash(int索引,T项)
{
_hash^=索引;
hash(structure) := hast(item1) ^ hash(item2) ^ ... ^ hash(item_n)
hash(structure) := hast(item1, 1) ^ hash(item2, 2) ^ ... ^ hash(item_n, n)