When to initialize a dummy node in a linked list - java

I am implementing a version of singly linked list in Java with a dummy node.
public class Node{
private String data;
private Node nextNode;
public Node(String data){
this.data = data;
this.nextNode = null;
}
//getters, setters, toString()
}
public class LinkedList {
private Node header;
private Node lastNode;
private int size;
public LinkedList() {
this.header = new Node(null);
this.lastNode = this.header;
size = 0;
}
public void prepend(String data) {
if (data == null || data.trim().length() == 0) {
return;
}
Node newNode = new Node(data);
// when the linked list is empty
if (size == 0) {
this.header.setNext(newNode);
this.lastNode = newNode;
} else { // when the list has nodes
Node existingNode = this.header.getNext();
newNode.setNext(existingNode);
this.header.setNext(newNode);
}
size++;
}
}
I am mainly concentrating on this part.
public LinkedList() {
this.header = new Node(null);
this.lastNode = this.header;
size = 0;
}
When a linked list object is created and initialized, header and last node point to a dummy node.
Would this be an efficient way to implement a linked list? Or, do I have to alter my code in prepend() method as follows?
public void prepend(String data) {
if (data == null || data.trim().length() == 0) {
return;
}
Node newNode = new Node(data);
// when the linked list is empty
if (size == 0) {
this.header = new Node(null);
this.header.setNext(newNode);
this.lastNode = newNode;
} else { // when the list has nodes
Node existingNode = this.header.getNext();
newNode.setNext(existingNode);
this.header.setNext(newNode);
}
size++;
}
Also, is it really necessary to use a dummy node as the header? Can we use the first node itself as the header? Under what circumstances should we be using a dummy node, if at all used?

A dummy node is useful if you want to enforce a non-null constraint for the link fields of the node. Further, it allows to implement all operations without the need to implement special cases for the first and last node, e.g.
public class LinkedList {
static final Node REMOVED = new Node();
public static class Node {
Node next, prev;
String data;
Node() {
next = prev = this;
}
Node(String s, Node n, Node p) {
data = s;
next = n;
prev = p;
}
public Node insertBefore(String s) {
if(next == REMOVED) throw new IllegalStateException("removed node");
Node node = new Node(s, this, prev);
prev.next = node;
prev = node;
return node;
}
public Node insertAfter(String s) {
return next.insertBefore(s);
}
public void remove() {
if(next == REMOVED) throw new IllegalStateException("already removed");
prev.next = next;
next.prev = prev;
next = prev = REMOVED;
}
#Override
public String toString() {
return data;
}
}
final Node content = new Node();
private Node first() {
return content.next;
}
private Node last() {
return content.prev;
}
public Node getFirst() {
Node f = first();
if(f == content)
return null; // or throw new NoSuchElementException(string);
return f;
}
public Node getLast() {
Node f = last();
if(f == content)
return null; // or throw new NoSuchElementException(string);
return f;
}
public Node prepend(String s) {
return first().insertBefore(s);
}
public Node append(String s) {
return last().insertAfter(s);
}
public Node findFirst(String string) {
for(Node n = first(); n != content; n = n.next) {
if(n.data.equals(string)) return n;
}
return null; // or throw new NoSuchElementException(string);
}
public Node findLast(String string) {
for(Node n = last(); n != content; n = n.prev) {
if(n.data.equals(string)) return n;
}
return null; // or throw new NoSuchElementException(string);
}
void printForward() {
for(Node n = first(); n != content; n = n.next) {
System.out.println(n.data);
}
}
void printBackward() {
for(Node n = last(); n != content; n = n.prev) {
System.out.println(n.data);
}
}
}
This is a doubly linked list whose internally used dummy node’s next and prev fields become the “first” and “last” fields of the list. This way, all modification methods only have to operate on the Node class and its next and prev fields and the references to the first and last node are treated the right way automatically. Note how all modification methods settle atop only two implementation methods, insertBefore and remove.
It can be use like
LinkedList l = new LinkedList();
l.append("H").insertAfter("l").insertAfter("l");
l.findFirst("l").insertBefore("e");
l.findLast("l").insertAfter("o");
l.printForward();
System.out.println();
l.getFirst().remove();
l.findFirst("l").remove();
l.getFirst().remove();
l.getLast().insertBefore("r");
l.getFirst().insertBefore("d");
l.append("W");
l.printBackward();
for example. For a single linked list, a dummy node might be less useful. If, like in your example, you’re not drawing a benefit from it but have all the special case handling, you should not use a dummy node which only makes the code even more complicated.

Related

Problem with printing own Linked List and implementing 2 methods

I created my own Linked List using nodes, and I have few methods to do.
Methods in main:
//List<Person> females = peopleFromWarsaw.getWithFilter(p -> p.getName().endsWith("a"));
// Dont know how to implements this methods.
// ObjectContainer.removeIf(p -> p.getAge() > 50);
// peopleFromWarsaw.storeToFile("youngPeopleFromWarsaw.txt",
// p -> p.getAge() < 30, p -> p.getName() + ";" + p.getAge() + ";" + p.getCity());
At the begging i made a linked list and tried to print elements from list but doesnt work.
At first it looks like it doesn't have a method toString but class Person has toString. I guess the program takes the node but I want to print object.
Maybe u can see what is the problem with code, basically nodes and methods in Object Container are fine.
Secondly i have a problem with implementing methods in main (getWithFilter,removeIf and storeToFile)
No matter how I write method in ObjectContainer, always intelij tells me that cannot use lambda and underline p.getName (p -> p.getName().endsWith("a"));
In class Person i have getters and setters with fields name,age.
Maybe someone could explain how properly write this methods ?
public class ObjectContainer<T> {
private Node head;
private Node tail;
private final Predicate<T> predicate;
public ObjectContainer(Predicate<T> predicate) {
this.predicate = predicate;
}
static class Node {
private Object object;
private Node next;
Node(Object object) {
this.object = object;
}
}
public void add(T object) {
if (!predicate.test(object)) {
throw new IllegalArgumentException("Element can not be added");
}
Node newNode = new Node(object);
if (head == null) {
head = newNode;
tail = newNode;
} else {
tail.next = newNode;
tail = newNode;
}
}
public int size() {
int count = 0;
Node current = head;
while (current != null) {
count++;
current = current.next;
}
return count;
}
public void push(T new_data) {
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
public void insertAfter(Node prev_node, T new_data) {
if (prev_node == null) {
System.out.println("The given previous node cannot be null");
return;
}
Node new_node = new Node(new_data);
new_node.next = prev_node.next;
prev_node.next = new_node;
}
public void append(T new_data) {
Node new_node = new Node(new_data);
if (head == null) {
head = new Node(new_data);
return;
}
new_node.next = null;
Node last = head;
while (last.next != null)
last = last.next;
last.next = new_node;
return;
}
public void printList() {
Node tnode = head;
while (tnode != null) {
tnode = tnode.next;
System.out.println(tnode);
}
}
}
Probably you don't want to print the node, but the object contained within. Also, you want to print the first object, too. That is
public void printList() {
Node tnode = head;
while (tnode != null) {
System.out.println(tnode.object);
tnode = tnode.next;
}
}

Add and Print new Nodes

I was working on a program to add nodes to a list, but I seem to be doing something wrong...
My java program has three Classes; Demo, Lista and Node
Class Node:
public class Node {
private int num;
private Node tail;
private Node head;
public Node (int num, Node head, Node tail) {
this.num = num;
this.head = head;
this.tail = tail;
}
}
Class Lista:
public class Lista {
private Node nil;
public Lista () {
nil = null;
}
public void add (int num) {
Node newNode = new Node(num, head, tail);
if (head == null) {
head = newNode;
tail = newNode;
}
}
public void display () {
Node current = head;
while(current != null) {
System.out.print(current.num);
}
}
}
Class Demo:
public class Demo {
public static void main ( String [] args) {
Lista lista = new Lista();
lista.add(3);
lista.add(9);
lista.add(7);
lista.display();
}
}
Demo class is to add the different nodes to the list "lista". Class Node has num, head which is the next one and tail which is the previous one. How can I go about getting Class Lista to be able to use head and tail from Class Node? And if it is possible would this code work when running Demo? What should I change/modify to get this to work?
You may want to modify your code something like this:
EDIT - This is a doubly-linked list implementation.
class Node {
int num;
Node prev;
Node next;
Node(int num) {
this.num = num;
}
Node(int num, Node prev, Node next) {
this.num = num;
this.prev = prev;
this.next = next;
}
void setPrev(Node prev) {
this.prev = prev;
}
void setNext(Node next) {
this.next = next;
}
}
class Lista {
Node root;
Node endNode;
public void add(int num) {
Node n = new Node(num);
if (root == null) {
root = n;
} else {
n.setPrev(endNode);
endNode.setNext(n);
}
endNode = n;
}
public void display() {
Node iterateeNode = root;
while (iterateeNode != null) {
System.out.print(iterateeNode.num + " ");
iterateeNode = iterateeNode.next;
}
}
}
The selected answer is technically not correct. For a (single) Linked List, all your Lista need is a single (head) node. Additionally, the Node class needs a single (next) Node field.
The following is a potential implementation of Node:
public class Node {
private Node next;
private int value;
public Node(int value) {
this.value = value;
}
public boolean hasNext() {
return next != null;
}
public Node next() {
return next;
}
public void add(Node node) {
if (next == null) {
next = node;
} else {
Node temp = next;
while (temp != null) {
temp = temp.next;
}
temp = node;
}
}
#Override
public String toString() {
return String.valueOf(value);
}
}
The add() method will insert the new node in next if it is null. Otherwise, it will traverse the nodes until it finds the tail node (the one where next is null).
The Lista has only the first element in the list (head node).
public class Lista {
private Node head;
public void add(Node node) {
if (head == null) {
head = node;
} else {
Node temp = head;
while (temp.hasNext()) {
temp = temp.next();
}
temp.add(node);
}
}
// Other methods
}
When the add() function in the list is called, it will either add the new node as the head (if the list doesn't have one already) or rely on the already added nodes to figure out where the end of the list is in order to insert the new node.
Lastly, to display the list, just override the toString() method in node and add the "toString" value to a string buffer and send the concatenated string value to the console similar to the the code below.
public void display() {
StringBuilder buff = new StringBuilder("[");
buff.append(head);
if (head != null) {
Node next = head.next();
buff.append(",");
while (next != null) {
buff.append(next);
next = next.next();
buff.append(",");
}
}
buff.append("]");
int idx = buff.lastIndexOf(",");
buff.replace(idx, idx+1, "");
System.out.println(buff.toString());
}
Executing the following displays [3,9,7] as expected.
public class Demo {
public static void main ( String [] args) {
Lista lista = new Lista();
lista.add(new Node(3));
lista.add(new Node(9));
lista.add(new Node(7));
lista.display();
}
}

How to remove from a Linked list in Java?

So I wrote my own linked list (and list node) in Java as a part of a homework.
Now, I'm trying to erase entries, but the function is not working.
I know the concept:
Search for node keeping the previous;
Tell previous node to point to next node;
Return or stop using the node so GC erases it.
For some reason it is not working. I can delete the node with the same value over and over. I'm afraid it is something related to Java pointers.
The code:
Node:
public class SimpleNode<E> {
private E value;
private SimpleNode<E> next;
public SimpleNode() {
this.value = null;
this.next = null;
}
public NoSimples(E data, SimpleNode<E> ref) {
this.value = data;
this.next = ref;
}
// Getters and Setters
}
List:
public class LinkedList<E> implements Iterable<SimpleNode<E>> {
private SimpleNode<E> head;
private int size = 0;
public LinkedList() {
this.head = new SimpleNode<E>();
}
public void add(SimpleNode<E> node) {
this.addFirst(node.getValue());
}
public void addFirst(E item) {
SimpleNode<E> nonde = new SimpleNode<E>(item, this.head);
this.head = node;
size++;
}
public void add(E value) {
this.addFirst(value);
}
public SimpleNode<E> removeFirst() {
SimpleNode<E> node = this.head;
if (node == null) {
return null;
} else {
this.head = node.getNext();
node.setNext(null);
this.size--;
return node;
}
}
public SimpleNodes<E> remove(E value) {
SimpleNode<E> nodeAnt = this.head;
SimpleNode<E> node = this.head.getNext();
while (node != null) {
if (node.getValue()!= null && node.getValue().equals(value)) {
nodeAnt.setNext(node.getNext());
node.setNext(null);
return node;
}
nodeAnt = node;
node = node.getNext();
}
return null;
}
// Other irrelevant methods.
}
Multiple Problems :
Think if you have a list 1,2,3,4. Now, if you try to remove 1, your code fails.
nodeAnt = node should be nodeAnt = nodeAnt.getNext(). Remember, the're all references, not Objects
Also, a recursive way might be easier to understand. For example, Here is how I implemented it
public void remove(E e){
prev = head;
removeElement(e, head);
System.gc();
}
private void removeElement(E e, Node currentElement) {
if(currentElement==null){
return;
}
if(head.getData().equals(e)){
head = head.getNext();
size--;
}else if(currentElement.getData().equals(e)){
prev.setNext(currentElement.getNext());
size--;
}
prev = prev.getNext();
removeElement(e, currentElement.getNext());
}
Note: I delete all occurrences of the Element, as I needed it. You may need it to be different.

Linked List Wrong Output Java

Hey ya'll I am having a little trouble with my singly linked list. I decided to create a simple one because we do not get enough practice during my data structures class and cannot seem to find why I am not getting the right output.
The code is:
package linked_list;
public class LinkedList {
private Node head;
private Node tail; // After figuring out head, come back to this FIXME
private int listSize;
public LinkedList() {
head = new Node(null);
tail = new Node(null);
}
public void addLast(String s) {
Node newNode = new Node(s);
if (head == null) {
addFirst(s);
} else {
while (head.next != null) {
head = head.next;
}
head.next = newNode;
tail = newNode;
}
listSize++;
}
public void addFirst(String s) {
Node newNode = new Node(s);
if (head == null) {
head = newNode;
tail = newNode;
}
else {
newNode.next = head;
head = newNode;
}
listSize++;
}
public Object getFirst() {
return head.data;
}
public Object getLast() {
return tail.data;
}
public void clear() {
head = null;
tail = null;
listSize = 0;
}
public Object peek() {
try {
if (head == null) {
throw new Exception ("The value is null");
}
else {
return head;
}
} catch (Exception e) {
System.out.println(e.getMessage());
return null;
}
}
public int size() {
return listSize;
}
// This class has the ability to create the nodes that are used
// in the Linked List.
private class Node {
Node next;
Object data;
public Node(String value) {
next = null;
data = value;
}
public Node(Object value, Node nextValue) {
next = nextValue;
data = value;
}
public Object getData() {
return data;
}
public void setData(Object dataValue) {
data = dataValue;
}
public Node getNext() {
return next;
}
public void setNext(Node nextValue) {
next = nextValue;
}
}
}
Now here is my driver that I created to run a simple little operation:
package linked_list;
public class LinkedListDriver {
public static void main(String[] args) {
LinkedList list1 = new LinkedList();
list1.clear();
list1.addLast("This goes last");
list1.addFirst("This goes first");
list1.addLast("Now this one goes last");
System.out.println(list1.getFirst());
System.out.println(list1.getLast());
}
}
My output is this:
This goes last
Now this one goes last
I guess my question is why am I not getting the answer This goes first from my getFirst() method. It seems to be something wrong with the order or structure of that method but I cannot pinpoint it.
When you are in the else in the addLast, you are changing the reference to head. You should use another reference pointer to traverse the list when adding in the else.
Also, your list size should only be incremented in the else in addLast because you are incrementing twice otherwise (once in addFirst and again after the if-else in addLast).

Iterating over a linked list in Java?

I have been diligently watching YouTube videos in an effort to understand linked lists before my fall classes start and I am uncertain how to proceed with iterating over the following linked list. The 'node' class is from a series of videos (same author), but the 'main' method was written by me. Am I approaching the design of a linked list in an illogical fashion (assuming of course one does not wish to use the predefined LinkedList class since the professor will expect each of us to write our own implementation)?:
class Node
{
private String data;
private Node next;
public Node(String data, Node next)
{
this.data = data;
this.next = next;
}
public String getData()
{
return data;
}
public Node getNext()
{
return next;
}
public void setData(String d)
{
data = d;
}
public void setNext(Node n)
{
next = n;
}
public static String getThird(Node list)
{
return list.getNext().getNext().getData();
}
public static void insertSecond(Node list, String s)
{
Node temp = new Node(s, list.getNext());
list.setNext(temp);
}
public static int size(Node list)
{
int count = 0;
while (list != null)
{
count++;
list = list.getNext();
}
return count;
}
}
public class LL2
{
public static void main(String[] args)
{
Node n4 = new Node("Tom", null);
Node n3 = new Node("Caitlin", n4);
Node n2 = new Node("Bob", n3);
Node n1 = new Node("Janet", n2);
}
}
Thanks for the help,
Caitlin
There are some flaws in your linked list as stated by some of the other comments. But you got a good start there that grasps the idea of a linked list and looks functional. To answer your base question of how to loop over this particular implemention of the linked list you do this
Node currentNode = n1; // start at your first node
while(currentNode != null) {
// do logic, for now lets print the value of the node
System.out.println(currentNode.getData());
// proceed to get the next node in the chain and continue on our loop
currentNode = currentNode.getNext();
}
Maybe this will be useful:
static void iterate(Node head) {
Node current = head;
while (current != null) {
System.out.println(current.getData());
current = current.getNext();
}
}
// or through recursion
static void iterateRecursive(Node head) {
if (head != null) {
System.out.println(head.getData());
iterateRecursive(head.getNext());
}
}
class List {
Item head;
class Item {
String value; Item next;
Item ( String s ) { value = s; next = head; head = this; }
}
void print () {
for( Item cursor = head; cursor != null; cursor = cursor.next )
System.out.println ( cursor.value );
}
List () {
Item one = new Item ( "one" );
Item two = new Item ( "three" );
Item three = new Item ( "Two" );
Item four = new Item ( "four" );
}
}
public class HomeWork {
public static void main( String[] none ) { new List().print(); }
}
Good luck!!
You can have your linked list DS class implement 'Iterable' interface and override hasNext(), next() methods or create an inner class to do it for you. Take a look at below implementation:
public class SinglyLinkedList<T>{
private Node<T> head;
public SinglyLinkedList(){
head = null;
}
public void addFirst(T item){
head = new Node<T>(item, head);
}
public void addLast(T item){
if(head == null){
addFirst(item);
}
else{
Node<T> temp = head;
while(temp.next != null){
temp = temp.next;
}
temp.next = new Node<T>(item, null);
}
}
private static class Node<T>{
private T data;
private Node<T> next;
public Node(T data, Node<T> next){
this.data = data;
this.next = next;
}
}
private class LinkedListIterator implements Iterator<T>{
private Node<T> nextNode;
public LinkedListIterator(){
nextNode = head;
}
#Override
public boolean hasNext() {
return (nextNode.next != null);
}
#Override
public T next() {
if(!hasNext()) throw new NoSuchElementException();
T result = nextNode.data;
nextNode = nextNode.next;
return result;
}
}
}

Categories

Resources