I'm trying to improve my recursion skills (or probably gain them for the first time :)). For it, I've written out a Java code to reverse a singly linked list, which is as follows:
node head, prev; // head is pointing to the start of the linked list
void reverselist(node current) {
if (current.next != null) {
reverselist(current.next);
}
if (current.next == null) {
this.head = current;
prev = current;
}
else {
prev.next = current;
current.next = null;
prev = current;
}
}
This code works fine, but for learning's sake, I want to avoid using global variable (node prev) for operations inside the recursive function. So can this function be re-written to avoid it completely? Any other optimizations are welcome :)
A better implementation should be as below:
public Node reverse(Node current)
{
if (current== null || current.next==null) return current;
Node nextItem = current.next;
current.next = null;
Node reverseRest = reverse(nextItem);
nextItem.next = current;
return reverseRest;
}
public Linkedlist reverseList (LinkedList list) {
Node temp = null;
Node nextNode = list;
while(list != null) {
nextNode = list.next;
list.next = temp;
temp = list;
list = nextNode;
}
return temp;
}
private class LinkedList {
int data;
LinkedList next;
}
Related
I am implementing a single linked list of integer and I was wondering what is the most efficient way to locate a given value and remove it from the list. This is what I have so far:
public class LinkedList {
Node head;
public void insert(int value){
Node newNode = new Node();
newNode.data = value;
newNode.next = null;
if(head==null){
head = newNode;
} else {
Node iterator = head;
while(iterator.next!=null){
iterator = iterator.next;
}
iterator.next = newNode;
}
}
public void display(LinkedList list){
Node iterator = head;
while (iterator!=null){
System.out.println(iterator.data);
iterator = iterator.next;
}
}
public void remove(LinkedList list, int value){
Node iterator = head;
while(iterator!=null){
if(iterator.next.data == value){
iterator.next = iterator.next.next;
} else{
iterator = iterator.next;
}
}
}
}
public class Node {
int data;
Node next;
}
I am adding snippet here to remove the node from SinglyLinkedList. I prefer forLoop over while; that's the reason I have added snippet with for loop.
Hope the comment in the code helps you to navigate/dry run the snippet.
public boolean remove(int value){
Node oneBeforeValueNode;
// Using for to iterate through the SinglyLinkedList
// head → is the head of your SingleLinkedList
for (Node node = head; node != null; node = node.next) {
// Compare the value with current node
if (value.equals(node.data)) {
// if matches then unlink/remove that node from SinglyLinkedList
// if its a first node in SingleLinkedList
if(oneBeforeValueNode==null){
// Considering there exists next element else SLL will be empty
head = head.next;
} else {
// if there exists next element it SLL it will attach that element with previous one
oneBeforeValueNode.next = node.next;
}
return true;
}
// Storing previous node from current
// To use it once value is found to reference it to current.next(node.next)
oneBeforeValueNode = node;
}
return false;
}
Adding with while variant as well; just to go with your flow.
public Node remove(Node head, int key) {
Node current = head;
Node previous = null;
while (current != null) {
if(current.data == key) {
if(current == head) {
head = head.next;
current = head;
} else {
previous.next = current.next;
current = current.next;
}
} else {
previous = current;
current = current.next;
}
}
return head;
}
I solved the next exercises having two solutions: https://www.hackerrank.com/challenges/reverse-a-doubly-linked-list
First (non-recursive):
/*
Insert Node at the end of a linked list
head pointer input could be NULL as well for empty list
Node is defined as
class Node {
int data;
Node next;
Node prev;
}
*/
Node Reverse(Node head) {
if (head == null) return null;
Node current = head;
while (current.next != null) {
Node temp = current.next;
current.next = current.prev;
current.prev = temp;
current = temp;
}
current.next = current.prev;
current.prev = null;
return current;
}
Second algorithm (recursive):
/*
Insert Node at the end of a linked list
head pointer input could be NULL as well for empty list
Node is defined as
class Node {
int data;
Node next;
Node prev;
}
*/
Node Reverse(Node head) {
if (head.next == null) {
head.next = head.prev;
head.prev = null;
return head;
}
Node newHead = Reverse(head.next);
Node temp = head.next;
head.next = head.prev;
head.prev = temp;
return newHead;
}
According to the book, the solution must be O(n). I guess using recursive solution is more elegant but maybe I'm wrong. Can you help to determine the space and time complexity of these two algoritms, or in your, which is better in performance?
The question is a bit unclear, both solutions seem to be O(n) in both time and space. Although you could probably remove the special cases and make Torvalds happy. Something like:
Node Reverse(Node head) {
if (head == null) return null;
Node current = head;
while (current != null) {
Node temp = current.next;
current.next = current.prev;
current.prev = temp;
current = temp;
}
return current;
}
Node Reverse(Node head) {
Node temp = head.next;
head.next = head.prev;
head.prev = temp;
return temp==null?head:Reverse(temp);
}
I have not tested these, use them as inspiration only. (Also the recursive will nullpointer if head is null in the beginning).
I am trying to implement the reverse function of my own LinkedList implementation. Using my implementation of LinkedList:
public class LinkedList<T> {
public Node head;
public LinkedList(){
// Add HEAD
head = new Node(null);
}
public void add(T data){
getLastNode().next = new Node(data);
}
public void insert(int index, T data){
if(index == 0){
throw new Error(); // TODO: What is the Error Type?
}
Node current = head;
for (int i = 0; i != index - 1 ; i ++) {
current = current.next;
if (current == null){
throw new IndexOutOfBoundsException();
}
}
Node next = current.next;
Node newNode = new Node(data);
current.next = newNode;
newNode.next = next;
}
public T get(int index){
return getNode(index).data;
}
public void delete(int index){
if (index == 0){
throw new IndexOutOfBoundsException("Cannot delete HEAD node");
}
Node prev = getNode(index - 1);
Node next = prev.next.next;
prev.next = null;
prev.next = next;
}
public void reverse(){ // TODO: Last node links to a null node
Node prev = null;
Node current = head;
Node next = null;
while(current != null){
next = current.next;
current.next = prev;
prev = current;
current = next;
}
head = new Node(null);
head.next = prev;
}
public void display(){
Node current = head;
String diagram = String.format("head->");
while(current.next != null){
current = current.next;
diagram += String.format("%s->", current.data);
}
System.out.println(diagram);
}
private Node getNode(int index){
Node node = head;
for(int i = 0; i != index; i++){
node = node.next;
if(node == null){
throw new IndexOutOfBoundsException();
}
}
return node;
}
private Node getLastNode(){
Node current = head;
while(current.next != null){
current = current.next;
}
return current;
}
public class Node {
private Node next;
private T data;
public Node(T data){
this.data = data;
}
public Node getNext(){
return this.next;
}
}
}
And this main function:
LinkedList list = new LinkedList();
list.add("e1");
list.add("e2");
list.add("e3");
list.add("e4");
list.display();
list.reverse();
list.display();
The displayed result is:
head->e1->e2->e3->e4->
head->e4->e3->e2->e1->null->
This has happened due to the fact that e1 is still connected to the head. If I use the implementation of reverse available online:
Node prev = null;
Node current = head;
Node next = null;
while(current != null){
next = current.next;
current.next = prev;
prev = current;
current = next;
}
head = prev;
Then the result will ditch e4: head->e3->e2->e1->null->
What am I doing here? Why is my implementation different than everybody else's?
Also: Why does everyone use a reverse function that has head as an argument which could be problematic if the developer enters a different node?
You are using a first node as a head of your list. The solution for the reverse function is this:
head.next = prev;
You have to preserve the 'head' node, but change its 'next' field.
The rest of the function don't change at all:
public void reverse(){ // TODO: Last node links to a null node
Node prev = null;
Node current = head.next;
Node next = null;
while(current != null){
next = current.next;
current.next = prev;
prev = current;
current = next;
}
head.next = prev; // *** The only change ***
}
In your constructor you have:
public LinkedList(){
// Add HEAD
head = new Node(null);
}
then, 'head' is a Node that points to nothing initially.
In the reverse function, the 'head' node don't change, you don't need to create another out. But it has to point to the correct first Node.
If the list was empty, this 'head' points to null.
If the list has only one Node, this 'head' points to it yet.
If the list has more than one Node, this 'head' has to point to the last node.
Because of this, you need to change its 'next' field.
Can someone provide the possible ways to print a Linkedlist in reverse in Java.
A way I understand would be to Recursively reach the end of list, And then start printing from the back and come to front recursively.
Please share the possible ways.
I am using a Node having next and previous.
A Solution I figured is below. But here I need to create a variable each time entering in the recursive loop. That's bad :(
public void reversePrinting(int count){
if(count==0){ //to assign the root node to current only once
current=root;
count++;
}
else{ //moving current node to subsequent nodes
current=current.nextNode;
}
int x= current.data;
if(current.nextNode==null){
System.out.println(x);
return;
}
reversePrinting(count);
System.out.println(x);
}
try this, it is able reverse a linkedlist
public class DoReverse{
private Node head;
private static class Node {
private int value;
private Node next;
Node(int value) {
this.value = value;
}
}
public void addToTheLast(Node node) {
if (head == null) {
head = node;
}
else {
Node temp = head;
while (temp.next != null)
temp = temp.next;
temp.next = node;
}
}
public void printList(Node head) {
Node temp = head;
while (temp != null) {
System.out.format("%d ", temp.value);
temp = temp.next;
}
System.out.println();
}
public static Node reverseList(Node head){
Node prev = null;
Node current = head;
Node next = null;
while(current != null){
next = current.next;
current.next = prev;
prev = current;
current = next;
}
head = prev;
return head;
}
public static void main(String[] args) {
DoReverse list = new DoReverse();
// Creating a linked list
Node head = new Node(5);
list.addToTheLast(head);
list.addToTheLast(new Node(6));
list.addToTheLast(new Node(7));
list.addToTheLast(new Node(1));
list.addToTheLast(new Node(2));
list.addToTheLast(new Node(10));
System.out.println("Before Reversing :");
list.printList(head);
Node reverseHead= list.reverseList(head);
System.out.println("After Reversing :");
list.printList(reverseHead);
}
}
Why not copy the list so that it is reversed:
Reversing a linked list in Java, recursively
And then loop the copy of the list like your normally would?
I have a question for combining two linkedlist. Basically, I want to append one linkedlist to the other linkedlist.
Here is my solution. Is there a more efficient way to do it without looping the first linkedlist? Any suggestion would be appreciated.
static Node connect(LinkedList list1, LinkedList list2) {
Node original = list1.first;
Node previous = null;
Node current = list1.first;
while (current != null) {
previous = current;
current = current.next;
}
previous.next = list2.first;
return original;
}
Use list1.addAll(list2) to append list2 at the end of list1.
For linked lists, linkedList.addAll(otherlist) seems to be a very poor choice.
the java api version of linkedList.addAll begins:
public boolean addAll(int index, Collection<? extends E> c) {
checkPositionIndex(index);
Object[] a = c.toArray();
so even when you have 2 linked lists, the second one gets converted to an array, then re-constituted into individual elements. This is worse than just merging 2 arrays.
I guess this is your own linked list implementation? With only a pointer to next element, the only way to append at the end is to walk all the elements of the first list.
However, you could store a pointer to the last element to make this operation run in constant time (just remember to update the last element of the new list to be the last element of the added list).
The best way is to append the second list to the first list.
1. Create a Node Class.
2. Create New LinkedList Class.
public class LinkedList<T> {
public Node<T> head = null;
public LinkedList() {}
public void addNode(T data){
if(head == null) {
head = new Node<T>(data);
} else {
Node<T> curr = head;
while(curr.getNext() != null) {
curr = curr.getNext();
}
curr.setNext(new Node<T>(data));
}
}
public void appendList(LinkedList<T> linkedList) {
if(linkedList.head == null) {
return;
} else {
Node<T> curr = linkedList.head;
while(curr != null) {
addNode((T) curr.getData());
curr = curr.getNext();
}
}
}
}
3. In the Main function or whereever you want this append to happen, do it like this.
LinkedList<Integer> n = new LinkedListNode().new LinkedList<Integer>();
n.addNode(23);
n.addNode(41);
LinkedList<Integer> n1 = new LinkedListNode().new LinkedList<Integer>();
n1.addNode(50);
n1.addNode(34);
n.appendList(n1);
I like doing this way so that there isn't any need for you to pass both these and loop again in the first LinkedList.
Hope that helps
My Total Code:
NOTE: WITHOUT USING JAVA API
class Node {
Node next;
int data;
Node(int d){
data = d;
next = null;
}
}
public class OddEvenList {
Node head;
public void push(int new_data){
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
Node reverse(Node head){
Node prev = null;
Node next = null;
Node curr = head;
while(curr != null){
next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
Node merge(Node head1, Node head2){
Node curr_odd = head1;
Node curr_even = head2;
Node prev = null;
while(curr_odd != null){
prev = curr_odd;
curr_odd = curr_odd.next;
}
prev.next = curr_even;
return head1;
}
public void print(Node head){
Node tnode = head;
while(tnode != null){
System.out.print(tnode.data + " -> ");
tnode = tnode.next;
}
System.out.println("Null");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
OddEvenList odd = new OddEvenList();
OddEvenList even = new OddEvenList();
OddEvenList merge = new OddEvenList();
odd.push(1);
odd.push(3);
odd.push(5);
odd.push(7);
odd.push(9);
System.out.println("Odd List: ");
odd.print(odd.head);
System.out.println("Even List: ");
even.push(0);
even.push(2);
even.push(4);
even.push(6);
even.push(8);
even.print(even.head);
System.out.println("After Revrse: --------------------");
Node node_odd =odd.reverse(odd.head);
Node node_even = even.reverse(even.head);
System.out.println("Odd List: ");
odd.print(node_odd);
System.out.println("Even List: ");
even.print(node_even);
System.out.println("Meged: --------------");
Node merged = merge.merge(node_odd, node_even);
merge.print(merged);
}
}