How to properly count nodes in the stack? - java

I created this loop to count elements in the stack that are within the interval [-10;10], but when I return the answer, I can see, that it doesn't count the last node, is there something wrong here?
public int intervalNumbers() {
int counter = 0;
Node node;
for (node = top;
node.link != null;
node = node.link) {
if (node.data >= -10 && node.data <= 10) {
counter++;
}
}
return counter;
}

It is sort of off by one case.
for (node = top;
node.link != null;
node = node.link)
Because of the condition node.link != null, the body of the loop is not executed for the last node (as the last node's link would be null)
Change it to node != null

Related

Make a moving cursor using doubly linked list in java

I'm trying to write a code for a simple moving cursor in java. I have to use doubly linked list. Also I should implement doubyLinkedList class myself. In this program first we take an integer like n from user as number of lines. Then we take n lines of input. Each line contains only one character which can be < or > or - or one of the lower case English alphabet. For > or < we move the cursor to right or left. For - we delete the character in the place of cursor. For alphabets we add them to the doubly linked list. At last we print the result in one line without spaces. I have made the doubyLinkedList class and needed methods. I think it is working properly but the time complexity of the code must be O(n). I guess it's O(n^2) now.
import java.util.*;
public class DoublyLinkedList {
static Node head = null;
static int size = 0;
class Node {
String data;
Node prev;
Node next;
Node(String d) {
data = d;
}
}
static Node deleteNode(Node del) {
if (head == null || del == null)
return null;
if (head == del)
head = del.next;
if (del.next != null)
del.next.prev = del.prev;
if (del.prev != null)
del.prev.next = del.next;
del = null;
size --;
return head;
}
public String GetNth(int index) {
Node current = head;
int count = 0;
while (current != null)
{ if (count == index)
return current.data;
count++;
current = current.next;
}
assert (false);
return null;
}
public static void deleteNodeAtGivenPos(int n) {
size--;
if (head == null || n <= 0)
return;
Node current = head;
int i;
for (i = 1; current != null && i < n; i++)
current = current.next;
if (current == null)
return;
deleteNode(current);
}
void insertFirst (String data){
size++;
Node newNode = new Node(data);
if (head == null) {
newNode.prev = null;
head = newNode;
return;
}
else
head.prev= newNode;
newNode.next=head;
head = newNode;
}
void append(String data) {
size++;
Node newNode = new Node(data);
Node last = head;
newNode.next = null;
if (head == null) {
newNode.prev = null;
head = newNode;
return;
}
while (last.next != null)
last = last.next;
last.next = newNode;
newNode.prev = last;
}
public void insertAtGivenPos(String s , int index){
Node newNode= new Node(s);
Node current= head;
if (index==0)
insertFirst(s);
else if(index==size)
append(s);
else{
for(int j = 0; j < index && current.next != null; j++){
current = current.next;
}
newNode.next = current;
current.prev.next = newNode;
newNode.prev = current.prev;
current.prev = newNode;
size++;
}
}
public void print(Node node) {
while (node != null) {
System.out.print(node.data + "");
node = node.next;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = Integer.parseInt(sc.nextLine());
String [] arr= new String[n];
for (int i=0; i< n; i++)
arr[i] = sc.nextLine();
DoublyLinkedList dll = new DoublyLinkedList();
int cursor= 0;
for (int i=0; i< n; i++){
if (arr[i].matches("[a-z]")){
dll.insertAtGivenPos(arr[i], cursor);
cursor++;
}
else if (arr[i].contains("-")&& dll.GetNth(cursor-1)!= null) {
dll.deleteNodeAtGivenPos(cursor);
cursor--;
}
else if (arr[i].contains("<") && dll.GetNth(cursor-1)!= null)
cursor--;
else if (arr[i].contains(">") && dll.GetNth(cursor+1)!= null)
cursor++;
}
dll.print(dll.head);
}
}
How can I improve my code to reduce time complexity?
Edit: Also I understood that my code is giving wrong answer for some cases. Could you help me debug it?
If you are not forced to follow implementation details, I suggest not to have a cursor. Instead, keep a variable currentNode which is the node that the cursor would point to. So for every command (or data) in the input loop, you have one O(1) operation as bellow and hence will get O(n) time complexity.
1 - for > : change the currentNode to currentNode.next
2 - for < do the reverse
3 - for - change the previous and the next node of currentNode to
point to each other (so the current is deleted)
4 - and finally for insertion : create a node and like 3, change the
the side nodes to point to it
You don't need inner for loop. process the input as soon as as you accept it.
for (int i=0; i< n; i++)
arr[i] = sc.nextLine();
DoublyLinkedList dll = new DoublyLinkedList();
int cursor= 0;
if (arr[i].matches("[a-z]")){
dll.insertAtGivenPos(arr[i], cursor);
cursor++;
}
else if (arr[i].contains("-")&& dll.GetNth(cursor-1)!= null) {
dll.deleteNodeAtGivenPos(cursor);
cursor--;
}
else if (arr[i].contains("<") && dll.GetNth(cursor-1)!= null)
cursor--;
else if (arr[i].contains(">") && dll.GetNth(cursor+1)!= null)
cursor++;
}

Doubly Circular Linked List

I created a Doubly Circular Linked List.
I need to know the distance from every node to head.
Because when I must delete or get a node with a specific key, if 2 nodes have the same key and same distance, both must be deleted or got, otherwise must be deleted the node closest to head.
I don't know how to calculate the distance because is circular ...
The insertion of this Linked List work in this way.
All the nodes go after the Head.
Example :
1) Head
2) Head-A (Inserted A)
3) Head-B-A (Inserted B)
4) Head-C-B-A (Inserted C)
For now, i did only a normal cancellation without the distance.
This is my code.
/* Function to delete node with the key */
public void deleteWithKey(int key) {
if (key == head.getData()) {
if (size == 1) {
head = null;
end = null;
size = 0;
return;
}
head = head.getLinkNext();
head.setLinkPrev(end);
end.setLinkNext(head);
size--;
return;
}
if (key == end.getData()) {
end = end.getLinkPrev();
end.setLinkNext(head);
head.setLinkPrev(end);
size--;
}
Node current = head.getLinkNext();
for (int i = 2; i < size; i++) {
if (key == current.getData()) {
Node p = current.getLinkPrev();
Node n = current.getLinkNext();
p.setLinkNext(n);
n.setLinkPrev(p);
size--;
return;
}
current = current.getLinkNext();
}
System.out.println("Don't exist a node with this key");
}
Thanks to All.
You actually don't need to know the distance. Rather, you need to find the closest to head.
Since it's a circular doubly linked list, this task is trivial:
define two variables a and b, initializing both to head
if either are the target, remove matching nodes and exit
assign a = a.next and b = b.previous
goto 2
This is the pseudocode I could think of to solve the problem.
Given head,
// no data
if(head==null) return;
// next and prev are always at same distance
next = head;
prev = head.prev;
// ensure nodes are not same or crossed half way through the list
while (next == prev || next.prev == prev){
// delete nodes if values are same
if (next.val == prev.val){
if(next!=head) {
next.prev.next = next.next;
next.next.prev = next.prev;
prev.prev.next = prev.next;
prev.next.prev = prev.prev;
}
// list has only two nodes
else if(head.next==prev){
head = null;
return;
// remove head and its prev node
else{
head = head.next;
head.prev = prev.next;
head.prev.next = head
}
}
// traverse through the list
next = next.next
prev = prev.prev
}
This is the final working code that i did.
Have you improvements?
Thanks to all for the help.
Complexity = O(n)
/* Function to delete node with the key */
public void deleteWithKey(int key) {
if (key == head.getData()) {
if (size == 1) {
head = null;
end = null;
size = 0;
return;
}
head = head.getLinkNext();
head.setLinkPrev(end);
end.setLinkNext(head);
size--;
return;
}
if (key == end.getData()) {
end = end.getLinkPrev();
end.setLinkNext(head);
head.setLinkPrev(end);
size--;
}
Node next = head;
Node back = head;
while (next != end) {
next = next.getLinkNext();
back = back.getLinkPrev();
if ((key == next.getData()) && (key == back.getData()) && (next != back)) {
Node p = next.getLinkPrev();
Node n = next.getLinkNext();
Node p1 = back.getLinkPrev();
Node n1 = next.getLinkNext();
p.setLinkNext(n);
n.setLinkPrev(p);
p1.setLinkPrev(n1);
n1.setLinkPrev(p1);
size -= 2;
return;
}
if ((key == next.getData()) && (next != back)) {
Node p = next.getLinkPrev();
Node n = next.getLinkNext();
p.setLinkNext(n);
n.setLinkPrev(p);
size--;
return;
}
if ((key == next.getData()) && (next == back)) {
Node p = next.getLinkPrev();
Node n = next.getLinkNext();
p.setLinkNext(n);
n.setLinkPrev(p);
size--;
return;
}
}
System.out.println("Don't exist a node with this key");
}

Linked List Delete Method

Could anyone explain why the following delete method does not work? It appears to create an infinite loop at the value I am trying to remove. It should loop through a linked list, delete all instances of the value passed to the method, and return the total number of nodes deleted (return num;).
public int delete(T value)
{
int num = 0;
ListNode<T> trav = head;
ListNode<T> next = head.getNext();
while(trav != null) {
if(trav.getValue().compareTo(value) == 0) {
trav = next;
num++;
}
if(next.getValue().compareTo(value) == 0) {
trav = next.getNext();
num++;
}
trav = trav.getNext();
}
return num;
}
You never change the value of next.
if(trav.getValue().compareTo(value) == 0) {
trav = next;
num++;
}
if(next.getValue().compareTo(value) == 0) {
trav = next.getNext();
num++;
}
Since next never changes, you're comparing the same value in the second if every time.

LinkedList from scratch, replacing a node

I was given an assignement to create a LinkedList from scratch, I've figured how to code a method that add a node at the end of the list but I still can't figure how to replace a node. Here is what I have so far:
public boolean replace(int element, int index) {
Node temp= new Node(pElement);
Node current = getHead();
if (!isEmpty()) {
for (int i = 0; i < index && current.getNext() != null; i++) {
current = current.getNext();
}
temp.setNext(noeudCourant.getNext());
noeudCourant.setNext(temp);
listCount++;
return true;
}
return false;
}
Using aNode.replace(10, 4) on "0 1 2 3 4 5 6 7 8 9 10"
will make it into
[0]->[1]->[2]->[3]->[4]->[10]->[5]->[6]->[7]->[8]->[9]->[10]
but I want:
[0]->[1]->[2]->[3]->[10]->[5]->[6]->[7]->[8]->[9]->[10]
Any help is appreciated.
[edit]I already have a working method setData() but the assignment I have forbid me to use it. What I want is basically this:
http://i.imgur.com/oOVYCvc.png
Here is a simple solution for your question:
package linkedlist;
class Node {
public Node next = null;
public int element;
public Node(int el) {
element = el;
}
}
class LinkedList {
public Node first = null;
public void add(Node node) {
if (first == null) {
first = node;
} else {
// Traverse to the last
Node cursor = first;
while (cursor.next != null) {
cursor = cursor.next;
}
cursor.next = node;
}
}
public void add(int[] elements) {
int len = elements.length;
for (int i=0;i < len;i++) {
add(new Node(elements[i]));
}
}
public boolean replace(int element, int index) {
Node cursor = first;
Node prev = null;
while (cursor != null && index >= 0) {
index--;
prev = cursor;
cursor = cursor.next;
}
if (index > 0) return false;
if (prev != null)
prev.element = element;
return true;
}
public void displayAll() {
Node cursor = first;
while (cursor != null) {
System.out.print(cursor.element + " ");
cursor = cursor.next;
}
System.out.println();
}
}
public class Main {
public static void main(String[] args) {
// Prepare elements
LinkedList linkedList = new LinkedList();
linkedList.add(new int[]{0,1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
println("Display the initial linked list content:");
linkedList.displayAll();
println("After replace:");
linkedList.replace(10, 4);
linkedList.displayAll();
println("Done");
}
static void println(String msg) {
System.out.println(msg);
}
}
If you really want to replace the Node and do not delete it then here is how you should be writing your replace() function:
public boolean replace(int element, int index) {
Node head = getHead();
int counter = 0;
while(null != head && counter++ < index - 1) {
head = head.getNext();
}
if(null == head || null == head.getNext()) return false;
Node newNode = new Node(element);
newNode.setNext(head.getNext().getNext());
head.setNext(newNode);
return true;
}
Here, I'm assuming that you have setNext() method in your Node class to set the link.
Also note that here it is assumed that you'll never replace head itself i.e. you'll never replace the element at index 0 or else you'll have to return the new head from the function.
Try below code. I have written the logic in comments wherever required.
public boolean replace(int element, int index) {
Node temp= new Node(pElement);
Node current = getHead();
if (!isEmpty()) {
//Run for loop one less than index value.
for (int i = 0; i < index -1 && current.getNext() != null; i++) {
current = current.getNext();
}
// At this point current points to element 3.
// Set next element of node 4 as a next element of new element 10.
temp.setNext(current.getNext().getNext());
// at this point we have two references for element 5 like below
// [0]->[1]->[2]->[3]->[4]->[5]->[6]->[7]->[8]->[9]->[10]
// [10]->[5]->[6]->[7]->[8]->[9]->[10]
// Set null to next element of of element 4 to remove reference to
// element 5
current.getNext().setNext(null);
// At this point we have two list as below:
// [0]->[1]->[2]->[3]
// [10]->[5]->[6]->[7]->[8]->[9]->[10]
// Set new element as next of current element (current element is 3)
current.setNext(temp);
// here we have replaced the element 4 with element 10
listCount++;
return true;
}
return false;
}

Java: NPE in Circular Linked List :(

import javax.swing.JOptionPane;
public class RotateArrayCircularLL
{
private Node head=null;
public void init()
{
int choice = 0;
while (choice != -1){
choice = Integer.parseInt(JOptionPane.showInputDialog("Enter -1 to stop loop, 1 to continue"));
if(choice == -1)
break;
inputNum();
}
printList();
}
public void inputNum()
{
Node n;
Node temp;
int k;
k = Integer.parseInt(JOptionPane.showInputDialog(null,"Enter a number:"));
n = new Node(k);
if (head == null) {
head = n;
} else {
temp = head;
while (temp.getNext() != null)
temp = temp.getNext();
temp.setNext(n);
}
}
public void printList()
{
Node temp = head;
int count = Integer.parseInt(JOptionPane.showInputDialog("Enter the value to shift to the right"));
for (int i = 1; i <= count; i++) // Rotates the head
temp = temp.getNext();
for (Node c = temp; c != null && c.getNext() != head; c= c.getNext()){ // Prints the new LL
System.out.print(c.getInfo());
}
}
}
I get an NPE during the second for loop. I understand that it is giving me a NPE because I reach the end of the list, but how can I stop it from doing this?
It appears from the behavior you are seeing that one of the nodes in your linked list is returning null instead of the next element of the list. At a guess, I'd suggest that the last node of your list is probably not pointing to the first node of your list. Hence as Hovercraft Full Of Eels suggests, you don't really have a properly circular linked list. If you can post the code showing how temp is populated, it may be possible to give a more concrete solution to your issue. Otherwise, you need to treat the case where getNext() returns null as a special case and ensure that you instead get the first element from the initial list.

Categories