I am a bit new to Java and one thing is currently bothering me a bit regarding referencing.
I have a method that returns void. I passed in a linked list to this method. There is another linked list variable called noDuplicateLL that references to the same linked list. noDuplicateLL skips nodes in the linked list.
code:
public static void removeDuplicate(LinkedListNode a) {
LinkedListNode noDuplicateLL = null;
if (a == null) {
//return null;
} else {
HashMap<Integer, Boolean> duplicateCheck = new HashMap<Integer, Boolean>();
while (a != null) {
// check in hashtable O(1)
if (duplicateCheck.containsKey(a.data)) {
noDuplicateLL.next = a.next;
} else {
noDuplicateLL = a;
duplicateCheck.put(a.data, true);
}
// update
a = a.next;
}
}
}
LinkedListNode a gets iterated through the whole list. LinkedListNode noDuplicateLL stops moving once a reaches null. So once this method is done, both pointers are pointing somewhere else in the list, not the front.
The method below prints on the list from beginning to end.
public static void printLinkedList(LinkedListNode head) {
while (head != null) {
System.out.println(head.data);
head = head.next;
}
}
My main:
LinkedListNode LL = LinkedList.randomLinkedList(nodeVal);
removeDuplicate(LL);
printLinkedList(LL);
How come the output still prints from beginning to end of the linked list when LL is passed into the method as a? Is it because a simply points to the nodes in the linked list while LL maintains the reference to the front of the linked list?
LL --> some head node
// invoke method
// LL's value bound to parameter a
a --> some head node
// method executes
a --> head's next
a --> that next's next
...
a --> null
// method exits
LL still points to the original head node.
Is it because a simply points to the nodes in the linked list while LL
maintains the reference to the front of the linked list?
Yes. Read this as soon as you can.
Related
public Object clone() {
LinkedList<E> clone = superClone();
// Put clone into "virgin" state
clone.first = clone.last = null;
clone.size = 0;
clone.modCount = 0;
// Initialize clone with our elements
for (Node<E> x = first; x != null; x = x.next)
clone.add(x.item);
return clone;
}
This is the source code of LinkedList. The clone already has the elements in the original list, what is the purpose of making it empty and assigning the elements again?
The way that a java.util.LinkedList is implemented, is that it uses Node<E> objects to link elements together. And a LinkedList object has a reference to the first and last Node<E> in the list.
If you scroll around a bit you'll find this declaration:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
Visually, a LinkedList with 4 elements can be thought of like this:
When cloning a linked list, what we would expect to happen is that the entire chain of Nodes is copied. Like this:
However, superClone just calls super.clone, which does not make copies of these Node objects. It only copies the LinkedList object. Therefore, it would be incorrect to implement LinkedList.clone by just calling super.clone, because then the cloned list would use the same chain of Nodes as the original:
This would mean that adding something in the middle of the chain would add that thing to both the cloned list, and the original list!
By resetting the cloned list to its initial state, and then re-adding all the elements from the original list, we create a new chain of Node objects for the cloned list. This is because add creates new Node objects:
public boolean add(E e) {
linkLast(e);
return true;
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
The purpose of the clone method is returning a copy of the instance object. They correct meaning of copy is delegated to the implementor class, but main requirement is when
object.clone() != x, it returns true.
In the case of the Java LinkedList, it returns a shallow copy of the elements, but not a copy of the elements theirslef. In this case the list.clone() != list, it's still true, but when you check their elements is going to return false (example list.get(0) != list.clone().get(0)).
The purpose of the copied list is to be not linked to the original one, so you could add/insert/delete elements without modify the original list.
Example (pseudo-code):
original.add(1);
original.add(2);
original.size(); // 2
clonedList = original.clone();
clonedList.size(); // 2
clonedList.add(3);
clonedList.size(); //3
originalList.size(); //2
I have these folowing methods and I want to implement this in a class called LinkedBag
void replace(T oldEntry, T newEntry){}
boolean isDuplicated(T anEntry){}
void doubleBag(){}
void replace(T oldEntry,T newEntry) replaces any entry that is equal to oldEntry with the new entry newEntry. For example,suppose that replace(A,D) is called on this bag {A,B,C,A}. The resulting bag should be {D,B,C,D}
the boolean returns true if the entry anEntry appears more than
one time in the bag and false otherwise. For example, calling isDuplicated(B) on the resulting
bag in part 1 should return false, but isDuplicated(D) should return true.
void doubleBag()adds to the bag a copy of each entry that appears in the bag. For example,
calling doubleBag() on the resulting bag in part 1 should change the bag contents to {4’D, 2’B, 2’C}.
Now so far I though of getting the frequency of a node and checking if the node is duplicated like:
public boolean isDuplicated(T anEntry){
Node currentNode =firstNode;
int counter=0;
while ((counter <numberOfEntries)&&(currentNode!=null))
if(anEntry.equals(currentNode)){
return true;
}
return false;
}
and for the replace method I tried assigning values to another variables then removing them and then reassigning them again but I don't think it's right
T entry=null;
T entry1 = null;
oldEntry=entry;
newEntry=entry1;
remove(oldEntry);
entry=newEntry;
entry1=oldEntry;
add(oldEntry);
add(newEntry);
System.out.println( oldEntry+" , "+newEntry );
}
as for the double bag I still don't know how to do it.
Excuse me for my bad programming I am learning java new, and still learning the basics.
Let's just briefly look at your replace method:
T entry = null;
T entry1 = null;
// entry and entry1 are both null
oldEntry = entry;
newEntry = entry1;
// entry, entry1, oldEntry and newEntry are all null.
remove(oldEntry); // remove null
entry = newEntry; // overwriting null with null
entry1 = oldEntry; // same as previous statement
add(oldEntry); // add null
add(newEntry); // add null again
// print "null , null"
System.out.println(oldEntry + " , " + newEntry);
It's not clear what you're trying to do, but at least what's here is just a bunch of nothing. What you probably want is a little more like this:
// assuming oldEntry and newEntry are set somewhere and are correct,
// and that remove and add work as expected:
remove(oldEntry);
add(newEntry);
// And you'll want to repeat this for as many duplicates as there are of oldEntry.
As for the doubleBag method, you'll want some way to walk over entries, and then duplicate them:
Node currentNode = head;
Node newHead = null;
Node newTail = null;
while (currentNode != null) {
Node first = new Node(currentNode.data);
Node second = new Node(currentNode.data);
first.next = second;
if (newHead != null) {
newTail.next = first;
newTail = second;
} else {
newHead = first;
newTail = second;
}
currentNode = currentNode.next;
}
return newHead;
This code traverses the input list starting at head, creates two copies of the node (named first and second), links them together and appends them to a new list, which it returns at the end.
That should get you started. Also, notice how the traversal works, and see how it differs from your isDuplicated implementation (which currently has an infinite loop). I'll leave it to you to fix your implementation.
I am currently doing a Cracking the Coding Interview Problem (2.4) and I am supposed to partition a linked list around a value x, such that all nodes less than x come before all nodes greater than or equal to x. However, I am really confused as to why a temporary variable "next" is needed and why is node.next nulled below it. Why can't I just do node = node.next at the end of the while loop?
I am simply creating two linked lists, before and after, and merging them together once the correct values are put into each list.
public static Node partition(Node node, int x) {
Node beforeStart = null;
Node beforeEnd = null;
Node afterStart = null;
Node afterEnd = null;
/* Partition list */
while (node != null) {
Node next = node.next;
node.next = null;
if (node.data < x) {
if (beforeStart == null) {
beforeStart = node;
beforeEnd = beforeStart;
} else {
beforeEnd.next = node;
beforeEnd = beforeEnd.next;
}
} else {
if (afterStart == null) {
afterStart = node;
afterEnd = afterStart;
} else {
afterEnd.next = node;
afterEnd = afterEnd.next;
}
}
node = next;
}
/* Merge before list and after list */
if (beforeStart == null) {
return afterStart;
}
beforeEnd.next = afterStart;
return beforeStart;
}
Why can't I just do node = node.next at the end of the while loop?
It can be done this way. After doing the partition, for each list, you need to set the last node's next pointer to NULL. This will just take two lines of code.
The example code is using next = node.next and node.next = NULL to terminate each list during the partition process, but in this case that's not needed, since the lists don't need NULL terminators until after the partition process is done.
The loop in your question removes nodes from the head of the original list, and appends them to the before list or the after list, until the original list is empty. Then it concatenates the before and after lists.
That's easy to explain and easy to understand.
It can be done without the temporary next or nulling out node.next in every iteration, but then the above description would no longer apply -- nodes would not be removed from the original list in every iteration, the before list and after list would not contain only the appropriate nodes, the operation you perform on them is not 'appending', and nodes would even appear in multiple lists for a while.
Your algorithm would suddenly be a lot more difficult to describe and understand. That is a bad thing in software development, and a bad thing in a coding interview.
Please accept my apologies first, but I could not reverse my Linked List in java..
I have class and inner class:
MyList{
class Element{
private Element next;
public Element getNext(){return next;}
}
public void reverseMyList(Element curr) {
if (curr.next == null) {
head = curr.next;
return;
}
reverseMyList(curr.next);
while (curr.next != null) {
curr.next.next = curr.next;
curr.next = null;
}
}//:~
I need to reverse my List, I am using method reverseMyList, which needs Element curr.
If my way of thinking in this case is correct ?
Thank you in advance!
Since this kinda looks like homework, I'm not going to lay out the entire solution here, but I will explain how you should conceptually do it.
Imagine that you have 2 linked lists. You have your input list that you need to reverse, and you have an empty one.
If you keep taking the first element off of the original list, and keep putting that on the front of the new list until your original list is empty, than your new list will be what the original was, except reversed.
public static void Reverse(Element element)
{
Element current = element;
Element next = current.Next;
Element nextToNext;
var first = current;
while (next != null && next.Next != null)
{
nextToNext = next.Next;
next.Next = current;
current = next;
next = nextToNext;
}
if (next != null)
{
next.Next = current;
}
first.Next = null;
}
the method you are looking for already exist in package java.utils:
Collections.reverse(mylist);
this method will change the order of element direcly inside your list and you dont need to instance a new list-object... here you can find more specified documentation
i have a question about circularly linked lists. My linked list object has two references, first and last, and the next node of the last reference is first. I want to write a method that inserts a node into the end of the list.
void insertLast(int k) {
Node a = new Node(k);
if (first == null) {
first = last = a;
} else {
last.after = a;
a.after = first;
}
last = a
}
Is something like this possible? Have I made a mistake?
Yes, it is.
let the current last point to the new one (last.setNext(newNode))
let the new one point to the first (newNode.setNext(first))
set the last to be the new node (last = newNode)