akifusenet
akifusenet

Reputation: 192

How to have a TreeSet which is "inconsistent with equals"

I have read numerous posts about TreeSets, Comparable/Comparator Interfaces, equals, compareTo, compare methods and I know that API says you have to make your ordering "consistent with equals" or weird things might happen.

But in my case and I think this is a fairly general case, I really do need a TreeSet ordering which is "inconsistent with equals".

Lets say we are doing some kind of heuristic search and we are expanding (or generating) new states starting from a root(initial) state. And we put new (expanded/generated) states into a TreeSet which we usually call open list. We would like to use the TreeSet container because we dont want duplicate states in our open list.

Every state generated/expanded is evaluated by a cost function and given a heuristic value which shows the quality of the state. We want the TreeSet (open list) ordered by this value. We want to have the best states (which has the best cost value) at the top of the TreeSet.

Now here comes the problem. To accommodate the ordering by cost value we need to give the TreeSet a comparator which compares the cost values. But, two different states can have the same cost/heuristic value. I want to have both of these states on my open list because they are not "equal". But comparator needs to return 0 from the compare method because they have the same cost value. And because this, different states with the same cost value will not be inserted into the list.

I want to give a simple example to make this more understandable. Lets say our states are strings showing binary data and the cost function counts the number of "1"s in the string.

Lets say these are the generated states and their respective cost values.

  No  State       Cost 
  1   01001001     3
  2   01101001     4
  3   10001001     3
  4   01001111     5

As you can see all these 4 states are different. They are "not equal". But even though state-1 and state-3 are different, they have the same cost value "3". So when we order our TreeSet by cost, state-3 will not be added to the TreeSet because there is already an element with the same cost value. But we need that state to be added to the list because it is perfectly valid, different, new state.

How can I overcome this problem?

Thanks.

Upvotes: 3

Views: 594

Answers (2)

biziclop
biziclop

Reputation: 49724

What you need is simply a comparator that does two things:

  1. First compares the costs. Lower costs will be ranked first.
  2. If the costs are equal (and only then), it uses an arbitrary tie breaker to rank states. (For example, compares the ids of the states.) It's important that while the tie breaker can be arbitrary, it should be deterministic, only depending on fields in the state object that will stay constant throughout the lifetime of the object in the set.

This is a kind of lexicographic ordering and it's fully consistent with equals(). (Because the comparator will return 0 iff equals() returns true.)

Complete aside: Depending on your specific use case, you may be better off with a PriorityQueue than a TreeSet. Then you don't have to worry about multiple elements with the same priority.

Upvotes: 5

Davio
Davio

Reputation: 4737

What is meant by "consistent with equals" just means that for two objects that equal each other, the comparator should return 0, or:

obj1.equals(obj2) should be the same boolean value as comparator.compare(obj1, obj2) == 0;

But you're free to just use your own comparator which puts low costs ahead of high costs, as long as the comparator returns 0 for equal states.

Upvotes: 1

Related Questions