C# 从HashSet获取相等的对象<;T>;在O(1)中

C# 从HashSet获取相等的对象<;T>;在O(1)中,c#,set,C#,Set,HashSet可以在O(1)中确定它是否包含某个项目。如果我在我的自定义类上重写Equals()和GetHashCode(),我可以拥有一个对象A和另一个对象A',这两个对象的标识不相等,但Equals()返回true和GetHashCode()返回相同的哈希代码 现在,假设A在散列集中,我想检索O(1)中的A,给定A'(从散列集的角度来看,它等于A) var a=新的MyClass(“a”); var a_prime=新的MyClass(“a”); Assert(a.Equals(a_prim

HashSet
可以在O(1)中确定它是否包含某个项目。如果我在我的自定义类上重写
Equals()
GetHashCode()
,我可以拥有一个对象A和另一个对象A',这两个对象的标识不相等,但
Equals()
返回
true
GetHashCode()
返回相同的哈希代码

现在,假设A在散列集中,我想检索O(1)中的A,给定A'(从散列集的角度来看,它等于A)

var a=新的MyClass(“a”);
var a_prime=新的MyClass(“a”);
Assert(a.Equals(a_prime));
Assert(a.GetHashCode()==a_prime.GetHashCode());
var set=新的HashSet();
增加(a);
Assert(set.Contains(a_prime));
//这:
检索到的var\u a=set.Get(a\u素数);
如何做到这一点

(请注意,这不是我要寻找的答案,而且根本没有答案。)



一些背景信息:我想使用集合来实习生我自己的对象,就像C#实习生字符串一样:相等的对象只需要一个实例。通过这种方式,我可以将元数据附加到这样一个对象,并确保没有该元数据,任何地方都不会有其他相同的实例。

HashSet
上没有任何方法可以满足您的需要

您可以使用
字典

var dict = new Dictionary<MyClass, MyClass>();
dict[a] = a;
Debug.Assert(dict.ContainsKey(a_prime));
var retrieved_a = dict[a_prime];
var dict=newdictionary();
dict[a]=a;
Assert(dict.ContainsKey(a_prime));
var_a=dict[a_素数];

如果我没记错的话,
字典
没有基本集合操作的固定时间实现,而
HashSet
有。下面是一种使用恒定时间相等查找实现它的方法,而不会增加哈希集的其他复杂性。如果需要获取许多随机元素,那么使用这种方法是至关重要的。我在下面写的是Java语法,因为我不懂C语言,但它的思想与语言无关

class MySet<A> {
     ArrayList<A> contents = new ArrayList();
     HashMap<A,Integer> indices = new HashMap<A,Integer>();

     //selects equal element in constant time
     A equalElement(A input) {
         return contents.get(indices.get(input));
     }

     //adds new element in constant time
     void add(A a) {
         indices.put(a,contents.size());
         contents.add(a);
     }

     //removes element in constant time
     void remove(A a) {
         int index = indices.get(a);
         contents.set(index,contents.get(contents.size()-1));
         contents.remove(contents.size()-1);
         indices.set(contents.get(contents.size()-1),index);
         indices.remove(a);
     }

     //all other operations (contains(), ...) are those from indices.keySet()
}
类MySet{
ArrayList contents=新的ArrayList();
HashMap索引=新的HashMap();
//在恒定时间内选择相等的元素
相等元素(输入){
返回contents.get(index.get(input));
}
//在常量时间中添加新元素
无效添加(A){
index.put(a,contents.size());
内容。添加(a);
}
//以固定时间删除元素
无效删除(A){
int index=index.get(a);
contents.set(index,contents.get(contents.size()-1));
contents.remove(contents.size()-1);
index.set(contents.get(contents.size()-1),index);
删除(a)段;
}
//所有其他操作(contains(),…)都是来自index.keySet()的操作
}

使用
HashSet.TryGetValue
。(从开始提供。)

为什么不使用字典映射到
a
a
?可能是另一个的重复我一直避免使用映射到自己的dict。这是坏习惯吗?“还是我什么都不担心?”汉斯一如既往,这要看情况而定。你为什么认为这是一种不好的做法?你为什么要避开他们?@svick我不知道,我只是觉得很奇怪。我想我没有任何具体的理由来避免它,但我从来没有使用过这样的构造,但出于某种原因,我看
dict[a]=a让我畏缩。它也让我畏缩。如果没有别的,它有一个明显的冗余。不过,除非遇到性能问题,否则可能不值得修复。对不起,随机是一个输入错误,我的意思是“相等”而不是“随机”。我现在已经纠正了这个方法。基本上,我不使用HashSet,而是使用HashMap和ArrayList,它们包含相同的元素,HashMap指向ArrayList中该元素的索引。HashMap显示的不是HashSet中简单的“Yes I have this key”,而是“Yes I have this key and it point the integer
I
”。然后在ArrayList中,您可以通过在位置
i
获取对象。感谢您的更正!现在它更相关了!作为旁注,我仍然会非常小心关于“恒定时间”的说法。我不认为HashMaps保证了最坏情况下的O(1)获取时间,我认为它是平均的O(1),并且如果你,例如,邪恶地修补映射键的GetHashCode,你会变得更糟。无论如何,删除了-1和之前的评论,因为它与现在的帖子不匹配。你是对的,我说的“恒定时间”是指“平均时间:恒定”。这太棒了,+1。虽然我的性能列表将以
HashMap
的形式实现这一点,并手动实现set操作。但我认为有一个小小的修正:从
内容中删除该项后,您无法执行
contents.get(contents.size()-1)
。它会给你错误的项目。它应该是
index.set(contents.get(contents.size()-1),index)
contents.remove之前(contents.size()-1)
class MySet<A> {
     ArrayList<A> contents = new ArrayList();
     HashMap<A,Integer> indices = new HashMap<A,Integer>();

     //selects equal element in constant time
     A equalElement(A input) {
         return contents.get(indices.get(input));
     }

     //adds new element in constant time
     void add(A a) {
         indices.put(a,contents.size());
         contents.add(a);
     }

     //removes element in constant time
     void remove(A a) {
         int index = indices.get(a);
         contents.set(index,contents.get(contents.size()-1));
         contents.remove(contents.size()-1);
         indices.set(contents.get(contents.size()-1),index);
         indices.remove(a);
     }

     //all other operations (contains(), ...) are those from indices.keySet()
}