finding loop in linked list using HashMap in java - java

i am writing code for lop detection in linked list using hashmap. why it goes in infinite loop?
boolean hasCycle(Node head) {
HashMap<Integer,Node> map = new HashMap<Integer,Node>();
//<Address,data>
if(head == null || head.next == null)
return false;
Node p = head;
while(p.next!=null)
{
if(map.containsValue(p.next))
{
return true;
}
else
{
map.put(p.data,p.next);
}
p = p.next;
}
return false;
}

Use the Node as key and the data field as value and then check whether the HashMap contains the key:
boolean hasCycle(Node head) {
HashMap<Node,Integer> map = new HashMap<Node,Integer>();
if(head == null || head.next == null)
return false;
Node p = head;
while(p.next!=null) {
if (map.containsKey(p.next)) {
return true;
} else {
map.put(p.next,p.data);
}
p = p.next;
}
return false;
}
And also follow the Java Code Conventions.

Your code calls
map.containsValue(p.next)
This method iterates through the whole map looking for an object that is equal to the passed argument. To do that, it calls your Node.equals() method. It is highly probable that this is where it's going into an infinite loop.
To solve it, you could just use a HashSet of the Node objects (as mentioned in the comments) and check that your equals() and hashCode() methods are correct. But there is also another way to check for cycles, which doesn't involve the use of any extra memory. You just use two iterators, one going at half the speed of the other. If there is a cycle, the faster iterator will lap the slower one.

Have you defined .equals() and .hashCode() on your Node class? if not, it defaults to ==, and if the HashMap makes a copy of your Node as it inserts or moves it in memory, and then your equivalence would fail, because == compares memory addresses.
assuming your node class is akin to
public class Node{
public int data;
public Node next;
}
you could define them as
#Override
public int hashCode(){
int nextData=next.data;
return data^nextData;
}
#Override
public boolean equals(Object other){
boolean equal=false;
if(other!=null&&other instanceof Node){
Node otherNode=(Node)other;
if(otherNode.data==data){
if(otherNode.next==null&&next==null){
equal=true;
}else if(otherNode.next!=null&&next!=null){
if(otherNode.next.data==next.data){
equal=true;
}
}
}
}
return equal;
}

Related

Binary Tree path() Implementation

I am working on a programming assignment that requires us to write a path(root, value) method that returns a LinkedList of Direction Enums (left, right) that leads to the target node (value). We are not allowed to create any new fields to make this happen, which is why I've created a pathHelper() method. One of the tests I'm failing is supposed to return: left, right as the path but it's returning left, right, left, right. I'm not sure why it's counting the steps twice. Any suggestions would be appreciated!
NOTE: This is a Binary Tree, not a BST. We are supposed to use an exhaustive DFS approach.
public static <T> LinkedList<BinaryNode.Direction> path(BinaryNode<T> root, T value) {
if (root == null) {
return null;
} else if (root.payload == value) {
return new LinkedList<>();
}
LinkedList<BinaryNode.Direction> list = new LinkedList<>();
pathHelper(root, value, list);
return list;
}
public static <T> void pathHelper(BinaryNode<T> root, T value, LinkedList<BinaryNode.Direction> list) {
if (root.left != null) {
if (root.payload != value) {
list.add(BinaryNode.Direction.left);
}
pathHelper(root.left, value, list);
} if (root.right != null) {
if (root.payload != value) {
list.add(BinaryNode.Direction.right);
}
pathHelper(root.right, value, list);
}
}
Your code has quite a few errors in it so I'm surprised any test cases are passing. You seem to be storing directions as you search the tree rather than when you find the value.
I suspect you are overcomplicating the problem. If you return a boolean from your helper function based on whether the item is found then you can easily add the directions when you return from the recursion:
private boolean findPath(BinaryNode<T> node, T value, List<BinaryNode.Direction> directions) {
if (node == null) {
return false;
} else if (node.payload.equals(value)) {
return true;
} else if (findPath(node.left, value, directions)) {
directions.add(0, BinaryNode.Direction.LEFT);
return true;
} else if (findPath(node.right, value, directions)) {
directions.add(0, BinaryNode.Direction.RIGHT);
return true;
} else {
return false;
}
}
Note that this inserts the direction at the start of the list to ensure it's in the correct order. This also allows you to detect where the root has the value because it will return true but the path will be empty.

Remove the second appearance of specific object in singly linked list

I am trying to remove the second appearance of specific object in singly linked list.
I have this code for my Node:
public class Node {
Node next;
Object data;
public Node(Object _data)
{
next = null;
data = _data;
}
public Node(Object _data, Node _next)
{
next = _next;
data = _data;
}
public Object getData()
{
return data;
}
public void setData(Object _data)
{
data = _data;
}
public Node getNext()
{
return next;
}
public void setNext(Node _next)
{
next = _next;
}
}
And this is my function to remove:
public void removeSecondAppear(Object data)
{
Node temp = new Node(data);
Node current = head;
boolean found = false;
for(int i = 1; i < size(); i++)
{
current = current.getNext();
if(current.getData().equals(temp.getData()))
{
if(found == true)
{
// remove element
current.setNext(current.getNext().getNext());
listCount--;
break;
}
else if(found == false)
{
found = true;
}
}
}
}
For some reason it won't remove the element. The method to find it works fine, but I don't know why it won't remove the element. I have a similar function to remove element of specific index which works fine:
public boolean remove(int index)
{
if(index < 1 || index > size())
{
return false;
}
Node current = head;
for(int i = 1; i < index; i++)
{
if(current.getNext() == null)
{
return false;
}
current = current.getNext();
}
current.setNext(current.getNext().getNext());
listCount--;
return true;
}
I'm using the same methood, but it won't work in my method to remove the second appearance. Any help what I'm doin wron??
public int indexOf(Object data)
{
Node temp = new Node(data);
Node current = head.getNext();
for(int i = 0; i < size(); i++)
{
if(current.getData().equals(temp.getData()))
{
return i;
}
current = current.getNext();
}
return -1;
}
My implementation:
LinkedList LL = new LinkedList();
LL.add(1);
LL.add(2);
LL.add(3);
LL.add(4);
LL.add(4);
LL.add(5);
LL.removeSecondAppear("4");
My add method:
public void add(Object data)
{
Node temp = new Node(data);
Node current = head;
while(current.getNext() != null)
{
current = current.getNext();
}
current.setNext(temp);
listCount++;
}
My constructor:
public LinkedList()
{
head = new Node(null);
listCount = 0;
}
Your issue is going to be found here (in a couple places):
As you loop through, you will keep advancing current until you find two instances where the data is equal and then remove it. Your remove won't work because you're not actually removing the node you want, it's the next node you're removing, which won't necessarily be equal because you've already iterated over the list and lost the previous equal node.
current = current.getNext();
if(current.getData().equals(temp.getData()))
{
if(found == true)
{
// remove element
current.setNext(current.getNext().getNext()); // this isn't actually removing 'current'...
listCount--;
break;
}
else if(found == false)
{
found = true;
}
}
First thing, you're not resetting found after not finding an equal node.
After the if (equals) block, add:
else {
found = false;
}
Assuming you fix that, here's where you'd end up.
Take the following example:
[3] -> [4] -> [4] -> [5] -> [6]
In your algorithm you will iterate over each element in this list like so:
Pass 1:
found = false
[3] -> [4] -> [4] -> [5] -> [6]
^
current
found = false
Pass 2:
found = false
[3] -> [4] -> [4] -> [5] -> [6]
^
current
found = true
Pass 3:
found = true
[3] -> [4] -> [4] -> [5] -> [6]
^
current
When you get here, you are setting current.next to current.next.next, which is effectively removing [5] from the list, not 4. (consequently, this is also causing your NPE... consider the effects when you get to the end of the list and there is no next.next)
What you want to do is either find the index of your duplicate node and call your existing method to remove an element by the index, or keep a previous node to hold the value of the node that comes before current and when you remove, set previous.setNext(current.getNext()) which will effectively delete current.
Second, you've made use of the equals method for Object, which uses the most discriminating method for determining equality, in that it will only return true for cases where the two compared objects refer to the same object. While this isn't necessarily a problem this can lead to issues depending on the type of data you store. Calling equals on any object will default to the closest implementation of equals for the actual type of data being represented by that object, so if it can't find one, it will default to Objects implementation, which will almost always give a false result if the objects are not the same.
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
Barring that, you might want to change how you compare object data, but I don't think that will really cause you too much of an issue.
Lastly, you will probably want to do some null checking and work your looping algorithm a bit, since this one will have problems if the duplicates are at the head of the list, but this should get you pointed in the right direction.
Here's a cut at a method that can help shed some light on what I've said:
public void removeSecondAppear(Object data)
{
Node temp = new Node(data);
Node current = head;
Node previous = null;
boolean found = false;
while(current != null)
{
// for the sake of argument, let's say this will return true if you find equal data
if( current.getData() != null && current.getData().equals(temp.getData()))
{
if(found)
{
// remove element
previous.setNext(current.getNext());
listCount--;
break;
}
else
{
found = true;
}
}
else {
found = false;
}
previous = current;
current = current.getNext();
}
}
Edit: I've written a small subset of a LinkedList implementation using the OP's Node class definition and used a small test to make sure my removeSecondAppear method works.
public class LinkedList {
private Node head;
public LinkedList() {
head = new Node(0);
}
public LinkedList(Node node) {
head = node;
}
public void add(Node node) {
Node ptr = head;
while ( ptr.getNext() != null ) {
ptr = ptr.getNext();
}
ptr.setNext(node);
}
... /// added removeSecondAppear here, but left out to keep it short(er)
// provided a print() method
}
Using this test:
public class Test {
public static void main(String[] args) {
LinkedList list = new LinkedList(new Node(1));
list.add(new Node(2));
list.add(new Node(4));
list.add(new Node(4));
list.add(new Node(5));
list.print();
list.removeSecondAppearance(4);
list.print();
}
}
My output is:
1 2 4 4 5
1 2 4 5
Adding to pmac89's answer, it would be better if you genericized your node class so that you can use the proper .equals() method for the type of your data:
public class Node<T> {
Node<T> next;
T data;
...
}
From that point essentially you can replace Object with T and Node with Node<T>. When you create a node, you specify its type. Then, say you make a Node<String>. When you call .equals() on the data, it will use String.equals() instead of Object.equals().
The reason you don't want to call Object.equals() is, as pmac89 said, because you are checking if they are the same object. What you really want to check is whether they have the same value.
Edit:
As Ryan J mentioned, if your data is a subclass of Object, it will default to the equals() implementation for that type, if there is one.
Here's the generics tutorial if you aren't familiar with them:
http://docs.oracle.com/javase/tutorial/java/generics/
So the problem is your Node class....
In
public class Node {
...
Object data;
....
}
So when you are calling
if(current.getData().equals(temp.getData()))
in your removeSecondAppear, they will not equal. Remember, Object.equal() on an object is comparing memory locations. None of the list items will equal each other, only the item itself.
EDIT: Also you would want
previous.setNext(current.getNext()) //Oops, fixed a mistake here too!!!
EDIT 2:
Also you are not excluding the thing you are looking for, so you are finding itself. To elaborate on this, think of it this way;
I have the list 1, 2, 3, 4, 4, 5. How many times does it find 4? I am guessing once. The reason being is that each of the list items has an address that does not match the other, as this is saying data is an Object which is assigned a place in memory. So when you call the Object.equals(someOtherObject) you are asking if they have the same location in memory. They do not have the same location in memory. The reason why you are only finding 1 second appearance in your check during the removeSecondAppear is because you are going through the whole list again and not excluding the node that you are looking for.

Issue with Object Comparison in Java (Context is RB Tree)

High, I'm mostly familiar with C & C++ but I've been trying my hand at java recently.
My issue is that line if (parent.leftChild == temp) is never true. Although parent.leftChild.Key = temp.key (and the rest of the contents are the same), I'm under the impression that the issue is that parent.leftChild's ID in Eclipse's debugger = ...5792 while temp's ID is ...3632.
I was hoping that someone could further explain. A workaround to my code can always be to change the if statement to if (parent.leftChild.key = temp.key), but shouldn't parent.left == temp be valid?
class Node{
int key;
char color;
Node leftChild;
Node rightChild;
Node parent;
//...constructors..//
}
private Node GetParent(Node node){
if(node != null)
return node.parent;
else
return null;
}
private void RemoveNodeFromTree(Node myNode){
Node temp = new Node(myNode);
//traverse
if(temp.leftChild!= null){
temp = temp.leftChild;
while(temp.rightChild!= null)
temp = temp.rightChild;
myNode.key = temp.key;
}
else if(temp.rightChild != null)
myNode.key = temp.rightChild.key;
Node parent = GetParent(temp);
Node childL = temp.leftChild;
Node childR = temp.rightChild;
//have parent point to the proper new node.
//parent points to left if it exists, then it tries right.
//if both are null, point to right anyway
if(parent !=null ){
//replace temp with it's left child
if(childL!= null){
if (parent.leftChild == temp)
parent.leftChild = childL;
else
parent.rightChild = childL;
childL.parent = parent;
childL.color = 'B';
if(childL.color == 'B' && temp.color == 'B')
DoubleBlackRestructure(childL, parent);
}
else //replace temp with it's right child
{
if (parent.leftChild == temp)
parent.leftChild = childR;
else
parent.rightChild = childR;
if(childR!= null)
childR.parent = parent;
if((childR == null || childR.color == 'B') && temp.color == 'B')
{
if(childR != null)
childR.color = 'B';
DoubleBlackRestructure(childR, parent);
}
else if (childR != null)
childR.color = 'B';
}
}
else
myNode = null;
temp = null;
}
Every object in Java represents a reference type. Typically, a reference is the memory address at which the object or array is stored. However, since Java references are opaque and cannot be manipulated in any way, this is an implementation detail. Therefore Java doesn't really have pointers like C++ but it has references to objects.
As for your problem, using the workaround you suggested should be the easiest and simplest way to solve your problem. However, if you want to compare objects in Java in general, here is how you do it.
Java has two kinds of object equality:
Object reference equality : when two object references point to the same object.
if (obj1 == obj2) {
// The two object references point to the same object
}
Object value equality : when two separate objects happen to have the same values/state.
if(obj1.equals(obj2)) {
// two object references contain "equal" objects
}
The reason "equal" is in quotes is because it is up to us to say when exactly are two objects equal.
To be able to value-compare two Java objects of the same class, the boolean equals(Object obj) method must be overridden and implemented by the class.
Note that equal objects must have equal hash codes. Therefore, when overriding the equals method, we must also override the hashCode method. Failure to do so violates the general contract for the hashCode method, and any classes that use the hash code, such as HashMap will not function properly.
We decide which values must be equal to consider two objects to be equal. In your case, you could just override the equals() method without the hashCode since you are not putting Node objects in any containers that require a properly implemented hashCode but you should be aware of the possible consequences. The equals() method inside the Node class could compare nodes based on their keys and would look something like:
class Node {
int key;
char color;
Node leftChild;
Node rightChild;
Node parent;
//...constructors..//
boolean equals(Object obj) {
//null instanceof Object will always return false
if (!(obj instanceof Node)) {
return false;
}
// each object is obviously equal to itself
if (obj == this) {
return true;
}
return this.key == ((Node) obj).key;
}
/* This is a simple example of how to override the hashCode as well.
public int hashCode() {
// some code to represent each node uniquely
// i just assume each node has a unique key
return this.key
}
*/
}
Then you can just use the following statement in your code:
if (parent.leftChild.key.equals(temp.key))
The advantage of using equals() implementation is that you can define object equality in many specific ways so it is a quite flexible solution.
Here is a good stackoverflow thread on this
Here is another useful read

The Iterator interface

I have a University assignement that requires me to implement an inner class which implements the Iterator interface. The iterator works on a single-linked list superclass.
Currently my inner class looks like this:
private class ListIterator implements Iterator<V>{
Node temp;
boolean nextCalled = false;
ListIterator(Node fo){
this.temp = fo;
}
#Override
public boolean hasNext() {
if(temp != null){
return true;
}
return false;
}
#Override
public V next() {
nextCalled = true;
return temp.getReprValue();
}
#Override
public void remove() {
if(nextCalled && hasNext()){
nextCalled = false;
removeElement(temp.getReprKey());
temp = temp.getNext();
}
}
}
Now my problem is that the hasNext() method returns true even when the list is actually empty. Everything else seems to work. I have probably overlooked a logic flaw somewhere, but I cannot find it myself.
Changed your implementation to reflect what the Iterator contract needs. You need to remember that you need to be able to iterate over all elements of the collection, i.e., next() should start from the first element and after every call it must change the current next element to the next element in the list or throw an exception if there's none.
It's good to read the Iterator interface doc to undestand the way you need to implement it and start from there.
private class ListIterator implements Iterator<V> {
private Node next;
private boolean alreadyDeleted = false;
ListIterator(Node node){
this.next = node;
}
#Override
public boolean hasNext() {
// because next is the current element. We need to iterate over all the elements
// from the collection.
return next != null;
}
#Override
public V next() {
if (next == null) {
throw new NoSuchElementException();
}
Node current = next;
this.next = current.getNext();
this.alreadyDeleted = false; // it's better to try to elimate this state variable. You can try to do in another way, if yours removeElement returns something
return current;
}
#Override
public void remove() {
if (alreadyDeleted || next == null) {
throw new IllegalStateException();
}
removeElement(next.getReprKey());
this.alreadyRemoved = true;
}
}
You need to keep track of where you are in your list, implement a cursor, or if your nodes in the linked list are aware of their next, just ask them if they have a next element.
When the cursor is bigger then the length / your node has no next you return false in hasNext().
Do all this in your hasNext() method. Remember, it's okay to have next() throw an exception if hasNext() would have been false - so you need to make sure that's the only time it will throw an exception.
As I don't know the underlying data structure of your list, I can't tell you which one of these will be better.
hasNext returns true if the current node (temp) is not null.
If your linked list implementation uses a header node, then the constructor always receives fo!=null and hasNext will return true even though the list is empty. You should consider this fact in your implementation.
Based on your code, it seem that
ListIterator(Node fo){
this.temp = fo.getNext();
}
may do the trick (if header.getNext()==null for an empty list).
To reduce some code, and make it a touch more readable
rename temp to next,
use shortcut notation,
probably should have some concept of the current node,
which makes the update look like:
private Node next;
private Node current; //track deletion
#Override
public boolean hasNext() {
return next != null;
}
public Node getNext() {
if (hasNext()) {
current = next;
next = next.getNextNode();
}
return current;
}
the delete could set current to null. We don't need a flag (assuming that we're fine with doing nothing if a person deletes prior to calling the first getNext(). Heck, if we really want to go for the gold, have remove() throw an IllegalStateException if current == null.

Java : Merging two sorted linked lists

I have developed a code to merge two already sorted linked lists in java.
I need help with the following:
How do I retain the value of head node of merged list without using tempNode?
Can this code be better optimized?
public static ListNode mergeSortedListIteration(ListNode nodeA, ListNode nodeB) {
ListNode mergedNode ;
ListNode tempNode ;
if (nodeA == null) {
return nodeB;
}
if (nodeB == null) {
return nodeA;
}
if ( nodeA.getValue() < nodeB.getValue())
{
mergedNode = nodeA;
nodeA = nodeA.getNext();
}
else
{
mergedNode = nodeB;
nodeB = nodeB.getNext();
}
tempNode = mergedNode;
while (nodeA != null && nodeB != null)
{
if ( nodeA.getValue() < nodeB.getValue())
{
mergedNode.setNext(nodeA);
nodeA = nodeA.getNext();
}
else
{
mergedNode.setNext(nodeB);
nodeB = nodeB.getNext();
}
mergedNode = mergedNode.getNext();
}
if (nodeA != null)
{
mergedNode.setNext(nodeA);
}
if (nodeB != null)
{
mergedNode.setNext(nodeB);
}
return tempNode;
}
1: You have to keep a record of the first node, which means you will have to store it in a variable such as tempNode.
2: No. There's not much to optimize here. The process is quite trivial.
There are a few possibilities:
1) Instead of using mergedNode to keep track of the previous node, use nodeA.getNext().getValue() and nodeB.getNext().getValue(). Your algorithm will become more complex and you will have to deal with a few edge cases, but it is possible to eliminate one of your variables.
2) Use a doubly linked-list, and then use either nodeA.getPrev().getValue() and nodeB.getPrev().getValue() instead of mergedNode. You will also have to deal with edge cases here too.
In order to deal with edge cases, you will have to guarantee that your references can not possibly be null before calling getPrev(), getNext() or getValue(), or else you will throw an exception.
Note that the above modifications sacrifice execution time slightly and (more importantly) simplicity in order to eliminate a variable. Any gains would be marginal, and developer time is far more important than shaving a microsecond or two off of your operation.

Categories