我有一项任务,必须为集合中的每个对象生成唯一值。如果哈希码合约中不允许冲突,则使用哈希码将是完美的。
一个想法:将每个对象的哈希码记录到多集中。然后,使用哈希码作为唯一标识符,但如果该哈希码多次出现在集合中,请使用不在集合中的其他值。但这感觉笨重而且很尴尬。
更好的想法?
这是我已经拥有的:
public static <V> void toGraphViz(final Graph<V, DefaultWeightedEdge> g, String filename) {
// to avoid hashcode collisions
final Set<Integer> hashcodes = new HashSet<Integer>(g.vertexSet().size());
DOTExporter<V, DefaultWeightedEdge> dot = new DOTExporter<V, DefaultWeightedEdge>(new VertexNameProvider<V> () {
// vertex name must be unqiue
@Override
public String getVertexName(V arg0) {
int hash = arg0.hashCode();
while (hashcodes.contains((hash))) {
hash += 1;
}
return "" + hash;
}
}
编辑:我想这本来不是很清楚,但是id号确实需要成为对象的函数,因为getVertexName(V)
会多次被调用,而它我们希望对于相同的V
值,它会得到相同的结果。
此外,Vertex类型是通用的。因此,我无法对特定类进行任何修改来解决此问题。
答案 0 :(得分:4)
这个唯一号码的生命周期是多少?只是程序的生命周期?在这种情况下,为什么不只是一个简单的静态计数器在类中,通过适当的同步访问?为每个新对象增加它。无需保留已使用的值列表,只需保留您使用的最高值。
如果在许多执行中都是唯一的(也许是许多同时发生的实例),那么也许您可以使用生成unqiue记录ID的数据库。
为回应澄清而编辑
我之前错过的部分是我们无法修改我们想要生成唯一“哈希”的类。
我认为从类的哈希码开始工作会产生冲突,这会让生活变得艰难。假设我们可以依赖正确实现equals()的Vertex类,那么我们可以使用对象本身作为我们使用的哈希码集的关键。
public class Hasher {
public <V> void toGraphViz(final Graph<V, DefaultWeightedEdge> g, String filename) {
final Map<V, Integer> hashcodes = new HashMap< V, Integer>();
final int latestHashHolder[] = { 0 }; // array to allow access from inner class
DOTExporter<V, DefaultWeightedEdge> dot
= new DOTExporter<V, DefaultWeightedEdge>(new VertexNameProvider<V> ()) {
// vertex name must be unqiue
@Override
public synchronized String getVertexName(V vertex) {
int hashcode;
if ( hashcodes.containsKey(vertex)){
hashcode = hashcodes.get(vertex);
} else {
hashcode = latestHashHolder[0];
latestHashHolder[0]++;
hashcodes.put(vertex, (Integer)latestHashHolder[0]);
}
return "Vertex-" + hashcode;
}
};
}
}
答案 1 :(得分:2)
为什么不使用序列号?
static private int serial=0;
static public synchronized nextSerialNumber() { return ++serial; }
或者组合/混合,比较长((hash&lt;&lt; 32)| getNextSerial())。
构造对象时,将序列号分配给私有成员变量并将其返回给hashCode()。然后你应该通过调用super.equals()来覆盖equals(因为生成的序列号与默认的equals()实现一致)因为看到一个没有相应的equals()重写的hashCode()重写会使代码重新标记工具(和其他程序员)。
public class Vertex
{
private final int serial; // instance serial number
public Vertex() {
serial=nextSerialNumber();
...
}
public int hashCode() {
return serial;
}
public boolean equals(Object obj) {
return super.equals(obj); // serial number hash-code consistent with default equals
}
...
static private int nextSerial=0;
static public synchronized nextSerialNumber() { return nextSerial++; }
}
答案 2 :(得分:2)
您可以考虑使用UUID,具体取决于您要完成的工作......
答案 3 :(得分:2)
要查找对象的唯一值,您必须知道使对象唯一的属性组合。
要运行“.contains()”,你需要有一个确定“.equals()”的方法,这意味着你应该已经知道如何唯一地识别一个顶点,所以也许你可以想出一个表达式独特的属性?
例如,“(x,y,z,rgb)”除非我误解了这个问题,否则我不建议为此目的使用对象的hashCode。
答案 4 :(得分:1)
我认为你误解了哈希码。 根据合同,当equals(..)为真时,hascode应该是相同的,反之亦然。所以在你的情况下,只有具有相同属性的顶点应该具有相同的hascode,否则你自己编写的hascode计算方法应该是固定的。据我所知,你的问题顶点本身是独特的,所以你不应该有问题,对吗?
答案 5 :(得分:0)
我可能不明白你在做什么,但考虑创建一个参考 到每个对象。由于引用包含它将成为的对象的地址 每个对象都是唯一的。
答案 6 :(得分:0)
这不是那么难,是吗?只是使用不同的哈希算法,如果Java中的哈希算法不保证没有冲突。将对象发送到散列算法,例如Sha-256,并用它作为关键。如果您需要使用不同的哈希值保留完全相同的对象的不同副本,请在执行哈希时使用种子,并使用哈希将其与对象相关联。