I have a set of items that are serialized to a file. Some items can rely on other items, but circular references are not allowed. Thus, they need to be serialized in a way such that if A relies on B, B is serialized first in the file.
I wrote my Comparator that uses a reliesOn() function to determine if two items are linked:
Collections.sort(itemsToSort, new Comparator<Item>() {
@Override
public int compare(Item first, Item second) {
boolean firstReliesOnSecond = reliesOn(first, second);
if (firstReliesOnSecond) {
return 1;
}
boolean secondReliesOnFirst = reliesOn(second, first);
if (secondReliesOnFirst) {
return -1;
}
return 0;
}
});
This works for some cases, but not all. In debugging, it's obvious that the sort relies on the transitive nature of the Comparator, and understandably does not compare every possible pairing of items.
For example, with five items A through E, if:
A -> B
B -> E
C
D
E
Then one possible ordering would be:
E, B, A, C, D
At the very least, E comes before B, and B comes before A.
However, during the comparison phase (paraphrasing as an example), what happens is that C is compared to E, returning 0 because they have no relation. And then C is compared to B, and also returns 0.
And as a result, the sorting algorithm assumes B = E, which is not the case. (Even though I broke the Comparator contract.) How can I write my compare() method in a way that ensures transitivity?
Edit: It was pointed out that I'm performing a topological sort on a directed acyclic graph. I'm having flashbacks to my Data Structures course. Fortunately Wikipedia seems to have a good linear-time algorithm for performing this sort - I'll give it a shot.