Java:配对对象的高效Collection概念

时间:2011-07-22 23:16:35

标签: java performance collections

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

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

我正在建模由四面体单元组成的体网格(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 - 对象可以创建某种不可变的Signature - 仅包含顶点配置,方向(顺时针(cw)或逆时针(ccw))和背面的对象引用原始Face对象。 Face.Signature对象被认为是相等的(@Override equals()),如果它们占据相同的三个顶点 - 无论它们的方向和相关的单元格如何。

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

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 - 概念,它提供以下功能:

  • Face - 对象添加到集合中(应用程序禁止重复,因此不会发生)
  • 从Collection中检索给定Face的合作伙伴 - .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 - 对象。因此性能 是一个问题。

提前感谢任何至少试图跟随我的人:) 我希望有任何人有正确的想法来解决这个问题。

4 个答案:

答案 0 :(得分:3)

使用两个Map<Face.Signature, Face.Signature>有什么问题吗? 每个方向一个?

这就是我要做的。它实际上没有代码。

答案 1 :(得分:0)

使用您现在拥有的设计,无法解决某些需要迭代某处的问题。问题是,您希望迭代发生在哪里?我建议你这样做:

    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)左右。

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

编辑:经过一番思考后,我相信理想的数据结构将是一个Octuply Linked List,这会让事情变得混乱,但也会非常快(相对而言)。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您是否考虑过给每个Face一个合作伙伴数据成员?如,

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

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