I have to implement a generic AVL tree as homework. It's defined as follows:
public class AVL<Key,Elem>;
The problem is that I assume that at some point, I'll have to compare keys to decide in which side of a node I allocate an element. For the purpose of this homework, Integers will be used as Keys.
Since no other restriction or information about that is given, I first thought of just asuming that Key will always be an Integer. However, that makes the generic "Key" superfluous, and I don't think that's what the teachers expect. So, I think that the best solution involves forcing that whatever that is passed as Key implements a Comparator, or something like that (I've really never worked with Comparator, just guessing), and then using that comparator to compare the Keys instead of using the ==,<,> and != operators. However, I have no idea on how to do it. Any hints?
Thanks in advance.
Try public class AVL<Key extends Comparable<Key>,Elem>; and use the compareTo() method which is required by the Comparable<T> interface and which is implemented by Integer.
The SortedMap and SortedSet implementations in the standard Java API either use a Comparator<Key> and call its compare(k1, k2) method, or assume the keys implement Comparable<Key>, and call k1.compareTo(k2). Most offer both, depending on which constructor is used. (EnumMap/EnumSet don't, as they support only the build-in ordering of the enum values by declaration order.)
The Comparable approach mandates that the keys are always sorted in the same way, and would be used for keys which have a canonical ordering (like integers), where you want to use this ordering.
The Comparator approach is more flexible, since you can use the same key objects for different maps where they are differently ordered, and you can use it for keys over which you have no control, or who don't have a canonical ordering (like List, trees/graphs, etc. You can also use it to sort strings keys by other criteria than the pure unicode value (e.g. Locale-based), using a Collator (this is a class implementing Comparator).
Both require a total order on your keys, but I suppose this is necessary for your AVL tree, too.
Here is a Comparator implementation which works on any comparable objects, so you could use it (maybe internally) as an adapter for the Comparable variant.
public static <X extends Comparable<X>> Comparator<X> makeComparator() {
return new Comparator<X>() {
public int compare(X left, X right) {
return left.compareTo(right);
}
};
}
Related
I have a question which appeared in a past paper (I'm revising for my exams) and I came across this word natural order which appears to be a keywords since it was written in bold on the paper. I've looked online at Natural Order but I couldn't find anything that related it to arraylist's like my question asks.
Please note, I do not need help solving the actual question, I just wish to understand what natural order means.
Question:
Write a Java static method called atLeast which takes an ArrayList of objects which
have natural order, an object of the element type of the ArrayList, and an integer n. A
call to the method should return true if at least n elements of the ArrayList are greater
than the element type object according to natural order, otherwise it should return false.
This likely means the objects in the List implement Comparable:
This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method.
The declaration would look something like this:
static <T extends Comparable<? super T>>
boolean atLeast(List<T> list, T key, int n) {
...
}
Natural order means the default ordering for a particular type of collection. It actually depends upon the type of collection you are using. eg. if its a string collection, it will be sorted in alphabetical order, for numbers it follows numerical order.
Refer here for better understanding about natural ordering.
You can have a look at here for detail.
For objects to have a natural order they must implement the interface java.lang.Comparable. In other words, the objects must be comparable to determine their order. Here is how the Comparable interface looks:
public interface Comparable<T> {
int compareTo(T o);
}
I need to do this for a unit test. The method being tested returns an ImmutbaleMap and I need to be able to compare it with one that I already have. One way is to get key sets for both(keySets()), run through them and compare the values returned from both maps for those keys. However that to me seems a little inefficient. Is there a better/preferred way to do this ?
If both the keys and the values implement equals() correctly, you can simply use Map.equals():
Compares the specified object with this map for equality. Returns true if the given object is also a map and the two maps represent the same mappings. More formally, two maps m1 and m2 represent the same mappings if m1.entrySet().equals(m2.entrySet()). This ensures that the equals method works properly across different implementations of the Map interface.
If they don't, I doubt you'll find a one-liner that works out of the box. I expect you'd have to implement the comparison yourself. It's not hard to do:
If the symmetric difference between the two key sets is not empty, you're done.
Otherwise, iterate over one map, looking up the same key in the other and comparing the values (using whatever comparison method is appropriate).
This can be easily encapsulated into a helper function, perhaps parameterised by the value comparator.
Complement to #NPE's answer...
Since your values do not implement .equals()/.hashCode() correctly, a simple equals on maps will not work; but you use Guava; theefore you have the option of implementing an Equivalence.
This means, if the class of your values is Foo:
you'll need to implement an Equivalence<Foo>:
your map will have to be a Map<X, Equivalence.Wrapper<Foo>>.
With this, you'll be able to use Map's .equals().
You'll have to add values using Equivalence's .wrap() method. See here for an example of an Equivalence implementation.
Another choice would be to use plain Map, write impmementation of Equivalence and use followingdifference method from Maps class
MapDifference<K,V> difference(Map<? extends K,? extends V> left,
Map<? extends K,? extends V> right,
Equivalence<? super V> valueEquivalence)
I would prefer this way as it will not alter the Map types (won't do it just to calculate difference or to check equality).
Why should map1.entrySet().equals(map2.entrySet()) not work?
The EntrySet.equals() method refers to the Map.contains() method which should work for your values whether they implement equals() or not (in this case you probably have an IdentityHashMap underlying).
I have a class PriorityList with the signature
Tree<Key extends Comparable<Key>, Value>(which is given, I can't modify). The elements Tree are inserted in some order, given the key (i.e. it considers the key's compareTo method).
Let's say I have Tree<Integer, Integer>. The default compareTo of integer considers ascending order. I would like to be able to somehow have Tree insert the elements in descending order, if I wanted to. I know I could probably write another class MyInteger which implements Comparable and has a compareTo on its own.
But is there another way? What I would really like is to be able to somehow tell the Tree how to order the values.
Second question: If I were able to modify Tree, how would one pass a comparator as argument? (keeping generic types-syntax in mind).
You've named the two ways to do it: pass in a comparator or have key be comparable. If the class doesn't let you pass in your own comparator, then you're stuck monkeying with the keys or creating your own subclass with the Comparable interface
The alternative code would look something like this.
public class Tree<K,V>{
public Tree( Comparator<K> cmp ) {...}
}
You wouldn't need to create a new class for reverse. you can use Collections.reverseOrder() to obtain a Comparator in reverse of a given one.
As for the second question, you will simply add a setter to your tree. Something like: setComparator(Comparator<Key> c) and then use that comparator for all the comparisons needed in your Tree.
There are questions here how to get a Maps keys associated with a given value, with answers pointing to google collections (for bidirectional maps) or essentially saying "loop over it".
I just recently noticed that the Map interface has a boolean containsValue(Object value) method that "will probably require time linear in the map size for most implementations of the Map interface" and the implementation in AbstractMap indeed iterates over the entrySet().
What could be the reason for the design decision to include containsValue in Map, but no Collection<V> getKeysForValue(Object)? I can see why one would omit both, or include both, but if there is one, why not the other?
One thing that came to my mind is that it would require any Map implementation to know about a Collection implementation for the return value, but that is not actually a good reason as the Collection<V> values() method also returns a collection (an anonymous new AbstractCollection<V>() in case of AbstractMap).
There are collections which support this, but they usually involve mainlining a reverse lookup map which is more expensive that than the relatively simple one to one mapping. As such supporting this could make all Maps more than twice as expensive on update.
Another problem is generalisation. Keys have to implement hashCode and equals (for Hash maps) or comparable (for Sorted Maps) Values don't have to implement anything which makes constructing a generalised reverse lookup either impossible, or it places extra requirements on values which are unlikely to be needed.
Maps can return a Collection of their keys and values since 1.2, so it was trivial to look for a value: public Object containsValue(Object v) {return values().contains(v);} This method uses natively optimisations from values() and contains() for any implementation of Map, but is likely to be slow anyway in most of them...
The getKeysForValue(Object) you're looking for is NOT trivial. It requires a specific algorithm, and this algorithm cannot be made generic enough, it must be optimised for every implmentation of Map.
It could be the reason, or it is simply that the Collection API is full of this kind of little loopholes...
in which situations we have to implement the Comparable interface?
When you want to be able to compare 2 objects and get a result of equal, less than, or greater than.
Implementing Comparable gives your objects a compareTo method. If you add them to a sorted list then they will automatically be sorted based on what your compareTo method returns.
It's pretty basic. I don't know what else there is to add.
When your class implement the Comparable interface, you have to implement the compareTo() method in a way that you can clearly tell where an instance of your class would go in an ordered list of such instances.
Implementing efficient sorting algorithms and ordered collections isn't trivial. Therefore you would do this when you want objects of a class to have natural ordering, so you can use the proven sorting and order-dependent algorithms and classes provided by Java instead of implementing your own, like having the contents of a TreeSet remain ordered after insertions/deletions, or using Collections.sort().