Could anyone say when TeeMap makes sorting - on adding entries via put method or, for example, before we iterate the map? I tried to find in javadoc but with no luck.
It's done during the altering operations.
For exemple, here is the jdk8 implementation of the method put :
public V put(K key, V value) {
Entry<K,V> t = root;
if (t == null) {
compare(key, key); // type (and possibly null) check
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null) {
do {
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
else {
if (key == null)
throw new NullPointerException();
#SuppressWarnings("unchecked")
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
Related
I'm using a BST. Given a key, how will I find the successor key? This is the code I have so far. I've managed to insert a new key and retrieve a value given the key. Now, I need to finish the next method. How would I approach this?
class BST<K extends Comparable<K>, V> implements RangeMap<K,V> {
class Node {
Node left;
Node right;
Node parent;
KVPair<K,V> kv;
K key;
V value;
public Node(K key, V value) {
this.key = key;
this.value = value;
parent = left = right = sentinel;
}
}
private Node root;
public void add(K key, V value) {
// TODO: Implement me(basic score)
root = add (root, key, value);
}
private Node add(Node x, K key, V value){
if (x == null){
return new Node(key, value); }
int cmp = key.compareTo(x.key);
if (cmp < 0){
x.left = add(x.left, key, value);}
else if (cmp > 0 ){
x.right = add(x.right, key, value);}
else if (cmp == 0){
x.value = value;}
return x;
}
public V get(K key) {
Node x = root;
while (x != null){
int cmp = key.compareTo(x.key);
if (cmp < 0){
x = x.left;}
else if (cmp > 0 ){
x = x.right;}
else if (cmp == 0){
return x.value;}
}
return null;
}
public K next(K key) {
You would need a private method to getNode of key
Then you get successor of that node and return its value
You should also update your "V get(K key)" method to use the getNode(K Key) method to avoid code duplication
I've written all 3 methods below
private Node getNode(K key) {
Node x = root;
while (x != null){
int cmp = key.compareTo(x.key);
if (cmp < 0){
x = x.left;
} else if (cmp > 0 ) {
x = x.right;
} else if (cmp == 0){
return x;
}
}
return null;
}
public K next(K key) {
Node x = getNode(key);
if (x.right != null) {
x = x.right;
while (x.left != null) {
x = x.left;
}
return x.key;
}
Node p = x.parent;
while (p != null && p.right == x) {
p = p.parent;
x = x.parent;
}
return p.key;
}
public V get(K key) {
Node x = getNode(key);
return x==null?null:x.value;
}
When I use MapEntry[] entry = (MapEntry[]) new Object[capacity],
it tells me java.lang.ClassCastException.
How can this happen? I am confused about this. (Since it seems I should do the casting because it's generic)
I found some tutorial and they were using like this:
table = new Entry[capacity];
(http://www.javamadesoeasy.com/2015/02/hashmap-custom-implementation.html)
it did not even do the casting.
My codes are below.
public class MyHashMap<K, V> {
private class MapEntry {
K key;
V value;
MapEntry next;
MapEntry(K key, V value) {
this.key = key;
this.value = value;
}
}
private int size = 0;
private int capacity;
MapEntry[] entry;
#SuppressWarnings("unchecked")
MyHashMap() {
capacity = 10;
entry = (MapEntry[]) new Object[capacity];
}
#SuppressWarnings("unchecked")
MyHashMap(int capacity) {
entry = (MapEntry[]) new Object[capacity];
}
public void put(K key, V value) {
int hash = hashCode(key);
MapEntry newNode = new MapEntry(key, value);
if (entry[hash % capacity] == null) {
entry[hash % capacity] = newNode;
} else {
if (key == entry[hash % capacity].key) {
entry[hash % capacity].value = value;
} else {
MapEntry nextNode = entry[hash % capacity].next;
while (nextNode != null) {
if (key == nextNode.key) {
nextNode.value = value;
return;
}
nextNode = nextNode.next;
}
nextNode = newNode;
}
}
}
public V get(K key) {
int hash = hashCode(key);
MapEntry node = entry[hash % capacity];
if (node == null) {
return null;
}
if (node.key == key) {
return node.value;
}
while (key != node.key) {
node = node.next;
if (node.key == key) {
return node.value;
}
}
return null;
}
public boolean contains(K key) {
return get(key) != null;
}
public int size() {
return size;
}
public void remove(K key) {
int hash = hashCode(key);
MapEntry node = entry[hash % capacity];
if (node == null) return;
if (key == node.key) {
entry[hash % capacity] = node.next;
}
MapEntry pre = node;
while (key != node.key) {
node = node.next;
if (key == node.key) {
pre.next = node.next;
return;
}
pre = pre.next;
}
}
private int hashCode(K key) {
return Math.abs(key.hashCode());
}
public void display(){
for(int i = 0; i < capacity; i++){
if(entry[i] != null){
MapEntry node = entry[i];
while(node != null){
System.out.print("{" + node.key + "=" + node.value + "}" + " ");
node = node.next;
}
}
}
}
public static void main(String[] args) {
MyHashMap<Integer, Integer> hashMapCustom = new MyHashMap<Integer, Integer>();
hashMapCustom.put(21, 12);
hashMapCustom.put(25, 121);
hashMapCustom.put(30, 151);
hashMapCustom.put(33, 15);
hashMapCustom.put(35, 89);
System.out.println("value corresponding to key 21="
+ hashMapCustom.get(21));
System.out.println("value corresponding to key 51="
+ hashMapCustom.get(51));
System.out.print("Displaying : ");
hashMapCustom.display();
System.out.print("Displaying : ");
hashMapCustom.display();
}
}
You can't convert a class of an array by just casting that's yhe reason you get ClassCastException. You should use
`Arrays.copyof ().`
CustomType[]ca=Arrays.copyOf(array,array.length,CustomType[].class);
I have figured out how this work.
(Creation of array whose component type is either a type parameter, a concrete parameterized type or a bounded wildcard parameterized type, is type-unsafe.)
entry = (MapEntry[]) Array.newInstance(MapEntry.class, capacity);
In this way, there can be no errors.
There is another question with good solution.
How to create a generic array in Java?
Right now when I'm inserting Keys/Values into the BST and then searching them I get null values. I would like to get some assistance on how to handle with duplicate keys.
private Node put(Node root, final Key key, final Value value) {
if (root == null)
return new Node(key, value, 1);
final int result = key.compareTo(root.key);
if (result > 0)
root.right = put(root.right, key, value);
else if (result <= 0) {
root.left = put(root.left, key, value);
}
root.size = size(root.left) + size(root.right) + 1;
return root;
}
private Value get(final Node root, final Key key) {
if (root == null)
return null;
final int result = key.compareTo(root.key);
if (result > 0)
return get(root.right, key);
else if (result <= 0)
return get(root.left, key);
return root.value;
}
Your get code needs an == check. Your <= 0 check is grabbing the node to the left where you want < 0. Your == check should return the root.value.
Something like:
private Value get(final Node root, final Key key) {
if (root == null)
return null;
final int result = key.compareTo(root.key);
if (result > 0)
return get(root.right, key);
else if (result < 0)
return get(root.left, key);
else if (result == 0)
return root.value;
else
return null; //key not found
}
Follwing is my java class TestEntry.java
private void initializemapTest()
{
eventMap = new TreeMap<String,String>();
//Put some value into eventMap
mapTest = new TreeMap<String, String>( new Comparator<String>()
{
public int compare( String key1, String key2 )
{
if( key1 == null )
{
if( key2 == null )
{
return 0;
}
else
{
return 1;
}
}
else
{
if( key2 == null )
{
return -1;
}
else
{
return key1.compareTo( key2 );
}
}
}
} );
for( String s : eventMap.keySet() )
{
mapTest.put( eventMap.get( s ), s ); //Error at this line
}
}
As per my knowledge eventMap doesnot allow null values, hence keyset of eventMap does not have any null values,
if value of any key in eventMap is null, while i try to put it in mapTest, it shoukd not throw any null pointer exception, because its respective comparator allows null values
But why am i getting this exception
java.lang.NullPointerException
at java.util.TreeMap.cmp(TreeMap.java:1911)
at java.util.TreeMap.get(TreeMap.java:1835)
at kidiho.sa.client.reports.ReportEntry.initializemapTest(TestEntry.java:22)
It will throw NullPointerException because in TreeMap api get() method is throwing NullPointerException deliberately if that is null.
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
From TreeMap:
final Entry<K,V> getEntry(Object key) {
// Offload comparator-based version for sake of performance
if (comparator != null)
return getEntryUsingComparator(key);
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
Entry<K,V> p = root;
while (p != null) {
int cmp = k.compareTo(p.key);
if (cmp < 0)
p = p.left;
else if (cmp > 0)
p = p.right;
else
return p;
}
return null;
}
That is: TreeMap doesn't allow null keys, so you cannot do:
tm.put(null, something)
And subsequently, you cannot do
tm.get(null)
As according to the TreeMap behaviour, those operations actually don't make sense
As other said, you can't use a null value as a TreeMap key, it will throw a NullPointerException.
You're not getting the NullPointerException from the same place probably because your first map has a registered comparator and the second has none.
This method is supposed to find the smallest value in a Collection that is greater than the key. I keep getting a java.lang.UnsupportedOperationException, and I can't figure out how to fix it. Thanks in advance for any help.
public static <T> T ceiling(Collection<T> c, T key, Comparator<T> comp) {
T ceiling = null;
if (c == null || comp == null) {
throw new IllegalArgumentException();
}
else if (c.size() == 0) {
throw new NoSuchElementException();
}
else {
Iterator<T> itr = c.iterator();
while (itr.hasNext()) {
if (comp.compare(itr.next(), key) < 0) {
itr.remove();
}
}
}
if (c.size() == 0) {
throw new NoSuchElementException();
}
else {
Iterator<T> itr2 = c.iterator();
ceiling = itr2.next();
while (itr2.hasNext()) {
T temp2 = itr2.next();
if (comp.compare(temp2, ceiling) < 0) {
ceiling = temp2;
}
}
}
return ceiling;
}
Most likely you are trying to modify a collection which is unmodifiable.
I suggest you change the method to not modify the collection. (Also I suggest you read the stack trace to understand what it means)
Something like this
public static <T> T ceiling(Collection<T> c, T key, Comparator<T> comp) {
if (c == null || comp == null)
throw new NullPointerException();
T ret = null;
for (T t : c)
if (comp.compare(t, key)>=0 && (ret==null || comp.compare(t, ret)<0))
ret = t;
return ret;
}