我应该使用哪种数据结构来维护这些信息?

时间:2017-02-07 12:05:17

标签: java data-structures

大家好我有两个实体相互关联,有这样的关系:

实体A为实体B所知,实体B知道实体A.

为了维护这些信息,我可以使用哪种最有效的数据结构?

我想到有两个哈希映射,其中键是实体的A键,并且为每个知道A的B实体的值列出一个列表,另一个列出了关键实体B的密钥等。但我想知道我是否只能使用一个数据结构

我的目标是速度而不是空间,所以只要速度快就无所谓。

2 个答案:

答案 0 :(得分:0)

您为什么要使用Datastructure? 这是一个正常的"两个对象之间的双向关联。

class A {
    B b;
    ....
    // Perhaps you can do somthinkg like this to maintain consitsncy
    void setB(B b) {
        this.b = b;
        b.a = a;
}
class B {
    A a;
    ....
}

答案 1 :(得分:0)

鉴于您已经提到重点是速度,这实际上取决于您需要如何访问数据,即您需要问什么问题的数据结构。

例如,如果您只需要提问“X是否知道Y”或“Y知道X”那么您只需要一个哈希映射。或哈希集, 只要你能为它们生成一个合适的hashCode()实现 (稍后再看一下示例hashCode实现,虽然可能不是很好的,但是自从我使用Java以来​​已经很多年了)

即有一套

class Item extends Pair {
  Item(A,B)
  // override hashCode() and equals() methods as necessary 
}

hashset<Item> relationships;
relationships.add(new Item(A,B))
relationships.add(new Item(B,C))

if( ! relationship.contains (new Item(B,A)))
   // print "b does not know a"

或地图:

HashMap<Item,Boolean> relationships;
relationships.put(Item(A,B),True)
....

但是,如果您需要查看一个实体然后找到它所知道的所有内容,那么图形结构会更好。

如果您正在构建一个不需要太多灵活性的一次性数据集您可以将图形实现为单个链接列表,包含起点的所有边缘,并且具有指向的哈希(通过对象键)到每个已知项目列表的第一个边缘。

例如,未经测试的伪代码,不正确的java

Class Item {
  Entity first
  Entity second
  Item next;
  Item prior;
  Item(x,y) { first = x; second = y; }
  Item Join(nextItem) { 
    next = nextItem; next.prior = this; return next; 
  }
  // override hashCode and equals() but don't use 'next' or prior as part of the hash calculation or equals comparison

  //this is just for example, not sure if this is a good hash
  long hashCode() { return a. hashCode() & b.hashCode(); }
}

class Graph extends HashSet<Item> {

  Bool containsRelationship(Entity x, Entity y) {
     return contains(new Item(x,y))
   }
   Bool isRcognisedEntity(Entity x) {
     return contains(new Item(x,x))
  }
  Item getRelationships(Entity x) {
      Item ret = get(new Item(x,x))
       if ret is not null
         return ret.next // return the first entity x knows, other than itself
       else 
         return null // nothing known
  }

  Item addEntity(Entity e, Entity[] e_knows) {
     Item first = new item (e,e)
     add(first)
     Item lastItem = first
     for k in e_knows
         lastItem = lastItem.join(new item(e,k))
         add(lastItem)
     return first
  }
}

Entity a;
Entity b;
Entity c;
Graph g;
g.addEntity(a, {b,c})
g.addEntity(b, {c})
g.addEntity(c,{ a,b,c})

if g.contains(item(a,b))
   Print "a knows b"

c_knows = g.getRelationships(c)

while c_knows is not null
   Print "c knows " + c_knows.second
   c_knows = c.next

所以你只用一个Set看到这种方式,你可以问“x知道吗”以及“谁知道x知道”,代价是来自next / previous属性的一些内存开销(你可能只需要一个)

如果不是通用的Entity基类,而是有两个单独的类A和B,那么您可以使用Object执行此操作,并根据需要在Graph类的例程中转换结果以提供类型安全性。

例如

class Item {
  Object first;
  Object second;
 ...
}
class Graph {
 // as above except use Object instead of Entity, and make the methods protected not public
}
class ABGraph extends Graph {

   Iterator getRelationships(A a) {
     return new B_Itemterator(super.getRelationships(a));
   }
   void addRelationships(A a,B[] b_knows) {
     super.getRelationships( a, b_knows)
   }
   // Similar functions for B
}
class A_ItemIterator implements Java.collections...Iterator<A> {
  A_ItemIterator(Item i) { this.i = I }
  bool hasNext() { return i.next !=  null; }
  A next() { item n = i.next; I = n; return n; }
}

// similar iterator class for B_ItemIterator

ABGraph g;
A a;
B b1;
B b2;
g.addRelationships(a, new B[]{b1,b2})

if g.contains (a,b1) // should still work 

Iterator<B> i= g.getRelationships(a)
while(i.hasNext())
  print " thing "+ a + " of type A knows about " + b.next() + "of type B'