How to initialize Key Class in HashMap in Java - java

I have a question related to Key Type initialization in HashMap. For example, I have defined the below Node class with over-ridden equals() and hashCode() as follows:
public class Node implements Comparable<Node> {
private int Id;
public Node(int i) {
...
}
void setId(int i) {
Id = i;
}
int getId() {
return Id;
}
#Override
public boolean equals(Object o) {
if (o == null) {
throw new NullPointerException();
}
if (o instanceof Node && this != o) {
if (((Node) o).getId() == this.getId())
return true;
}
return false;
}
public int hashCode() {
return Id;
}
}
Now I am building a HashMap with key as type Node as follows:
public class AdjList {
public HashMap<Node,Double> adj;
public AdjList() {
adj = new HashMap<Node,Double>(maxSize);
}
...
}
As you can possibly figure out, I am trying to generate a graph adjacency list with the node class as HashMap.
Now, my question is when I call AdjList() constructor where I create a new HashMap with some maxSize, will it initialize the Node() class as key type? Or I need to separately initialize Node() clas for the key? If I need to initialize Node() in AdjList constructor, then how it can be possible?
Any suggestion will be valuable and useful suggestions will be rewarded.
Thanks,
Somnath

when I call AdjList() constructor where I create a new HashMap with some maxSize, will it initialize the Node() class as key type?
No! You are instantiate the Map with initialCapacity which is the loadFactor value not maxSize (See the documentation).
You may define a method in AddList that adds an entry.
public void add(int i,Double d)
{
adj.put(new Node(i),d);
}
Second, you've implemented Comparable so you must have to define the compareTo method.

There are a number of things that confuse me about your question (even after reading about adjacency lists which I had not heard of before). Firstly why is overriding equals and hash map important? Secondly how does this code form an adjacency list (reading http://en.wikipedia.org/wiki/Adjacency_list) I could not see the relationship between what you have and an adjacency list. I'm also not sure what you are asking when talking about initialising the Node class. It sounds like yoga re confused about some things, I'm just not sure what.
Finally, based on what I read about adjacency lists, I would simply use the following code:
Map<int, List<int>> adjList = new HashMap<int, List<int>>();
Then I can store node 1 with a adjacency list of nodes 2 and 3 as:
adjList.put(1, Arrays.aslist(2,3));
and retrieve then with:
adjList.get(1);
etc, etc. No need for any custom classes at all.

Related

Why Java TreeMap not printing all its inserted entries

Pls tell what is wrong is happening here. I have a Person class which I'm using as a key in TreeMap. I have implemented Comparable also so that TreeMap can do sorting.
public class Person implements Comparable{
private String name;
private int age;
// getters and setters were omitted
#Override
public int compareTo(Object o) {
return 0;
}
}
Now I created TreeMap and added values in it as:
Map treeMap=new TreeMap<Person,Object>();
treeMap.put(new Person(), "String1");
treeMap.put(new Person(), "String2");
treeMap.put(new Person(), "String3");
treeMap.put(new Person(), "String4");
System.out.println(treeMap);
After printing directly using System.out.println(treeMap); Iam only getting the last inserted value ie
Output:{Person#4aa36c=String4}
I know keys should be different but new operator always create a new object so I think its fine. But Iam helpless to figure out what is wrong going on here.
You are likely placing items in the Map backwards and would more than likely want the Person object as the value and the String as the key. But first you need to enhance your Person object with a Constructor to allow you to set the name at least, and maybe the age. Add a constructor to `Person':
public Person(String n, int a){
this.name = n;
this.age = a;
}
Then you can reorder how you add elements to the Map:
Person p1 = new Person("Bob Jones", 32);
treeMap.put(p1.getName(), person);
Additionally, TreeMap uses the compareTo method to determine where to place the entry in the Map for the keys. So, if you intend to use the Person object as the key, you need to implement the compareTo method. But your compareTo method is not implemented correctly and simply returns 0 for every element, causing your elements to overwrite each others location in the Map:
#Override
public int compareTo(Object o) {
/ TODO Auto-generated method stub
return 0;
}
You need to properly implement the method contents (Hence the TODO statement).
Maybe add a social security number (SSN) to the Person class:
Long ssn;
public void setSsn(Long value){
ssn = value;
}
public Long getSsn(){
return ssn;
}
Then you could compare on ssn:
#Override
public int compareTo(Object o) {
if(o == null) return 1;
Person op = (Person)o;
return ssn.compareTo(op.getSsn());
}
But if you just want to create some type of combination with what you have, maybe concatenate the name and age to try to have uniqueness:
#Override
public int compareTo(Object o) {
if(o == null) return 1;
Person op = (Person)o;
return (name + age).compareTo(op.getName() + op.getAge());
}
TreeMap uses compareTo method of Comparable (not equals method from Object) when it tries to put an element into Map. Since your compareTo method implementation returns 0 for all Person objects, there can only be one element in TreeMap.
So when you try to put multiple Person keys, TreeMap only updates value, since for it all Person objects are same (as per your implementation for compareTo).
Here is code snippet for TreeMap.put from Java-8
// 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);
}
So first it checks, whether Comparator is provided, if yes, TreeMap uses compare method to compare keys otherwise it uses compareTo method of Comparable for comparison.
You overrode toCompare method incorrectly. It always returns 0. So, all objects in the tree will be interpreted as the same and your treeMap always contains only the value that had been added the last.
I suggest you consider the compact (but not general as #4castle noted) solution.
#Override
public int compareTo(Person o) {
if (age != o.age) return age > o.age ? 1 : -1;
return name.compareTo(o.name);
}
If you changed the first line of the class declaration to
public class Person implements Comparable<Pesron>
Keys aren't unique based on their memory address, they are unique based on having a unique value. All of your Person objects are practically identical, but what's more, all of your Person objects claim to be "equal" to any other Person object given your current compareTo implementation (0 means equal).
The parameter order for the put method is key first, value second. You need to rearrange the put statements so that something unique is in front (the string), and therefore make all the entries unique.
treeMap.put("String1", new Person());
treeMap.put("String2", new Person());
treeMap.put("String3", new Person());
treeMap.put("String4", new Person());
Now there's no need to implement Comparable or have the compareTo method in Person.
If you require that the Person object be a key, you will have to make each one unique by giving it a unique variable with which to use the compareTo method properly. The best solution is to add a required ID number to each Person object, or otherwise use the name and age as the unique value for the object. Add on this code to Person:
private int id;
private static int numPeople = 0;
public Person() {
numPeople++;
id = numPeople;
name = "";
}
#Override
public int compareTo(Person o) {
if (age != o.age) return age > o.age ? 1 : -1;
if (!name.equals(o.name) return name.compareTo(o.name);
return id > o.id ? 1 : -1;
}
with
public class Person implements Comparable<Person>

How to deal with public/private pair in this binary trees?

The problem is to add a method to this class that reads from a scanner and constructs a tree with the data from the scannerin preorder fashion.
//the class to add the method readTree to
public class IntTree {
private IntTreeNode overallRoot;
...
}
Here is my solution(I have all of the logic down but having trouble with the public private pair)
public void readTree(Scanner s){
overallRoot = readTree(s);
}
private IntTreeNode readTree(Scanner s){
int type = s.nextInt();
IntTreeNode root = new IntTreeNode(s.nextInt());
if(type % 2 == 1){
root.left = readTree(s);
}
if(type==2 || type==3){
root.right= readTree(s);
}
return root;
}
Our style(in general too) is to use a public/private method approach to binary trees. That is take advantage of x=change(x). The return type of the public method should be void(given directions). The return type is IntTreeNode for the private helper because of the returning change(x) part. My question is how would you accompany my set directions of public/private pair, that is write the method signature of the private helper. For my current code, the compiler gives me a duplicate method(i expected that bc the two had the same method signature. I thought about introducing some arbitrary parameter and setting it to null but thought that was bad style. Unlike other problems, you don't need to pass in the int tree node as a parameter bc you don't work with existing data, you're constructing it all from scratch
I think the most straightforward approach would be to name the private method something slightly different, maybe
private IntTreeNode readTreeRecursive(Scanner s)
or
private IntTreeNode readTreeInternal(Scanner s)
is there a reason you can't do something like this?

Can I define my own subclass of java.util.List?

Can I define my own list in Java?
I have my own list-type class that is very similar to a LinkedList, called PersonList.
In another program, I'm using a Comparator, so I need to have a List() object as the parameter.
Is it possible to make the following statement, if I make changes in my code?
List list1= new PersonList();
PersonList doesn't extend or import anything.
You'd need to implement the built in interface java.util.List. It would need to define all the methods listed in the interface java.util.List.
You just have to overload the equals function which is implemented by every
class of Type Object (Every class). The list implementation will use your equals implementation due to the polymorphic concept of OOP.
I strongly recommend to use the given List implemenmtations because they meet all
performance issues you don't even think about. When you have concurrency issues refer to the documentation.
In order to achieve customized comparison you have to implement the Comparable interface
and implement its method toCompare(..);
In this way you can use all given Collection API classes and extend them using your own
comparison or equals algorithm which meets your application needs.
Update to to Comments
class Person implements Compareable {
#override
public int compareTo(Person p) {
return p.age > this.age; //Or whatever
}
#Override
equals(Object person) {
if (person instanceof Person) {
Person p = (Person)person;
if (p.x == this.x &&
p.y == this.y &&
p.address.equals(this.address) {
...
return true;
}
}
return false;
}
}
And now just intialize you list.
List<Person> personList = new ArrayList<Person>();
or
List<Persin> personList = new Vector<Person>();
or
LinkedList<Person> personList = new Queue<Person>();
and and and.
Collections.sort(personList);
To answer the question in the comment, "How would I go about writing my own Comparator for a Linked List?":
public class PersonListComparator implements Comparator<LinkedList> {
#Override
public int compare(LinkedList list1, LinkedList list2) {
// something that returns a negative value if list1<list2, 0 if list1 and
// list2 are equal, a positive value if list1>list2.
}
}
See the javadoc for Comparator, especially the text at the top. This explains what could happen if the compare function could return 0 when list1.Equals(list2) is false. It's not necessarily a problem, depending on how you use it.
Note that I'm still assuming you want to compare entire lists (rather than just individual Persons). Based on later comments, it looks like you want to compare Person objects, but provide different ways to compare ("depending on the different parameter being compared"). You could define more than one class that implements Comparator<Person>. Or you could define a class that takes a parameter when you construct the object:
public enum ComparisonType { NAME, AGE, WEIGHT } // whatever
public class ComparePerson implements Comparator<Person> {
private ComparisonType type;
public ComparePerson(ComparisonType type) {
this.type = type;
}
#Override
public int compare(Person p1, Person p2) {
switch(type) {
case NAME:
// return comparison based on the names
case AGE:
// and so on
...
}
}
}
I haven't tested this, so I could have made a mistake, but you get the idea. Hope this helps, but it's still possible I've misunderstood what you're trying to do.

Java equals override

I intend to override the boolean equals(Object otherObject) method within my Pair class that utilizes a private inner class with private instance variables as follows:
class Pair
{
class Node
{
private int x, y;
}
public boolean equasl(Object otherObject)
{
if(otherObject == null)
{
return false;
}
else if(getClass() != otherObject.getClass())
{
return false;
}
else
{
Pair other = (Pair)otherObject;
return (x.equals(otherObject.x) && y.equals(otherObject.y));
}
}
}
It is not clear to me how I am comparing two Pair objects in which each object is comprised of a doubly-linked list (not shown for clarity). Am I comparing each object beginning with the head node and traversing the lists verifying that each node in the lists are equal?
The Pair class is comparing its value using equals with another pair, rather than doubly linked list. It takes the object which is a Pair object, then checks for null and classtype and finally compares x and y values of Node class inside another pair object.
Let's assume you have an instance variable Node n which is an instance of the inner class. I would recommend restructuring your equals method a little bit:
public boolean equals(Object other) {
if (other == null)
return false;
if (! other instanceof Pair)
return false;
...
}
Beyond that, you need to structurally compare the Node instances inside of each class. Since those are private variables on the Node, you won't be able to access them for other. It might be helpful to define get methods and then just compare the integers.
This is a good guide in general to overriding equals
http://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&cad=rja&ved=0CC0QFjAA&url=http%3A%2F%2Fwww.seas.upenn.edu%2F~cis120%2F13fa%2Flectures%2Flec32.pdf&ei=TI6jUvLTBeeysQSZxoGQCA&usg=AFQjCNFWIq0POyO5CGD7jCTbmKxlYyU5iQ&bvm=bv.57752919,d.cWc

Deciding to use Comparable or Comparator

My program implements a Product class whose objects contain the following instance variables: name, priority, price, and amount.
I have a LinkedList of Product objects that I need to sort before doing any other operations on the LinkedList.
I want to sort the list first by priority (from lowest to highest). If priority is the same, then look at the price (lowest to highest), then the name (alphabetical order).
I have done a lot of reading about Collections.sort, Comparable, and Comparator. I believe I need to use the Comparable interface and implement a compareTo method. My thinking is that because both priority, price, and name have a "natural" ordering it makes more sense to use Comparable.
public class Product extends ProductBase implements PrintInterface, Comparable<Product>{
private String name;
private int priority;
private int cents;
private int quantity;
// setters and getters
/**
* Compare current Product object with compareToThis
* return 0 if priority, price and name are the same for both
* return -1 if current Product is less than compareToThis
* return 1 if current Product is greater than compareToThis
*/
#override
public int compareTo(Product compareToThis)
}
Then when I want to sort my LinkedList I just call Collections.sort(LinkedList). Before I start writing the code, can you tell me if I am I missing or forgetting anything?
*************UPDATE*******************************
I just created a separate class called ProductComparator with a compare method.
This is part of the LinkedList class..
import java.util.Collections;
public class LinkedList {
private ListNode head;
public LinkedList() {
head = null;
}
// this method will sort the LinkedList using a ProductComparator
public void sortList() {
ListNode position = head;
if (position != null) {
Collections.sort(this, new ProductComparator());
}
}
// ListNode inner class
private class ListNode {
private Product item;
private ListNode link;
// constructor
public ListNode(Product newItem, ListNode newLink) {
item= newItem;
link = newLink;
}
}
}
I am getting the following error from the IDE when I compile.
The method sort(List, Comparator) in the type Collections is not applicable for the arguments (LinkedList, ProductComparator).
Does anyone know why I am getting this error and can point me in the right direction to resolve it?
If there is a "natural" ordering, use Comparable. Rule of thumb for figuring out if the ordering is "natural" is, whether the order of the objects will always be that.
Having said that, the decision whether to use Comparable or Camparator is not the kind of decision you need to think too much about. Most IDEs have refactoring tools which makes the conversion between a Comparable and a Comparator very easy. So if you choose to walk the wrong path now, changing that will not require too much effort.
The order you define here on your Product is very specific and
will probably change in future versions of your program
might be enriched with contextual parameterization
won't cover new features
So it can hardly been said "natural".
I'd suggest to define a constant, for example
public static Comparator<Product> STANDARD_COMPARATOR = new Comparator<Product>() {
public int compare(Product p1, Product p1) {
return ...
}
};
then you'll be able to easily sort anywhere with
Collections.sort(myProductList, Product.STANDARD_COMPARATOR);
Your code will evolve in a better manner as you'll add other comparators.
Just like you should generally prefer composition over inheritance, you should try to avoid defining the behavior of your objects in immutable manner.
If your order was based only on numbers, Comparable would be fine.
However, since your order (sometimes) involves lexical order of text,
a Comparator class is better, since use of Comparable would mean using
String.compareTo which would prevent you from having internationalization.
A separate class which implements Comparator can make use of a
localized Collator for comparing Strings. For instance:
public class ProductComparator
implements Comparator<Product> {
private final Collator collator;
public ProductComparator() {
this(Locale.getDefault());
}
public ProductComparator(Locale locale) {
this.collator = Collator.getInstance(locale);
}
public int compare(Product product1,
Product product2) {
int c = product1.getPriority() - product2.getPriority();
if (c == 0) {
c = product1.getPrice() - product2.getPrice();
}
if (c == 0) {
c = collator.compare(product1.getName(), product2.getName());
}
return c;
}
}
Regardless of whether you go with Comparable or Comparator, it is wise
to make sure Product has an equals method which checks the same
attributes as the comparison code.

Categories