Just looking for some advice on my code, im trying to add a Node after a Node contains a specific value. So far i have got it to insert the Node but it seems to skip one Node then insert. So its always inserting one Node too far. Heres the code i came up with...
public void addAfterData(int obj)
{
int dataStop=7;
ListNode newNode = new ListNode();
ListNode insert = new ListNode(obj);
newNode = head;
while(newNode != null && newNode.data != dataStop)
{
newNode = newNode.link;
if(newNode != null)
{
insert.link = newNode.link;
newNode.link = insert;
}
}
}
The normal code to add a new after a node which contains a specific value would be this:
public void addNodeAfterData(Node head, Node node, int data)
{
while (head != null && head.data != data)
{
head = head.next;
}
if (head != null)
{
node.next = head.next;
head.next = node;
}
}
basically what we do here is move the head pointer to the location of the data we're looking, then, when we exit the while loop, we either reached the end because we didnt find the value, so we wont add it (or add it to the end, up to how you define that behavior), or if its not null, so we did find it, and then we make the node we're adding to point to the rest of the list, and we make the current node containing data to our node.
Related
I have a LinkedList full of Book objects which are stored in Nodes, which contain the year of publication and the title of the book. I am trying to sort the list so that it is arranged from oldest year to most recent year, however, after the first Book, the rest of my books now have the same title and year of publication. I believe it has something to do with when I make the swap using my setBook method.
public void sortByYear(){
Node current = head;
Node next = null;
if(isEmpty()){ //if the head is null
return;
}
while(current != null){
next = current.getNext();
while(next != null){
if(current.getBook().getYear() > next.getBook().getYear()){
Book temp = current.getBook();
current.setBook(next.getBook().getYear(), next.getBook().getTitle());
next.setBook(temp.getYear(), temp.getTitle());
// current.getBook() = next;
// next.getBook() = temp;
}
next = next.getNext();
}
current = current.getNext();
}
}
A few issues:
Your setBook method -- taking a year and title -- seems to mutate the book that is assigned to the node. This is not really the right approach. You should define a method that leaves the books untouched, but assigns a different book (all together) to a node.
Bubble sort will always start the inner loop from the first item in the list. The outer loop would only serve to count the number of times the inner loop has to kick in. This is not how you have implemented it. If the minimum node is not in the first or second place, your algorithm will never move it all the way back to the first position.
I would suggest to take a different approach and only mutate the next references in the list, so that you swap nodes as a whole, without having to touch the data at all. For this to work, you need a prev reference that walks "behind" the current node, so that you can rewire the preceding node to the node that gets swapped with the current node.
Here is an implementation:
public void sortByYear(){
if (head == null || head.getNext() == null) {
return;
}
for (Node iter = head; iter != null; iter = iter.getNext()) {
Node prev = null;
Node current = head;
for (Node next = current.getNext(); next != null; next = current.getNext()) {
if (current.getBook().getYear() > next.getBook().getYear()) {
if (prev == null) {
head = next;
} else {
prev.setNext(next);
}
current.setNext(next.getNext());
next.setNext(current);
prev = next;
} else {
prev = current;
current = next;
}
}
}
}
Something you could still work on
It would become even nicer if you would make your Node class comparable. That way the if statement can become more generic and less tied to your book-related implementation.
In the code below, even after deleting a node (20) if I try to print all the nodes by passing deleted node as head in disguise, it is printing all the nodes along with the deleted node. Can someone please explain this behavior along with Garbage Collection in Java? How was it able to iterate all the nodes even though there is no next element for the deleted node (20)?
Node:
class Node{
int nodeint;
Node next;
public Node(int nodeint){
this.nodeint = nodeint;
}
}
LinkedList:
public class linkedlist{
Node head;
//Node next;
public linkedlist(Node obj){
this.head = obj;
}
public Node addnodes(int news){
Node newlink = new Node(news);
newlink.next = head;
head = newlink;
return head;
}
public void printAllNodes(Node obj){
Node current = obj;
while(current!=null){
System.out.println(current.nodeint);
current = current.next;
}
}
public Node remove(){
Node temp = head;
head = head.next;
return temp;
}
public void printHead(){
System.out.println("This is the present head node"+head.nodeint);
}
public static void main(String [] args){
Node obj1 = new Node(2);
Node obj2 = new Node(3);
Node obj3 = new Node(4);
obj1.next = obj2;
obj2.next = obj3;
obj3.next = null;
linkedlist newobj = new linkedlist(obj1);
Node obj = null;
obj = newobj.addnodes(5);
obj =newobj.addnodes(20);
//System.out.println(obj.nodeint);
newobj.printAllNodes(obj);
obj = newobj.remove();
System.out.println("A node is deleted");
newobj.printAllNodes(obj);
newobj.printHead();
}
}
Output of this code:
20
5
2
3
4
A node is deleted
20
5
2
3
4
This is the present head node: 5
The node 20 has still reference to the next node i.e node 5 in this case. It is not related to garbage collection. If you want that behavior set temp.next == null in your remove method.
First you store dependency inside the head node, then you assign new head in you list, but assigned dependency in old head stays as it was. Also remove() method return the old head. And then you print all nodes statring from old head.
Also i would like to admit, that you class looks very stange. I don't understand why internal dependencies shown in outer world. You difenitely need to discover sourcecode of LinkedList from Java libruary
In printAllNodes(), instead of passing the node, do this
public void printAllNodes() {
Node current = head;
while (current != null) {
System.out.println(current.nodeint);
current = current.next;
}
}
And on remove(), return new head node instead of deleted node,
public Node remove(){
Node temp = head;
head = head.next;
temp.next = null; //removing link to next node
return head; //returning head. Not deleted node
}
Explanation: Your remove() function removes head from the linked list you invoke it on, but also returns the deleted head and this former head still has its next property pointing to the next node (which is the current head).
When you called newobj.printAllNodes(obj); you passed the returned former head as the parameter.
Solution 1: You could have called this as newobj.printAllNodes(newobj.head);
Solution 2: Do what #hege_hegedus suggested
Your code works. Look:
This is the present head node: 5
The list still prints 20, because linkedlist.printAllNodes prints the list starting with a parameter, not with it's head. Change your method:
public void printAllNodes() {
Node current = head;
while (current != null) {
System.out.println(current.nodeint);
current = current.next;
}
}
and change the invocations:
newobj.printAllNodes(); // invoke without parameter
I need to implement a circular single-linked list data structure. What I'm having trouble understanding is when and where do I have to state that the final node of the list must point to the first node. I have the following empty constructor to build the list:
public class SList<E> implements IList<E> {
protected SNode<E> firstNode = null;
public SList() {
firstNode = null;
}
So basically each list starts with a null object that points to null again, signifying the end of the list:
public class SNode<E> {
E elem;
public SNode<E> nextNode = null;
...
What I am unaware of however is how to make it so that when the list contains at least one node, that node will point to the first node of the list.
For example, taking a look at this addLast() method that I implemented for my regular linked list:
public void addLast(E newElem) {
SNode<E> newNode= new SNode<E>(newElem);
SNode<E> nodeTraveler = firstNode;
while (nodeTraveler.nextNode != null) {
nodeTraveler= nodeTraveler.nextNode;
}
nodeTraveler.nextNode = newNode;
}
I would have to change it into something like:
public void addLast(E newElem) {
SNode<E> nodeTraveler = firstNode;
SNode<E> newNode = new SNode<E>(newElem);
while (nodeTraveler.nextNode != firstNode){
nodeTraveler = nodeTraveler.nextNode;
}
nodeTraveler.nextNode = newNode;
newNode.nextNode = firstNode;
}
nodeTraveler would stop traversing the list once it's next node matched that of the firstNode (meaning it's at the last position), and then it would change its nextNode to the one we want to add, newNode, and point newNode to the firstNode.
Theoretically, that should work, but since I'm never actually pointing the last element to the first one prior to this method (which is my main question, how to point the last element to the first one by default), I get a nullPointer exception when the code reaches the while iteration.
Any help would be appreciated, thanks.
The only special case is when firstNode == null, which is the initial case.
After that, the first add will give a node whose next element is self:
public void addLast(E newElem) {
SNode<E> newNode = new SNode<E>(newElem);
if(firstNode == null) {
firstNode = newNode;
} else {
SNode<E> traveler = firstNode;
for( ; traveler.nextNode != firstNode ; traveler = traveler.nextNode) {}
traveler.nextNode = newNode;
}
newNode.nextNode = firstNode;
}
class linkedqueue <item_t> {
private class node{
item_t item;
node link;
public node(item_t t, node l){
item=t;
link=l;
}
private node front = null;
private node rear = null;
public void insert (item_t any) {
this.link=new node(any,this.link);
}
the insert method should add "any" to the end of the queue. It works only in the node class, but now it is in the linkedqueue class, I don't know how to fix the "this.link" part..
The last node in the LinkedList will point to a null value. So, grab the last Node in the list, set its next node to the new node you are passing in, and lastly set the new node's next pointer to null, indicating the end of the list.
private void addLast(Node<T> aNode)
{
Node<T> head, lastNode;
head = this.getHead();
mySize++;
if(head == null)
{
this.addFirst(aNode);
}
else
{
lastNode = this.getPrevious(null); // get last Node, which is the Node previous to Null
lastNode.setNext(aNode); // add the new node to the end of the list
aNode.setNext(null); //set the new node's next pointer to null, indicating the end of the list
}
}
"RemoveAll" class is a part of Linked List class. The class I wrote, removes all the keys from a Linked List but it doesn't remove duplicate keys.
Does anybody know why? How I can remove duplicate keys too?
public class LinkedIntList {
private ListNode front;
private String name = "front";
// Constructs an empty list.
public LinkedIntList() {
front = null;
}
public void removeAll(int key){
if(front == null){
throw new RuntimeException();
}else if( front.data == (key)) {
front = front.next;
return;
}
ListNode cur = front;
ListNode prev = null;
while(cur != null && cur.data != (key) ){
prev = cur;
cur = cur.next;
}
if(cur == null)
throw new RuntimeException();
prev.next = cur.next;
}
If you have duplicates, a brute force approach is to keep calling removeAll() until it returns false.
while (myCollection.removeAll(someOthercollection))
; // comment here that the loop does nothing for clarity
ADDED: as #Dukeling correctly points out, you shouldn't have to do this. But if the removeALl() is poorly implemented you may have to.
Well, your method only finds the first matching key, then attempts to remove that item from the list, then returns. Once you find the first match, you're going to have to loop, removing items until you find a key that does not match (or you hit the end of the list).
public void removeAll(T value) {
if (this.front == null) {
return;
}
Node<T> prevNode = null;
Node<T> currNode = this.front;
// If the node we want to remove is front node...
while (currNode.data.equals(value)) {
prevNode = currNode;
currNode = currNode.next;
prevNode.next = null;
}
this.front = currNode;
while (currNode != null) {
if (currNode.data.equals(value)) {
prevNode.next = currNode.next;
currNode.next = null;
} else {
prevNode = currNode;
}
currNode = prevNode.next;
}
}
You need to remove nodes while data == key, so that you make sure to remove all occurrences, not just the first one.
In the lines else if( front.data == (key)) { front = front.next; you are only removing the first occurence. It should be while ( front.data == (key)) { front = front.next;
Here again you are only removing one node:
prev.next = cur.next
You need a while cur.data == key block to adjust the prev and cur nodes to the last occurence of the matching key before calling prev.next = cur.next;. Otherwise you'll be only deleting the first occurrence.