Java - Functional Programming (Map, Filter) - java

I am just getting started with functional programming in Java. I'd like some help with a simple exercise to get up to speed.
Suppose one has the following two interfaces:
interface P {
boolean filter(int v);
}
interface F {
int apply(int v);
}
and one is required to create a map function that takes a function f as an argument and returns a Node that applies f to all elements. Secondly, one is required to create a filter function that returns a Node with all elements that match a predicate p within the Following class:
public class Node {
private int item;
private Node next;
public Node(int item, Node next){
this.item = item;
this.next = next;
}
/* Create a new Node that applies function f to all elements */
public Node map(F f){
}
/* Creates a new Node with all elements that match predicate p */
public Node filter(P p){
}
}

public Node map(F f){
Node start = new Node(f.apply(item), null);
Node current = start;
for(Node originalNode = this.next; originalNode != null; originalNode = originalNode.next) {
Node copyOfNextNode =new Node(f.apply(originalNode.item), null);
current.next = copyOfNextNode;
current = current.next;
}
return start;
}
/* Creates a new Node with all elements that match predicate p */
public Node filter(P p){
Node start = null;
Node current = null;
for(Node originalNode = this; originalNode != null; originalNode = originalNode.next) {
if(p.filter(originalNode.item)) {
Node copyOfNextNode =new Node(originalNode.item, null);
if(current == null) {
current = copyOfNextNode;
start = current;
} else {
current.next = copyOfNextNode;
current = current.next;
}
}
}
return start;
}

Related

write a function to add to the end of linked list [duplicate]

I'm studying for an exam, and this is a problem from an old test:
We have a singly linked list with a list head with the following declaration:
class Node {
Object data;
Node next;
Node(Object d,Node n) {
data = d;
next = n;
}
}
Write a method void addLast(Node header, Object x) that adds x at the end of the list.
I know that if I actually had something like:
LinkedList someList = new LinkedList();
I could just add items to the end by doing:
list.addLast(x);
But how can I do it here?
class Node {
Object data;
Node next;
Node(Object d,Node n) {
data = d ;
next = n ;
}
public static Node addLast(Node header, Object x) {
// save the reference to the header so we can return it.
Node ret = header;
// check base case, header is null.
if (header == null) {
return new Node(x, null);
}
// loop until we find the end of the list
while ((header.next != null)) {
header = header.next;
}
// set the new node to the Object x, next will be null.
header.next = new Node(x, null);
return ret;
}
}
You want to navigate through the entire linked list using a loop and checking the "next" value for each node. The last node will be the one whose next value is null. Simply make this node's next value a new node which you create with the input data.
node temp = first; // starts with the first node.
while (temp.next != null)
{
temp = temp.next;
}
temp.next = new Node(header, x);
That's the basic idea. This is of course, pseudo code, but it should be simple enough to implement.
public static Node insertNodeAtTail(Node head,Object data) {
Node node = new Node(data);
node.next = null;
if (head == null){
return node;
}
else{
Node temp = head;
while(temp.next != null){
temp = temp.next;
}
temp.next = node;
return head;
}
}
If you keep track of the tail node, you don't need to loop through every element in the list.
Just update the tail to point to the new node:
AddValueToListEnd(value) {
var node = new Node(value);
if(!this.head) { //if the list is empty, set head and tail to this first node
this.head = node;
this.tail = node;
} else {
this.tail.next = node; //point old tail to new node
}
this.tail = node; //now set the new node as the new tail
}
In plain English:
Create a new node with the given value
If the list is empty, point head and tail to the new node
If the list is not empty, set the old tail.next to be the new node
In either case, update the tail pointer to be the new node
Here is a partial solution to your linked list class, I have left the rest of the implementation to you, and also left the good suggestion to add a tail node as part of the linked list to you as well.
The node file :
public class Node
{
private Object data;
private Node next;
public Node(Object d)
{
data = d ;
next = null;
}
public Object GetItem()
{
return data;
}
public Node GetNext()
{
return next;
}
public void SetNext(Node toAppend)
{
next = toAppend;
}
}
And here is a Linked List file :
public class LL
{
private Node head;
public LL()
{
head = null;
}
public void AddToEnd(String x)
{
Node current = head;
// as you mentioned, this is the base case
if(current == null) {
head = new Node(x);
head.SetNext(null);
}
// you should understand this part thoroughly :
// this is the code that traverses the list.
// the germane thing to see is that when the
// link to the next node is null, we are at the
// end of the list.
else {
while(current.GetNext() != null)
current = current.GetNext();
// add new node at the end
Node toAppend = new Node(x);
current.SetNext(toAppend);
}
}
}
loop to the last element of the linked list which have next pointer to null then modify the next pointer to point to a new node which has the data=object and next pointer = null
Here's a hint, you have a graph of nodes in the linked list, and you always keep a reference to head which is the first node in the linkedList.
next points to the next node in the linkedlist, so when next is null you are at the end of the list.
The addLast() needs some optimisation as the while loop inside addLast() has O(n) complexity. Below is my implementation of LinkedList. Run the code with ll.addLastx(i) once and run it with ll.addLast(i) again , you can see their is a lot of difference in processing time of addLastx() with addLast().
Node.java
package in.datastructure.java.LinkedList;
/**
* Created by abhishek.panda on 07/07/17.
*/
public final class Node {
int data;
Node next;
Node (int data){
this.data = data;
}
public String toString(){
return this.data+"--"+ this.next;
}
}
LinkedList.java
package in.datastructure.java.LinkedList;
import java.util.ArrayList;
import java.util.Date;
public class LinkedList {
Node head;
Node lastx;
/**
* #description To append node at end looping all nodes from head
* #param data
*/
public void addLast(int data){
if(head == null){
head = new Node(data);
return;
}
Node last = head;
while(last.next != null) {
last = last.next;
}
last.next = new Node(data);
}
/**
* #description This keep track on last node and append to it
* #param data
*/
public void addLastx(int data){
if(head == null){
head = new Node(data);
lastx = head;
return;
}
if(lastx.next == null){
lastx.next = new Node(data);
lastx = lastx.next;
}
}
public String toString(){
ArrayList<Integer> arrayList = new ArrayList<Integer>(10);
Node current = head;
while(current.next != null) {
arrayList.add(current.data);
current = current.next;
}
if(current.next == null) {
arrayList.add(current.data);
}
return arrayList.toString();
}
public static void main(String[] args) {
LinkedList ll = new LinkedList();
/**
* #description Checking the code optimization of append code
*/
Date startTime = new Date();
for (int i = 0 ; i < 100000 ; i++){
ll.addLastx(i);
}
Date endTime = new Date();
System.out.println("To total processing time : " + (endTime.getTime()-startTime.getTime()));
System.out.println(ll.toString());
}
}
The above programs might give you NullPointerException. This is an easier way to add an element to the end of linkedList.
public class LinkedList {
Node head;
public static class Node{
int data;
Node next;
Node(int item){
data = item;
next = null;
}
}
public static void main(String args[]){
LinkedList ll = new LinkedList();
ll.head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
Node fourth = new Node(4);
ll.head.next = second;
second.next = third;
third.next = fourth;
fourth.next = null;
ll.printList();
System.out.println("Add element 100 to the last");
ll.addLast(100);
ll.printList();
}
public void printList(){
Node t = head;
while(n != null){
System.out.println(t.data);
t = t.next;
}
}
public void addLast(int item){
Node new_item = new Node(item);
if(head == null){
head = new_item;
return;
}
new_item.next = null;
Node last = head;
Node temp = null;
while(last != null){
if(last != null)
temp = last;
last = last.next;
}
temp.next = new_item;
return;
}
}

Adding Node to Initially Null LinkedList

I'm having issues when I try to add a node to a linked list that is initialized to null. In my method I set a test case to check if the node is initially null and if so it creates a new node with the value that was passed in. But for whatever reason it doesn't work unless the node has atleast one element already passed in. Check it out:
Node addNode(Node node, int val)
{
if(node == null)
{
Node newNode = new Node(val);
//node = newNode;
return newNode;
}
node.next = addNode(node.next, val);
return node;
}
//Driver Class
Scanner in = new Scanner(System.in);
Node myNode = new Node(1);
int numEntries = in.nextInt();
for(int i = 0 ; i < numEntries ; i++)
{
int inputVal = in.nextInt();
myNode.addNode(myNode, inputVal);
}
The above code will not run if myNode is initialized to a null value (Node myNode = null;)
Full Code:
/* package whatever; // don't place package name! */
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static class Node
{
private int value;
Node next;
public Node()
{
next = null;
}
public Node(int val)
{
value = val;
next = null;
}
Node addNode(Node node, int val)
{
if(node == null)
{
Node newNode = new Node(val);
//node = newNode;
return newNode;
}
node.next = addNode(node.next, val);
return node;
}
}
public static void main (String[] args) throws java.lang.Exception
{
Scanner in = new Scanner(System.in);
Node myNode = new Node(1);
Node current = null;
Node oddFirst = new Node(1);
int numEntries = in.nextInt();
for(int i = 0 ; i < numEntries ; i++)
{
int inputVal = in.nextInt();
myNode.addNode(myNode, inputVal);
}
current = myNode;
while(current != null) // Check if values were copied correctly
{
if(oddFirst == null)
{
oddFirst = new Node(current.value);
}
oddFirst.addNode(oddFirst,current.value);
//oddFirst = current.next;
//oddFirst = oddFirst.next;
current = current.next.next;
}
while(oddFirst != null)
{
System.out.println("Current Value: " + oddFirst.value);
oddFirst = oddFirst.next;
}
}
}
A simple solution for a linked list:
class Node {
int val;
Node next;
}
public class LinkedList {
public Node first;
public Node last;
public void addNext(int val) {
Node node = new Node();
node.val = val;
if(last == null) {
first = last = node;
}
else {
last.next = node;
last = node;
}
}
}
The main issue with the original code is that it doesn't concern itself with the case of the empty list.
You cannot discern the case where the list is comprised of a single 1 value, and the empty list.
Because you're not handling the return value of addNode().
You're returning a Node in the following function:
Node addNode(Node node, int val)
but you're not handling the return here:
myNode.addNode(myNode, inputVal);
This should help you figure out the solution.

How position based sequence ADT inserts an element in O(1) time?

I was reading about position based sequences. (Michael T.Goodrich) chapter-4 (Sequences).
What I understood is that the positional sequence keeps on adding nodes in linear order. (Based on the Doubly linked list ) moreover, each node may point to some other node/s.
For example, take a simple tree having four nodes a,b,c,d implemented by positional sequence.P (having nodes p1,p2,p3,p4)
Now if I want to add new tree node "e" as the right child of "b."For this I will add this node in p5, then I will make references of e.
Book says it adds a node in O(1) time.
My point is, To add e as right child of b, don't we need the position of b which we will get from the position of "a"(link hopping). How come it is not O(n).
one of the solution I found in Stackoverflow itself is the following code...
public interface Position{
Object element();
}
Make a class Node which implements Position interface:
public class Node implements Position {
private Object data;
private Node next;
private Node prev;
public Node(Node prev, Object data, Node next){
this.prev = prev;
this.data = data;
this.next = next;
}
public Object element() // Method of interface Position
{
return data;
}
public void setData(Object data)
{
this.data = data;
}
public void setNext(Node next)
{
this.next = next;
}
public void setPrev(Node prev)
{
this.prev = prev;
}
public Node getNext()
{
return next;
}
public Node getPrev()
{
return prev;
}
}
Make a class List implementing the List ADT:
// this is a List ADT implemented using a Doubly Linked List
public class List{
private Node first;
private Node last;
private int size;
List()
{
first = null;
last = null;
size = 0;
}
public int getSize()
{
return size;
}
public boolean isEmpty()
{
return (size==0);
}
// Accessor methods
public Position first()
{
return first;
}
public Position last()
{
return last;
}
public Position before(Position p) throws Exception
{
Node n = (Node) p;
try{
return n.getPrev();
}catch(NullPointerException ex)
{
throw new Exception("Position Doesn't Exists");
}
}
public Position after(Position p) throws Exception
{
Node n = (Node) p;
try{
return n.getNext();
}catch(NullPointerException ex)
{
throw new Exception("Position Doesn't Exists");
}
}
// Update methods
public void insertFirst(Object data)
{
Node node;
if(isEmpty())
{
Node prev = null;
Node next = null;
node = new Node(prev,data,next);
first = node;
last = node;
}
else
{
Node prev = null;
Node next = first;
node = new Node(prev,data,next);
first.setPrev(node);
first = node;
}
size++;
}
public void insertLast(Object data)
{
Node node;
if(isEmpty())
{
Node prev = null;
Node next = null;
node = new Node(prev,data,next);
first = node;
last = node;
}
else
{
Node prev = last;
Node next = null;
node = new Node(prev,data,next);
last.setNext(node);
last = node;
}
size++;
}
public void insertBefore(Position p, Object data) throws Exception
{
Node cur = (Node) p;
Node prev;
try{
prev = cur.getPrev();
}catch(NullPointerException ex)
{
throw new Exception("Position Doesn't Exists");
}
Node next = cur;
Node node;
node = new Node(prev,data,next);
next.setPrev(node);
if(cur!=first)
prev.setNext(node);
else
first=node;
size++;
}
public void insertAfter(Position p, Object data) throws Exception
{
Node cur = (Node) p;
Node prev = cur;
Node next;
try{
next = cur.getNext();
}catch(NullPointerException ex)
{
throw new Exception("Position Doesn't Exists");
}
Node node;
node = new Node(prev,data,next);
prev.setNext(node);
if(cur!=last)
next.setPrev(node);
else
last=node;
size++;
}
public Object remove(Position p) throws Exception
{
Node n = (Node) p;
Object data = n.element();
if(isEmpty())
{
throw new Exception("List is Empty");
}
else
{
Node prev,next;
if(n==first && n==last)
{
first = null;
last = null;
}
else if(n==first)
{
prev = null;
next = n.getNext();
next.setPrev(prev);
first = next;
}
else if(n==last)
{
prev = n.getPrev();
next = null;
prev.setNext(next);
last = prev;
}
else
{
prev = n.getPrev();
next = n.getNext();
prev.setNext(next);
next.setPrev(prev);
}
size--;
}
return data;
}
}
PEACE
I understand this situation as following. For add new item into the list we have to perform to tasks:
First one: find target item, after which we want to add new item.
Second one: add item and change links.
As you correctly noted, in case of linked list, first operation depends on the amount of item in the list, and will take (maximally) O(n). But, for example in case of array list it can take O(1).
I guess, book says about second task, when target item is already found. And this operation really will take constant amount of operations - O(1), if you are working with linked list. The same operation on array list can take O(n).
Regarding to your comment. Just compare:
Position based
get(i) is O(n)
add(item) is O(1) advantage
addToPosition(i, item) is O(n)
delete(item) is O(1) advantage
delete(i) is from O(1) to O(n)
Ranked based
get(i) is O(1) advantage
add(item) is from O(1) to O(n)
addToPosition(i, item) from O(1) to O(n)
delete(item) is from O(1) to O(2n)
delete(i) is from O(1) to O(n)
So, you should to know advantages of both of types, for use it depending on situation. For example, if you need large amount of add and delete operations - you should use LinkedList, but when you need just access items by index and there is few of add and delete operations - choose ArrayList.

Reversing a Doubly-Linked-List

Hey I'm currently stuck on the reverse method of my DoublyLinkedList. Everything is working fine (somehow) except for the reverse method. I'm not receiving any errors - System.out.println(list.reverse()) simply has no output.
Any suggestions? Thank you very much in advance. :)
Okay: I have edited my code now. So far everyhing is working correctly. However, the recursive method simply prints the list in the same order, instead of actually reversing it.
Updated Code:
public class DoublyLinkedStringList {
private String content;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;
public DoublyLinkedStringList(String info) {
content = info;
prev = null;
next = null;
}
private DoublyLinkedStringList(String content, DoublyLinkedStringList prev, DoublyLinkedStringList next) {
this.content = content;
this.prev = prev;
this.next = next;
}
public DoublyLinkedStringList prepend(String info) {
DoublyLinkedStringList newNode = new DoublyLinkedStringList(info);
prev = newNode;
newNode.next = this;
return newNode;
}
public DoublyLinkedStringList delete(int index) {
DoublyLinkedStringList curr = this;
if (index == 0) {
next.prev = null;
return next;
}
for (int i = 0; i < index; i++) {
curr = curr.next;
}
curr.prev.next = curr.next;
if (curr.prev.next != null) {
curr.prev.next.prev = curr.prev;
}
return this;
}
public DoublyLinkedStringList reverse() {
DoublyLinkedStringList currNode = this;
while (currNode != null) {
DoublyLinkedStringList temp = currNode.next;
currNode.next = currNode.prev;
currNode.prev = temp;
if (currNode.prev != null) {
currNode = currNode.prev;
}
}
return this;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (DoublyLinkedStringList currNode = this; currNode != null; currNode = currNode.next) {
sb.append(currNode.content);
if (currNode.next != null) {
sb.append(", ");
}
}
return sb.toString();
}
public static void main(String argv[]) {
DoublyLinkedStringList list = new DoublyLinkedStringList("Testliste");
list = list.prepend("6");
list = list.prepend("5");
list = list.prepend("4");
list = list.prepend("3");
list = list.prepend("2");
list = list.prepend("1");
list = list.prepend("0");
list = list.delete(1);
System.out.println(list);
list = list.reverse();
System.out.println(list);
}
}
One of the problems you are going to have with your design is when you reverse the list the head becomes the tail and the tail becomes the head. But the client is pointing to the head, and not the tail. Even if you did this operation 100% correct, you can't change the reference the client has. What you'll want to do is separate the concepts of the List as an object, and the Nodes that make up that object (currently you have combined these two concepts together because the nodes are the list and vice versa). By separating them the reference to the list is always the same regardless of what's in it, order, etc. The List contains the head and tail references, and the nodes only contain the next/prev. Right now you have head and tail in every node in your list which can make nasty bugs pop up if you don't replace every reference whenever head/tail changes (ie prepend, delete, or reverse). If you moved those two instances out of each node then you don't have to do as much maintenance to the list on changes. I think if you do that then you'll find it much easier to implement reverse.
Your error is exactly the problem I'm saying. At the end you return this, well the reference the client has was the head (ie this). However, after iterating over and reversing everything what was the head is now the tail so you've returned the new tail by returning this. And toString() on tail is NOTHING.
Normally I would implement the interface Iteratable and use an Iterator to reverse the list but I kept my revision in line with your current model. I changed the return types of the Node's getNext() and getPrev() methods to be dependent on the forward variable. Now the list never changes linkage when "reversed" but it is traversed in reverse order via the variable getNext() and getPrev() behavior.
IDEONE link to code
Consider this edit:
class DoublyLinkedStringList {
private Node head, tail;
boolean forward;
/**
* Diese Klasse repraesentiert einen Knoten in der Doubly Linked List der
* Klasse
* <code>DoublyLinkedStringList</code>
*
*/
private class Node {
private String content;
private Node next;
private Node prev;
public Node(String content) { this.content = content; }
public Node(String content, Node next) {
this.content = content;
if(forward) { this.next = next; } //EDITED
else { this.prev = next; } //EDITED
}
public Node getNext() { return (forward) ? next : prev; } //EDITED
public Node getPrev() { return (forward) ? prev : next; } //EDITED
public void setNext(Node next) {
if(forward) { this.next = next; } //EDITED
else { this.prev = next; } //EDITED
}
public void setPrev(Node prev) {
if(forward) { this.prev = prev; } //EDITED
else { this.next = prev; } //EDITED
}
}
public DoublyLinkedStringList() {
this.head = null;
this.tail = null;
}
public Node prepend(String info) {
Node newNode = new Node(info);
newNode.setPrev(null);
newNode.setNext(getHead());
if(newNode.getNext()!=null) {
newNode.getNext().setPrev(newNode); //EDITED
}
if(forward) { head = newNode; } //EDITED
else { tail = newNode; } //EDITED
if(getTail() == null) { //EDITED
if(forward) { tail = newNode; } //EDITED
else { head = newNode; } //EDITED
}
return head;
}
public Node delete(int index) {
Node currNode = getHead();
int count = 0;
if (index == 0) {
if(forward) { head = head.next; } //EDITED
else { tail = tail.prev; } //EDITED
return head;
}
while (currNode != null) {
if (count + 1 == index) {
currNode.next.prev = currNode.prev;
currNode.prev.next = currNode.next; //EDITED
break;
}
currNode = currNode.getNext(); //EDITED
count++;
}
return currNode;
}
private Node next() {
Node currNode = head;
if (forward) {
return currNode.getNext();
} else {
return currNode.getPrev();
}
}
public Node getHead() { return (forward) ? head : tail; } //EDITED
public Node getTail() { return (forward) ? tail : head; } //EDITED
public DoublyLinkedStringList reverse() { forward = !forward; return this; }
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
//EDITED LOOP STRUCTURE
for (Node currNode = getHead(); currNode != null; currNode = currNode.getNext()) {
sb.append(currNode.content);
if (currNode.getNext() != null) {
sb.append(", ");
}
}
return sb.toString();
}
public static void main(String argv[]) {
DoublyLinkedStringList list = new DoublyLinkedStringList();
list.prepend("6");
list.prepend("5");
list.prepend("4");
list.prepend("3");
list.prepend("2");
list.prepend("1");
list.prepend("0");
list.delete(3);
System.out.println(list);
System.out.println(list.reverse());
}
}
you simply have to set head and tail too. then it should work. but see chubbsondubs answer for further improvement!
Since you have a DoublyLinkedStringList as return type, I think you want to return a new object. In this case I suggest you to cycle over your object and build a new List using the prepend method you already implemented (that anycase has some other error). You can start with a empty list, and, as you scan the original object, prepend current element.
Otherwise, if you want to reverse the list "in place" you should return void, change the head with the last element, and, since is double linked, your should do anything else, since there are pointers to nodes in both directions.
try this for the reverse method:
public class DoublyLinkedList {
Node first, current;
boolean forward;
//constructors... methods...
private Node next() {
if(forward) return current.next();
else return current.previous();
}
public void reverse() {
while(true) {
if(next() == null) {
first = current;
forward = !forward;
return;
}
current = next();
}
}
}
Here is just my solution. I unfortunately do not have more time for explanatory notes.
public class DoublyLinkedStringList {
private String info;
private DoublyLinkedStringList prev;
private DoublyLinkedStringList next;
public DoublyLinkedStringList(String pInfo)
{
info = pInfo;
prev = null;
next = null;
}
private DoublyLinkedStringList(String pInfo, DoublyLinkedStringList pPrev, DoublyLinkedStringList pNext)
{
info = pInfo;
prev = pPrev;
next = pNext;
}
public DoublyLinkedStringList prepend(String info)
{
DoublyLinkedStringList n = new DoublyLinkedStringList(info);
prev = n;
n.next = this;
return n;
}
public DoublyLinkedStringList delete(int index)
{
if (index == 0)
{
next.prev = null;
return next;
}
DoublyLinkedStringList d = this;
for (int i = 0; i<index; i++)
d = d.next;
// d is now the node which should be deleted
// after delete(x) "next" schould be on pos x
d.prev.next = d.next; // take the next of the prev and set the new next to the next of d
if (d.prev.next != null) // if the next of d was not set to null, it must get to know his new prev (d's prev)
d.prev.next.prev = d.prev;
return this;
}
public DoublyLinkedStringList reverse() // moe or less less similar to my implementation in IntList.java
{
DoublyLinkedStringList oldLast = getLast();
next.reverse(this);
prev = next;
next = null;
return oldLast;
}
public void reverse(DoublyLinkedStringList last)
{
if (next != null)
next.reverse(this);
prev = next;
next = last;
}
public DoublyLinkedStringList getLast()
{
if (next == null)
return this;
return next.getLast();
}
#Override
public String toString()
{
String r = "";
for (DoublyLinkedStringList i = this; i != null; i = i.next)
{
r += i.info;
if (i.next != null)
r += ", ";
}
return r;
}
public String reverseToString() // uses prev; just for testing issues :)
{
String r = "";
for (DoublyLinkedStringList i = getLast(); i != null; i = i.prev)
{
r += i.info;
if (i.prev != null)
r += ", ";
}
return r;
}
public static void main(String argv[])
{
DoublyLinkedStringList list = new DoublyLinkedStringList("Test");
list = list.prepend("6");
list = list.prepend("5");
list = list.prepend("4");
list = list.prepend("3");
list = list.prepend("2");
list = list.prepend("1");
list = list.prepend("0");
list = list.delete(1);
System.out.println(list);
System.out.println(list.reverseToString()+"\n");
list = list.reverse();
System.out.println(list);
System.out.println(list.reverseToString());
list = list.delete(6);
list = list.delete(0);
System.out.println(list);
list = list.reverse();
list = list.prepend("1");
System.out.println(list);
}

Adding items to end of linked list

I'm studying for an exam, and this is a problem from an old test:
We have a singly linked list with a list head with the following declaration:
class Node {
Object data;
Node next;
Node(Object d,Node n) {
data = d;
next = n;
}
}
Write a method void addLast(Node header, Object x) that adds x at the end of the list.
I know that if I actually had something like:
LinkedList someList = new LinkedList();
I could just add items to the end by doing:
list.addLast(x);
But how can I do it here?
class Node {
Object data;
Node next;
Node(Object d,Node n) {
data = d ;
next = n ;
}
public static Node addLast(Node header, Object x) {
// save the reference to the header so we can return it.
Node ret = header;
// check base case, header is null.
if (header == null) {
return new Node(x, null);
}
// loop until we find the end of the list
while ((header.next != null)) {
header = header.next;
}
// set the new node to the Object x, next will be null.
header.next = new Node(x, null);
return ret;
}
}
You want to navigate through the entire linked list using a loop and checking the "next" value for each node. The last node will be the one whose next value is null. Simply make this node's next value a new node which you create with the input data.
node temp = first; // starts with the first node.
while (temp.next != null)
{
temp = temp.next;
}
temp.next = new Node(header, x);
That's the basic idea. This is of course, pseudo code, but it should be simple enough to implement.
public static Node insertNodeAtTail(Node head,Object data) {
Node node = new Node(data);
node.next = null;
if (head == null){
return node;
}
else{
Node temp = head;
while(temp.next != null){
temp = temp.next;
}
temp.next = node;
return head;
}
}
If you keep track of the tail node, you don't need to loop through every element in the list.
Just update the tail to point to the new node:
AddValueToListEnd(value) {
var node = new Node(value);
if(!this.head) { //if the list is empty, set head and tail to this first node
this.head = node;
this.tail = node;
} else {
this.tail.next = node; //point old tail to new node
}
this.tail = node; //now set the new node as the new tail
}
In plain English:
Create a new node with the given value
If the list is empty, point head and tail to the new node
If the list is not empty, set the old tail.next to be the new node
In either case, update the tail pointer to be the new node
Here is a partial solution to your linked list class, I have left the rest of the implementation to you, and also left the good suggestion to add a tail node as part of the linked list to you as well.
The node file :
public class Node
{
private Object data;
private Node next;
public Node(Object d)
{
data = d ;
next = null;
}
public Object GetItem()
{
return data;
}
public Node GetNext()
{
return next;
}
public void SetNext(Node toAppend)
{
next = toAppend;
}
}
And here is a Linked List file :
public class LL
{
private Node head;
public LL()
{
head = null;
}
public void AddToEnd(String x)
{
Node current = head;
// as you mentioned, this is the base case
if(current == null) {
head = new Node(x);
head.SetNext(null);
}
// you should understand this part thoroughly :
// this is the code that traverses the list.
// the germane thing to see is that when the
// link to the next node is null, we are at the
// end of the list.
else {
while(current.GetNext() != null)
current = current.GetNext();
// add new node at the end
Node toAppend = new Node(x);
current.SetNext(toAppend);
}
}
}
loop to the last element of the linked list which have next pointer to null then modify the next pointer to point to a new node which has the data=object and next pointer = null
Here's a hint, you have a graph of nodes in the linked list, and you always keep a reference to head which is the first node in the linkedList.
next points to the next node in the linkedlist, so when next is null you are at the end of the list.
The addLast() needs some optimisation as the while loop inside addLast() has O(n) complexity. Below is my implementation of LinkedList. Run the code with ll.addLastx(i) once and run it with ll.addLast(i) again , you can see their is a lot of difference in processing time of addLastx() with addLast().
Node.java
package in.datastructure.java.LinkedList;
/**
* Created by abhishek.panda on 07/07/17.
*/
public final class Node {
int data;
Node next;
Node (int data){
this.data = data;
}
public String toString(){
return this.data+"--"+ this.next;
}
}
LinkedList.java
package in.datastructure.java.LinkedList;
import java.util.ArrayList;
import java.util.Date;
public class LinkedList {
Node head;
Node lastx;
/**
* #description To append node at end looping all nodes from head
* #param data
*/
public void addLast(int data){
if(head == null){
head = new Node(data);
return;
}
Node last = head;
while(last.next != null) {
last = last.next;
}
last.next = new Node(data);
}
/**
* #description This keep track on last node and append to it
* #param data
*/
public void addLastx(int data){
if(head == null){
head = new Node(data);
lastx = head;
return;
}
if(lastx.next == null){
lastx.next = new Node(data);
lastx = lastx.next;
}
}
public String toString(){
ArrayList<Integer> arrayList = new ArrayList<Integer>(10);
Node current = head;
while(current.next != null) {
arrayList.add(current.data);
current = current.next;
}
if(current.next == null) {
arrayList.add(current.data);
}
return arrayList.toString();
}
public static void main(String[] args) {
LinkedList ll = new LinkedList();
/**
* #description Checking the code optimization of append code
*/
Date startTime = new Date();
for (int i = 0 ; i < 100000 ; i++){
ll.addLastx(i);
}
Date endTime = new Date();
System.out.println("To total processing time : " + (endTime.getTime()-startTime.getTime()));
System.out.println(ll.toString());
}
}
The above programs might give you NullPointerException. This is an easier way to add an element to the end of linkedList.
public class LinkedList {
Node head;
public static class Node{
int data;
Node next;
Node(int item){
data = item;
next = null;
}
}
public static void main(String args[]){
LinkedList ll = new LinkedList();
ll.head = new Node(1);
Node second = new Node(2);
Node third = new Node(3);
Node fourth = new Node(4);
ll.head.next = second;
second.next = third;
third.next = fourth;
fourth.next = null;
ll.printList();
System.out.println("Add element 100 to the last");
ll.addLast(100);
ll.printList();
}
public void printList(){
Node t = head;
while(n != null){
System.out.println(t.data);
t = t.next;
}
}
public void addLast(int item){
Node new_item = new Node(item);
if(head == null){
head = new_item;
return;
}
new_item.next = null;
Node last = head;
Node temp = null;
while(last != null){
if(last != null)
temp = last;
last = last.next;
}
temp.next = new_item;
return;
}
}

Categories