【问题标题】:Java: efficient Collection concept for a paired objectsJava:成对对象的高效集合概念
【发布时间】:2011-07-22 23:16:35
【问题描述】:

我缺少针对特定问题的某种收集功能。

我想从有关问题背景的一些信息开始 - 也许有一种更优雅的方法来解决它,它不会以我遇到的具体问题结束:

我正在建模由四面体单元组成的体积网格(2D 模拟将是三角形网格)。如果两个四面体共享一个三角形面(占据三个顶点),则认为它们是相邻的。我的应用程序必须能够通过它们的共同面孔从一个单元格导航到另一个单元格。

为了满足其他一些要求,我不得不将面分成两个所谓的半面,它们共享相同的顶点但属于不同的单元格并且具有相反的方向。

应用程序需要能够进行这样的调用(Face 模拟半脸):

Cell getAdjacentCell(Cell cell, int faceIndex) {
    Face face = cell.getFace(faceIndex);
    Face partnerFace = face.getPartner();
    if (partnerFace == null) return null; // no adjacent cell present
    Cell adjacentCell = partnerFace.getCell();
    return adjacentCell;
}

getPartner()-方法的实现是有问题的方法。我的做法如下:

Face-objects 可以创建某种不可变的Signature-object,其中仅包含顶点配置、方向(顺时针 (cw) 或逆时针 (ccw))和对原始对象的反向引用面对象。如果 Face.Signature-objects 占据相同的三个顶点,则认为它们是相等的 (@Override equals()) - 无论它们的方向和关联的单元格如何。

我在Mesh-objects 中创建了两个集合,以包含按方向分组的所有半面:

Set<Face.Signature> faceSignatureCcw = new HashSet<Face.Signature>();
Set<Face.Signature> faceSignatureCw = new HashSet<Face.Signature>();

现在我可以确定是否存在合作伙伴...

class Face {
    public Face getPartner() {
        if (this.getSignature().isCcw()) {
            boolean partnerExists = this.getMesh().faceSignatureCw.contains(this);
        } else {
            boolean partnerExists = this.getMesh().faceSignatureCcw.contains(this);
        }
    }
}

...但是Set 不允许检索它包含的特定对象!它只是确认它包含一个通过.equals() 匹配的对象。

(背景信息结束)

我需要一个Collection-concept,它提供以下功能:

  • Face-Object 添加到集合中(应用程序禁止重复,因此不会发生)
  • 从集合中检索给定 Face-Object 的合作伙伴,该对象 .equals() 但具有相反的方向

一种可能的(但速度较慢的)解决方案是:

class PartnerCollection {
    List<Face.Signature> faceSignatureCcw = new ArrayList<Face.Signature>();
    List<Face.Signature> faceSignatureCw = new ArrayList<Face.Signature>();

    void add(Face.Signature faceSignature) {
        (faceSignature.isCcw() ? faceSignatureCw : faceSignatureCcw).add(faceSignature);
    }

    Face.Signature getPartner(Face.Signature faceSignature) {
        List<Face.Signature> partnerList = faceSignature.isCcw() ? faceSignatureCw : faceSignatureCcw;
        for (Face.Signature partnerSignature : partnerList) {
            if (faceSignature.equals(partnerSignature)) return partnerSignature;
        }
        return null;
    }
}

要完整:最终的应用程序必须在实时环境中处理数十万个Face-Objects。所以性能一个问题。

在此先感谢任何至少尝试关注我的人 :) 我希望有人有正确的想法来解决这个问题。

【问题讨论】:

    标签: java performance collections


    【解决方案1】:

    使用两个Map&lt;Face.Signature, Face.Signature&gt;有什么问题吗?
    每个方向一个?

    这就是我要做的。它几乎没有代码。

    【讨论】:

    • 既然Map 的关键部分是Set,我最终会不会遇到与Set-Solution 相同的问题?我将能够识别出存在合作伙伴对象,但我无法获取对象本身。还是我错过了什么?
    • ...事实上我确实错过了一些东西 - 你是对的。我应该能够使用条目的值检索所需的对象。它仍然是某种内存浪费,但它应该解决原来的问题。我试试看,谢谢!
    【解决方案2】:

    这里是深夜,我还没有完全准备好你的问题。因此,如果这没有任何意义,我深表歉意,但是您是否考虑过使用图形数据结构?如果图数据结构确实是一个可能的解决方案,您可能需要查看jGraphT

    【讨论】:

      【解决方案3】:

      您是否考虑过只为每个人脸分配一个合作伙伴数据成员?如,

      public class Face
      {
          Face partner;
          //whatever else
      }
      

      Face.Signature 构造有点复杂,确实不需要。如果每张脸都有一个伙伴(或者足够多的Face 对象可以有一个伙伴,那么认为Face 和一个伙伴Face 之间存在has-a 关系是有意义的) ,连接应该只是一个实例变量。如果您可以使用这种方法,它应该会大大简化您的代码。如果没有,请发回这对您不起作用的原因,以便我继续努力提供帮助。

      【讨论】:

      • 这只是一个设计决定。 Signature 允许我定义与 Face-class 本身不同的相等类型。如果解决方案不需要覆盖equals()hashCode(),我可能会退回到单个实例变量。但是,还有一些其他应用程序特定的原因表明您不知道Signature-class,因为我没有提到它们。但是,切换到实例变量本身并不能解决问题。
      【解决方案4】:

      使用您现在拥有的设计,没有办法绕过需要迭代的东西某处。问题是,您希望迭代发生在哪里?我建议你这样做:

          List<Face.Signature> partnerList = faceSignature.isCcw() ? faceSignatureCw : faceSignatureCcw;
          int idx = partnerList.indexOf(faceSignature);
          if(idx == -1)
             return null;
          return partnerList.get(idx);
      

      另外,只要您使用Lists,并且知道初始大小必须相当大,您不妨说new ArrayList(100000) 左右。

      当然,这不是唯一的方法,只是一种确保迭代最优的方法。

      编辑:经过一番思考,我认为理想的数据结构将是一个八倍链表,这会使事情变得混乱,但也非常快(相对而言)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-04-22
        • 1970-01-01
        • 2013-03-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多