0

私はツリーのような構造をしており、私のコピー コンストラクターは時々私の「葉」の一部を落としているようです。

基本構造:

public class Arrow {
   ArrayList<Arrow> subArrows;
   Interval start;
   Interval end;
}

コピー コンストラクター:

public Arrow(Arrow other) {
    this.start = new Interval(other.start);
    this.end = new Interval(other.end);
    if (other.subArrows != null) {
        this.subArrows = new ArrayList<Arrow>();
        for (Arrow sub : other.subArrows) {
            this.subArrows.add(new Arrow(sub));
        }
    } else {
        this.subArrows = new ArrayList<Arrow>();
    }
}

これにより、基本的にツリー構造のディープコピーが行われると予想していました。代わりに、subArrowsアレイの 1 つが空であることに気付くことがあります。ツリーの最も低い「レベル」にある傾向があるという以外のパターンに気づいていません。

何か案は?しばらくJavaを使っていません。

編集: 何人かがより多くのコードを求めていたので、subArrows に触れるすべての場所をここに示します。これはかなり大きなアルゴリズム/データ構造からのものであるため、すべてを投稿するのは不合理です.

すべての subArrows を再帰的に取得し、それらのセットを返します。

Set<Arrow> allSubArrows(Arrow arrow) {
    Set<Arrow> arrowSet = new HashSet<Arrow>();
    if (arrow.subArrows != null && arrow.subArrows.size() > 0) {
        for (Arrow sub : arrow.subArrows) {
            arrowSet.addAll(allSubArrows(sub));
        }
        return arrowSet;
    } else {
        arrowSet.add(arrow);
        return arrowSet;
    }
}

Mathy はこれが何をするかの背後にある理由を説明しますが、subArrows は下部で変更されています:

void enforceMonotonicity(Arrow arrow) {
    boolean changed = false;
    if (arrow.end != null && arrow.start != null) {
        if (arrow.start.isParallelTo(arrow.end)) {
            //either left to right or bottom to top
            if (arrow.start.isVertical()) {
                //left interval pointing to right interval
                if (arrow.start.startGraph.y > arrow.end.startGraph.y) {
                    arrow.end.startGraph.y = arrow.start.startGraph.y;
                    changed = true;
                }
                if (arrow.end.endGraph.y < arrow.start.endGraph.y) {
                    arrow.start.endGraph.y = arrow.end.endGraph.y;
                    changed = true;
                }
            } else {
                //bottom interval pointing to top interval
                if (arrow.start.startGraph.x > arrow.end.startGraph.x) {
                    arrow.end.startGraph.x = arrow.start.startGraph.x;
                    changed = true;
                }
                if (arrow.end.endGraph.x < arrow.start.endGraph.x) {
                    arrow.start.endGraph.x = arrow.end.endGraph.x;
                    changed = true;
                }
            }
        }
    }
    if (changed) {
        //check to make sure SOMETHING is still reachable, if not arrow = null
        if (arrow.start.isVertical()) {
            if (arrow.start.startGraph.y >= arrow.start.endGraph.y ||
                    arrow.end.startGraph.y >= arrow.end.endGraph.y) {
                arrow = null;
            }
        } else {
            if (arrow.start.startGraph.x >= arrow.start.endGraph.x ||
                    arrow.end.startGraph.x >= arrow.end.endGraph.x) {
                arrow = null;
            }
        }
        //if we changed the outer arrows, we need to recursively change the subarrows
        if (arrow != null && arrow.subArrows != null && arrow.subArrows.size() > 0) {
            for (Arrow sub : arrow.subArrows) {
                enforceMonotonicity(sub);
            }
        }
    }
}

マージ アルゴリズムの一部:

HashSet<Arrow> mergeCells(Set<Arrow> first, Set<Arrow> second) {
    HashSet<Arrow> mergedCell = new HashSet<Arrow>();
    //loop through arrows in adjacent cells and find the ones that connect
    for (Arrow topArrow : first) {
        for (Arrow bottomArrow : second) {
            if(topArrow.start.intersects(bottomArrow.end)) {
                //merge arrows
                Interval middle = topArrow.start.intersection(bottomArrow.end);
                Arrow newArrow = new Arrow();
                if (middle != null) {
                    //if they connect, we copy the two arrows, modify their connection,
                    //create a new arrow with the constituents as subarrows, and add that to the mergedcell
                    //after the mergedcell is created, we can delete the base arrows
                    Arrow topCopy = new Arrow(topArrow);
                    topCopy.start = middle;
                    Arrow bottomCopy = new Arrow(bottomArrow);
                    bottomCopy.end = middle;

                    newArrow.subArrows.add(topCopy);
                    newArrow.subArrows.add(bottomCopy);
                    newArrow.start = bottomCopy.start;
                    newArrow.end = topCopy.end;

                    //if end and middle are parallel, we need to project monotonicity
                    //monotonicity is already enforced within a single cell
                    //and enforcemonotonicity knows whether or not start and end are parallel
                    enforceMonotonicity(newArrow);
                }
                //enforceMonotonicity could null out the new arrow
                if (newArrow != null && !newArrow.isNull()) {
                    mergedCell.add(newArrow);
                }
            }
        }
    }

    //keep the originals in case they can connect later on
    //(hashset doesn't allow duplicates, so no need to worry here)
    mergedCell.addAll(first);
    mergedCell.addAll(second);

    return mergedCell;
}
4

1 に答える 1

0

の場合(other.subArrows == null)でも、コードはによって作成this.subArrowsされnew ArrayList<Arrow>()ます。これは実際のクローンではありません(1つはnull、もう1つはそうではありません)。subArrowが常にnullでないことを確認したい場合(これにより、チェックせずにsubArrowを追加しやすくなりnullます)、フィールド定義でインスタンス化できます。

それでも機能しない場合は、矢印にsubArrowsを追加する方法がわからないため、さらにコードを表示する必要があります。また、コードがマルチスレッド環境であり、バグの再現が難しい場合は、同期の問題である可能性があります。ArrayListこれはスレッドセーフではないことに注意してください。VectorまたはCollections.synchronizedList代わりに、またはクリティカルブロックを適切に同期してみてください。繰り返しになりますが、関連するコードはありません。

ところで、宣言List<Arrow> subArrowsはよりも優れていArrayList<Arrow> subArrowsます。

于 2013-01-11T02:58:03.337 に答える