Java Circular Linked list, Deleting inconsistencies - java

Ok so the idea for me is to be moving to each node(user in this case) in a circular list and asking if they would like to log off,they will give a random yes or no answer,until everyone has logged off. this seems to be the case most of the time i run the program but sometimes users are logging back on which shouldn't happen,I will post the delete method and the display method i am using.
public void displayLinkedList() {
temp=first;
int i = 1;
do {
boolean rand=randomBoolean();
if(rand) {
System.out.println("USER : "+temp.data+" Logged off ");
temp.isloggedOut=true;
Node placeholder = temp.nextNode; //save value of temp.next before we delete temp
delete(temp);
Node.numOfUsers--;
temp = placeholder; //reassign "temp" to the appropriate next value.
} else if(!temp.isloggedOut) {
System.out.println("USER : "+temp.data+" Logged on ");
temp=temp.nextNode;
}
} while(Node.numOfUsers!=0);
}
public void delete(Node n) {
if(Node.numOfUsers == 0 || n == null) return; // 0 nodes or null parameter.
Node temp = first;
if(temp.nextNode == null) { //only one node
temp = null; //simply delete it
} else {
while(temp.nextNode != n) {
temp = temp.nextNode;
if(temp == first) { //if we circle the entire list and don't find n, it doesn't exist.
return;
}
}
temp.nextNode = n.nextNode; // perform the switch, deleting n
}
}

I think your problem is in this line
else if(!rand)
Add a boolean that checks if the user has been deleted
else if(!rand && !userExists)

In the above code, you reference the temp variable AFTER deleting it from this list. This is likely causing some problems. Adjust to be the code below.
do {
boolean rand=randomBoolean();
if(rand) {
System.out.println("USER : " + temp.data + " Logged off ");
Node placeholder = temp.next; //save value of temp.next before we delete temp
delete(temp);
Node.numOfUsers--;
temp = placeholder; //reassign "temp" to the appropriate next value.
} else {
System.out.println("USER : " + temp.data + " Logged on ");
temp = temp.nextNode;
}
} while(Node.numOfUsers != 0);
Also, fun fact. Theres no need to do else if(!rand) in the code you originally posted. By having your first case as if(rand) the only time this is true is when rand == true right? So the only other logical case is that rand == false, so there is no need to even have a second if statement checking this, because we know it can't be anything else.

Related

Tree traversing doesn't print desired solution

(java)
I have class called Node, which has following fields:
value (integer)
connectedNodes (array of Node objects, always has same size = 2)
combination (object of Combination class)
Combination class has one field called messageContext, let's just say that it's a message which needs to be shown on the screen when something happens (described later).
Also, we have one Tree object, which has only one field: root (Node object)
Now, let's say that we have one String called combinationStr = "1121". Now, we use Tree's method called addCombination:
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if(counter==combination.length()) {
return;
}
int value = combination.charAt(counter)-48;
if(current.connectedNodes[value-1]==null) {
current.connectedNodes[value-1] = new Node(value);
}
if(counter==combination.length()-1) {
current.combination = finalCombination;
return;
}
addCombination(finalCombination,current.connectedNodes[value-1],combination,counter+1);
}
finalCombination object is an object that is going to be assigned to the last Node's combination field, added to the Tree for one combinationStr. So, we use this function to create the Tree-like structure that has path: -1 (root) -> 1 -> 1 -> 2 -> 1
When we come to the last one, traversing the Tree, we should see message appear. This is the messageContext of finalCombination.
Okay so, now let's use while(true) loop that will let us input a number, which will be like a path-chooser. If we input 1, we will go to node 1 and have other options to choose.
While loop looks like this:
Scanner scanner = new Scanner(System.in);
Node currentNode = tree.root;
while(true) {
for(Node node: currentNode.connectedNodes) {
if(node!=null) {
System.out.print(node.value + " ");
continue;
}
System.out.print("nullnode ");
}
System.out.println("");
if(currentNode.combination!=null) {
System.out.println(currentNode.combination.messageContext);
}
if(currentNode.connectedNodes[0]==null && currentNode.connectedNodes[1]==null) {
currentNode = tree.root;
System.out.println("root");
}
int x = scanner.nextInt();
currentNode = tree.takeStep(currentNode,x);
}
So, what are we doing here is actually printing the value of current Node, then printing values of Node's we can go to. If Node doesn't exist, we print nullnode.
The takeStep() method looks like this:
public Node takeStep(Node current, int value) {
if(current.connectedNodes[value-1]!=null) {
return current.connectedNodes[value-1];
}
return this.root;
}
It just checks if there is a node we want to go to and returns that node, if it does. If it doesn't exist, it will return us to root.
But, what's the problem with this code ?
Well, look at the whole main class:
Tree tree = new Tree(new Node(-1));
String[] combination = {"1121","11","2212"};
for(String s: combination) {
Combination tempCombination = new Combination();
tempCombination.messageContext = s + " ova poruka";
tree.addCombination(tempCombination,tree.root,s,0);
tree.traverse(tree.root);
System.out.println("END");
}
Scanner scanner = new Scanner(System.in);
Node currentNode = tree.root;
while(true) {
System.out.println(currentNode.value);
for(Node node: currentNode.connectedNodes) {
if(node!=null) {
System.out.print(node.value + " ");
}
else {
System.out.print("nullnode ");
}
}
int x = scanner.nextInt();
if(currentNode.combination!=null) {
System.out.println(currentNode.combination.messageContext);
if(currentNode.connectedNodes[0]==null && currentNode.connectedNodes[1]==null) {
currentNode = tree.root;
break;
}
}
currentNode = tree.takeStep(currentNode,x);
}
When we enter number x, we will call takeStep and check if that node exists connected to current one. But the problem is: When we input 1, it prints everything normally, when we input 1 again, it prints everything normally, when we input 2, it prints everything normally... but when we input 1 again, it says there are 2 nullnodes, and for some reason it doesn't change to root. Can anyone help me please? Here are the full classes:
NODE:
public class Node {
int value;
Node[] connectedNodes = {null,null};
Combination combination;
public Node(int value) {
this.value = value;
this.combination = null;
}
}
TREE:
public class Tree {
Node root;
public Tree(Node root) {
this.root = root;
}
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if(counter==combination.length()) {
return;
}
int value = combination.charAt(counter)-48;
if(current.connectedNodes[value-1]==null) {
current.connectedNodes[value-1] = new Node(value);
}
if(counter==combination.length()-1) {
current.combination = finalCombination;
return;
}
addCombination(finalCombination,current.connectedNodes[value-1],combination,counter+1);
}
public void traverse(Node current) {
System.out.print(current.value+ " ");
for(Node node: current.connectedNodes) {
if(node!=null) {
traverse(node);
}
}
}
public Node takeStep(Node current, int value) {
if(current.connectedNodes[value-1]!=null) {
return current.connectedNodes[value-1];
}
return this.root;
}}
COMBINATION:
public class Combination {
String messageContext;
}
Can you please help me ? I just want to reset to root when it hasn't anywhere to go else ? Thank you in advance!
I ran your code and found out that you are storing the message context in the parent node instead of the actual node which marks the end of the combination. So I changed this piece of code in addCombination.
public void addCombination(Combination finalCombination, Node current, String combination, int counter) {
if (counter == combination.length()) {
//Storing at the original node.
current.combination = finalCombination;
return;
}
int value = combination.charAt(counter) - 48;
if (current.connectedNodes[value - 1] == null) {
current.connectedNodes[value - 1] = new Node(value);
}
addCombination(finalCombination, current.connectedNodes[value - 1], combination, counter + 1);
}
And changed following in the main code.
while (true) {
System.out.println(currentNode.value);
//Moved it up now as the node it self has the message context.
if (currentNode.combination != null) {
System.out.println(currentNode.combination.messageContext);
if (currentNode.connectedNodes[0] == null && currentNode.connectedNodes[1] == null) {
currentNode = tree.root;
continue;
}
}
for (Node node : currentNode.connectedNodes) {
if (node != null) {
System.out.print(node.value + " ");
} else {
System.out.print("nullnode ");
}
}
int x = scanner.nextInt();
currentNode = tree.takeStep(currentNode, x);
}
Now try the code it is resetting to root as expected.

Searching applicants by email through the Queue Class (listnode) fromt he GUI of the program

I have a program for my homework where we add/edit/remove/allocate students who have applied to uni/college with the contact details and ucas points. One of their contact details involves their email.
Basically I want to find an applicant I want to edit by email. I don't have much knowledge of list-nodes but I think I got it right, but it isn't working.
I've tried this with int search methods and it seems to work fine however with strings not so much.
This is from the AppGUI
if(e.getSource() == btnFind)
{
ApplicantQueue editApplicant = new ApplicantQueue();
String findEmail = txtFind.getText();
editApplicant.search(findEmail);
taEditDelteDisplay.setText(editApplicant.display());
if(editApplicant.getFront().getAppDetails().getEmail() == findEmail)
{
JOptionPane.showMessageDialog(null, "NOTICE, \nQualifications & UCAS Points have been cleared!\n you must re-enter this information!", "INFO", JOptionPane.INFORMATION_MESSAGE);
}
if(editApplicant.getFront().getAppDetails().getEmail() == null)
{
JOptionPane.showMessageDialog(null, "NONE FOUND, \nEmail not found.", "ERROR", JOptionPane.ERROR_MESSAGE);
}
This is from the queue class(listnodes)
public DegreeApp search(String email)
{
ListNode current = front;
while(current != null && current.getAppDetails().getEmail().equals(email) != false)
{
current = current.getLink();
}
if(current != null)
return current.getAppDetails();
else
return null;// dunno about this part so put it to null
}
//original int method
/*public int search(int reqNo)
{
int pos = 1;
ListNode current = front;
while(current != null && current.getAppDetails().getPriority() != reqNo)
{
current = current.getLink();
pos++;
}
if(current != null)
return pos;
else
return -1;
}*/
When they proper applicant is found by email, I want to be able to edit that given applicant, I have fully coded that part yet as I wanted to get the search working first, as you can see I've already made popups for when they're either found or that none exist.

A* algorithm infinite while-loop

I've been attempting to follow some pseudocode, namely
https://www.geeksforgeeks.org/a-search-algorithm/ &
http://mat.uab.cat/~alseda/MasterOpt/AStar-Algorithm.pdf ,
to create an A star pathfinding algorithm for a four-directional tile/cell-based map with obstacles. I understand the concept, and I could definitely explain how it should work in words/images, but putting it into code is proving challenging. For a few days now whenever I've run my program it crashes and I have to manually stop the application. I believe this is due to an infinite while-loop. This confuses me because the program should exit the while-loop once its found the end destination, but obviously that isn't working. This is the code which I think should make it exit the while-loop once the destination is found:
if (n.getX() == end.getX() && n.getY() == end.getY()) {
currentNode = n;
break;
}
I hope this isn't too much code to put in this post, but this is the meat of my algorithm with comments on what I think each piece is doing:
public void attempt2() {
double leastF = Integer.MAX_VALUE;
// Initializes the starting Node and, in the beginning, currentNode is the same
// as the starting node
Node start = new Node(r.getCell());
Node currentNode = start;
start.setParent(start);
closed.add(start);
open.add(start);
start.setEnd(destinationCP);
start.calculateH();
start.isCalculatedH();
while (open.size() > 0) {
// Finds the node with the least F score on Open
for (Node n : open) {
// Calculates the H-score if it hasn't been already
if (n.haveNotCalculatedH()) {
n.setEnd(destinationCP);
n.calculateH();
n.isCalculatedH();
}
// Calculates the g-score, with 1 being the value/distance of a cell
n.setAdditiveDistanceG(n.getAdditiveDistanceG() + 1);
// Calculates the F-score
n.calculateF();
// Actually finds the least F score in the open list and sets currentNode to the
// node with the least F
if (n.getTotalCostF() < leastF) {
leastF = n.getTotalCostF();
currentNode = n;
}
}
//
// Creates easy-access variables for the x and y values of the node on open with
// the least F score
int thisX = currentNode.getX();
int thisY = currentNode.getY();
// if this cell (cell in open w least F) is the end destination cell, stop the calculations
if (thisX == end.getX() && thisY == end.getY()) {
break;
}
//
// Generate 1-4 successors if Robot can pass into the cell
if (World.getCell(thisX + 1, thisY).canEnter(r)) {
successors.add(new Node(World.getCell(thisX + 1, thisY)));
}
if (World.getCell(thisX, thisY + 1).canEnter(r)) {
successors.add(new Node(World.getCell(thisX, thisY + 1)));
}
if (World.getCell(thisX - 1, thisY).canEnter(r)) {
successors.add(new Node(World.getCell(thisX - 1, thisY)));
}
if (World.getCell(thisX, thisY - 1).canEnter(r)) {
successors.add(new Node(World.getCell(thisX, thisY - 1)));
}
//
/*
* Loops through each of the 1-4 neighbors to currentNode (I need to add in to
* erase & add to open/closed every one in here so its empty before new ones are
* generated
*/
for (Node n : successors) {
double successorCurrentCost = 0;
// if this successor is already in the closed list, skip doing all the code for
// this node and add this successor's parent (currentNode) to the closed list
if (isInClosed(n)) {
continue;
}
// if this is the goal/end node, exit the 'successors' for-loop. the step that
// follows this (exiting the loop) is that this particular node/successor is
// added to the closed list
if (n.getX() == end.getX() && n.getY() == end.getY()) {
currentNode = n;
break;
}
//
// Calculates the F cost for each successor to currentNode
if (n.haveNotCalculatedH()) {
n.setEnd(destinationCP);
n.calculateH();
n.isCalculatedH();
}
n.setAdditiveDistanceG(n.getAdditiveDistanceG() + currentNode.getAdditiveDistanceG());
n.calculateF();
successorCurrentCost = n.getTotalCostF();
//
if (!isInOpen(n) && n.getAdditiveDistanceG() > successorCurrentCost
|| n.getAdditiveDistanceG() > successorCurrentCost && !isInClosed(n)) {
open.add(n);
if (n.haveNotCalculatedH()) {
n.setEnd(destinationCP);
n.calculateH();
n.isCalculatedH();
}
} else if (isInClosed(n) && n.getAdditiveDistanceG() <= successorCurrentCost) {
successorCurrentCost = n.getAdditiveDistanceG();
n.setParent(currentNode);
} else {
successorCurrentCost = n.getAdditiveDistanceG();
n.setParent(currentNode);
}
if (isInClosed(n)) {
closed.remove(n);
open.add(n);
}
}
closed.add(currentNode);
if (thisX == end.getX() && thisY == end.getY()) {
break;
}
}
if (currentNode.getMyCell() != this.destinationCP) {
System.out.println("ERROR: open list is empty");
return;
} else {
createPath();
}
}
I am aware that there are a few things that should be changed in this code, however I am most concerned about the while loop never being terminated. Any other comments about my code are appreciated but definitely not necessary.

How can I allow duplicates in a custom Ordered Linked List class?

I had an assignment where I was to create a custom Ordered Linked List from scratch. I was happy to receive an near perfect score on the assignment, but I was counted off for not allowing duplicates. Let's say I add "A", and then "A" again. It only prints one "A". Does anyone have any suggestions on how I could implement this? I'll show my add method. If anyone wants more code, feel free to ask and I'll gladly provide.
NOTE: The assignment is already complete, so it's already been graded.
public boolean add(Comparable obj) {
// TODO: Implement this method (8 points)
//FOR REFERENCE - public OrderedListNode(Comparable item, OrderedListNode previous, OrderedListNode next) {
try {
OrderedListNode node; //create new OrderedListNode for comparison
for (node = head; node.next != tail; node = node.next) { //loop one node at a time until next node is tail
int compare = obj.compareTo(node.next.dataItem); //compare current object with next node
if (compare == 0) {
return false; // Nope
}
if (compare < 0) { //obj is less than next node, so insert previous next
break;
}
}
OrderedListNode newNode = new OrderedListNode(obj, node, node.next);
newNode.next.previous = newNode; //swapping nodes
node.next = newNode;
System.out.println("Added: " + obj); //display elements added
modCount++; //another modification
theSize++; //increment size by 1
} catch (ClassCastException e) { //give message to user
System.out.println(RED + "Caught Exception" + RESET_COLOR);
System.out.println("'" + obj +"'" + RED + " not added" + RESET_COLOR);
}
return true; //successful add
}
Change
if (compare == 0) {
return false; // Nope
}
if (compare < 0) { //obj is less than next node, so insert previous next
break;
}
to
if (compare <= 0) { //obj is less than or equal next node, so insert previous next
break;
}
To me it looks like this will allow you to still insert the item if it is equal to another item.

Java Binary Tree insert method not working

I am making a recursive insert method for a binary tree. This method is not able to add nodes to the tree. i cant seem to find whats wrong with this method. the constructor takes a string label for the child and a parent node.
public void insert(String aLabel) {
//if compare is positive add to right else add to left
//basis case:
BSTreeNode aNode = new BSTreeNode(aLabel,null);
if (aNode.parent == null) {
aNode.parent = this;
}
inserts(this,aNode);
}
private void inserts(BSTreeNode aParent, BSTreeNode aNode){
//initially the root node is the parent however a proper parent is found thorough recursion
//left recursion:
if(aParent.getLabel().compareTo(aNode.getLabel()) <= 0) {
if (this.childrenLeft == null) {
this.childrenLeft = aNode;
aNode.parent = this;
return;
} else {
childrenLeft.inserts(childrenLeft, aNode);
}
}
//right recursion
else {
if (this.childrenRight==null) {
this.childrenRight = aNode;
return;
}
else{
childrenRight.inserts(childrenRight,aNode);
}
}
}
EDIT: This answer refers to the original version of the question.
When you call inserts(this.childrenLeft, aNode); you are still at the same node; i.e. this still refers to the old parent.
Instead you should do something like:
childrenLeft.insert(childrenLeft, aNode);
In fact, the first parameter of insert is redundant, you should refactor to remove it.
I think you may need something like this.
The code is commented so you understand what is going on...
// insert method takes The Node as a param and a value to store in BT
public void insert(Node node, int value) {
//Check that the value param is less than the Node (root) value,
// If so insert the data to the left of the root node. Else insert
// the right node as it is a larger number than root
if (value < node.value) {
if (node.left != null) {
insert(node.left, value);
} else {
System.out.println(" Inserted " + value + " to left of "
+ node.value);
node.left = new Node(value);
}
} else if (value > node.value) {
if (node.right != null) {
insert(node.right, value);
} else {
System.out.println(" Inserted " + value + " to right of "
+ node.value);
node.right = new Node(value);
}
}
}

Categories

Resources