Breadth-first search from one node to another - java

I'm implementing my own graph class, and I'm currently making my own BFS-search method. Right now it traverses all vertices from one root vertex.
public List<T> breadthFirstSearch(T start, T end) {
List<T> visited = new ArrayList<T>();
Queue<T> path = new LinkedList<T>();
visited.add(start);
path.add(start);
while (!path.isEmpty()){
T currentNode = path.poll();
for (Edge<T> edge: graphRep.get(currentNode)) {
if (!visited.contains(edge.node)) {
visited.add(edge.node);
path.add(edge.node);
}
}
}
System.out.println(visited);
return visited;
}
What I want to do is to find the path from vertex start to vertex end, but right now it finds the path between the start to all nodes. How do I change my code so that it only finds the path between the start to end?

There are several mistakes in your solution:
you not checking whether you find the target node;
case, when it is not possible to reach the end from the start node, is not covered in your solution;
the list visited will contain all a sequence of visited nodes, but not a path from the start node to end node;
method contains() costs O(n) for a list, you definitely have to use a HashSet for that purpose;
ArrayDeque will perform better than LinkedList (technically it's not a mistake but rather a strong recommendation).
So to fix your code you need to add a check whether the node to which points the current edge is equal to the end node and a boolean flag to break out from the loop (there's no need to do farther iterations).
In the code below HashMap paths is used for two purposes:
to track the parent node for each visited node in order to restore the path from start to end;
to check whether a new node is already visited.
Method getPath() will either return list nodes that represents a direct path from start to end an empty list if the path doesn't exist.
public List<T> breadthFirstSearch(T start, T end) {
Map<T, T> paths = new HashMap<>();
Queue<T> queue = new ArrayDeque<>();
queue.add(start);
paths.put(start, null);
boolean isFound = false;
while (!isFound && !queue.isEmpty()) {
T currentNode = queue.remove();
for (Edge<T> edge : graphRep.get(currentNode)) {
if (paths.containsKey(edge.node)) {
continue;
}
paths.put(edge.node, currentNode);
// end node was found
if (edge.node.equals(end)) {
isFound = true;
break;
}
}
}
return getPath(start, end, paths);
}
public List<T> getPath(T start, T end, Map<T, T> paths) {
List<T> path = new ArrayList<T>();
T current = end;
path.add(current);
while (current != start && current != null) { // if there's no path from start to end current eventually will become null
path.add(paths.get(current));
current = paths.get(current);
}
System.out.println(path);
Collections.reverse(path);
return current != null ? path : Collections.emptyList();
}

Related

Implementing a BFS-search method for a graph

I'm implementing my own graph class. My undirected graph is represented by a map which maps every node to a list storing the edges it has.
private Map<T, List<Edge<T>>> graphRep = new HashMap<>();
private static class Edge<T> {
int cost;
T node;
public Edge(T n, int w) {
node = n;
cost = w;
}
I have already created a recursive depth-first traversal method for my graph which utilizes a map to store the path between the start node to the search node. It does by mapping every node the next node on the path between the start node to end node.
#Override
public List<T> depthFirstSearch(T start, T end) {
Set<T> visited = new HashSet<T>();
Map<T,T> path = new HashMap<>();
recursiveDFS(start, end, visited,path);
List<T> myList = new ArrayList<T>();
T current = end;
myList.add(current);
while (current != start) {
myList.add(path.get(current));
current = path.get(current);
}
System.out.println(path);
System.out.println(myList);
Collections.reverse(myList);
return myList;
}
private void recursiveDFS (T node, T end, Set<T> visited, Map<T, T> path) {
// uppdatera path och visited
visited.add(node);
for (Edge<T> e : graphRep.get(node)) {
if (e.node == end) {
path.put(e.node, node);
return;
}
if (!visited.contains(e.node)){
path.put(e.node, node);
recursiveDFS(e.node, end, visited, path);
}
}
}
I believe I can utilize essentially the same code for the breadth-first search as with the depth-first search, only that the instead of traversing the nodes by depth I traverse them by breadth, and that's where I'm stuck. I'm completely lost on how to do that.
#Override
public List<T> breadthFirstSearch(T start, T end) {
Set<T> visited = new HashSet<T>();
Map<T,T> path = new HashMap<>();
recursiveBFS(start, end, visited,path);
List<T> myList = new ArrayList<T>();
T current = end;
myList.add(current);
while (current != start) {
myList.add(path.get(current));
current = path.get(current);
}
System.out.println(path);
System.out.println(myList);
Collections.reverse(myList);
return myList;
}
public void recursiveBFS (T node, T end, Set<T> visited, Map<T, T> path) {
visited.add(node);
for (Edge<T> e : graphRep.get(node)) {
if (e.node == end) {
path.put(e.node, node);
return;
}
if (!visited.contains(node)) {
//Here's where I'm stuck. I have no idea how to traverse the graph by breadth
}
}
}
How do I complete my breadth-first traversal method?
BFS requires a container that will allow to retrieve nodes in the order they were visited. It can't be achieved with a Map. You need a Queue for that purpose (take a look carefully at the description of this algorithm).
Note that although BFS could be implemented recursively, the iterative approach is way better for this task.
Firstly, you need to create a queue and add a starting node into it. Then the queue will be passed as an argument to the recursiveBFS().
At each call of the recursiveBFS() a node at the beginning of the queue will be removed. If the queue is empty that will mean that the start-node and end-node are not connected.
That is how recursive implementation might look like:
public List<T> breadthFirstSearch(T start, T end) {
Map<T, T> paths = new HashMap<>();
Queue<T> queue = new ArrayDeque<>();
queue.add(start);
recursiveBFS(end, new HashSet<>(), queue, paths);
return getPath(start, end, paths);
}
public void recursiveBFS(T end, Set<T> visited, Queue<T> queue, Map<T, T> paths) {
if (queue.isEmpty()) { // start-node and end-node are not connected
return;
}
T parentNode = queue.remove();
visited.add(parentNode);
for (Edge<T> edge : graphRep.get(parentNode)) { // avoid one-letter variables like "e" instead of edge
if (visited.contains(parentNode)) {
continue;
}
paths.put(edge.node, parentNode);
// end node was found
if (edge.node.equals(end)) { // don't compare object with "=="
return;
}
recursiveBFS(end, visited, queue, paths); // this line was missing
}
}
In order to make this solution adhere to the Single responsibility principle I extracted the logic for restoring the path from the start-node to end-node from the breadthFirstSearch() into the separate method.
public List<T> getPath(T start, T end, Map<T, T> paths) {
List<T> path = new ArrayList<T>();
T current = end;
path.add(current);
while (current != start && current != null) { // if there's no path from start to end current eventually will become null
path.add(paths.get(current));
current = paths.get(current);
}
System.out.println(path);
Collections.reverse(path);
return current != null ? path : Collections.emptyList();
}
Recommendations:
The most important I want to point out is the overall design of your graph. While traversing the graph you heavily rely on the Map<T, List<Edge<T>>> graphRep, edges are helpless without it. You might consider refining your graph so that its elements will be more self-contained. Firstly, in my opinion, the edge of a graph has to have two references because by definition it is meant to represent a connection between two vertices of the graph. And if you add a Vertex class to your graph then will contain reference a collection of edges then you can implement graph traversal algorithms using only edges and vertexes without a need to fall back on graphRep.
don't compare object with ==, use equals() method instead.
avoid one-letter variables like e.
don't name like myList, but try to come up with the name that explains the purpose of this variable (like path).
Update
Below is an iterative implementation of BFS:
public List<T> breadthFirstSearch(T start, T end) {
Map<T, T> paths = new HashMap<>();
Set<T> visited = new HashSet<>();
Queue<T> queue = new ArrayDeque<>();
queue.add(start);
visited.add(start);
boolean isFound = false;
while (!isFound && !queue.isEmpty()) {
T parentNode = queue.remove();
for (Edge<T> edge : graphRep.get(parentNode)) {
if (!visited.add(edge.node)) {
continue;
}
paths.put(edge.node, parentNode);
// end node was found
if (edge.node.equals(end)) {
isFound = true;
break;
}
}
}
return getPath(start, end, paths);
}
An iterative solution would be cleaner if you take into account recommendation above. And since for BFS as well as for DFS we don't need any information specific to edges (because vertex (node) can store data about adjusent vertexes) these algorithms could be implemented using vertecies only.

How to obtain all the nodes in a path from breadth first search of a graph

Suppose we have a simple graph like this:
It was easy to find a path from start node to end node with depth-first search, but I got stuck while trying to do the same thing with breadth-first search. My code is as follows:
public List<String> getPathBreadth(String name1, String name2) {
Node node1 = getNode(name1);
Node node2 = getNode(name2);
if (node1 == null || node2 == null) {
return null;
}
return getPathBreadth(node1, node2, new HashSet<String>(), new LinkedList<Node>());
}
private List<String> getPathBreadth(Node start, Node destination, HashSet<String> visited, Queue<Node> queue) {
List<String> path = new ArrayList<String>();
if (start == destination) {
path.add(start.name);
return path;
}
visited.add(start.name);
queue.offer(start);
while (queue.size() > 0) {
Node cur = queue.poll();
for (String friend : cur.friends) {
if (visited.contains(friend)) {
continue;
}
visited.add(friend);
if (getNode(friend) == destination) {
path.add(friend); // I got the final node, I could also add cur, but how do I get the previous nodes along the path
return path;
}
queue.offer(getNode(friend));
}
}
return path;
}
Suppose we want to go from John to Linda, so I wish to return something like [Linda, Robert, John] or [Linda, Patrica, John], but the best I can do for now is get the last and second to the last nodes. In this case they are Linda and Robert. How do I get all the previous nodes along the path?
To make the code usable please add Node definition, and tree (test data).
(see mcve ).
I think the problem is here :
if (getNode(friend) == destination) {
path.add(friend);
return path;
}
The only node you add to the path in the last one. Try:
path.add(friend);
if (getNode(friend) == destination) {
return path; //or better: break;
}
Unfortunately I can't run and check it.
A side note:
visited.add(friend) Returns true if this set did not already contain friend
so:
if (visited.contains(friend)) {
continue;
}
visited.add(friend);
can be replaced with
if (! visited.add(friend)) {
continue;
}

Remove extra edge from BST

I have a BST which looks like below. How can I remove extra edge not needed from BST?
1->2, 1->3, 2->4, 2->5, 3->5
Should remove either 2->5 or 3->5
void BFS(int s)
{
// Mark all the vertices as not visited(By default
// set as false)
boolean visited[] = new boolean[V];
// Create a queue for BFS
LinkedList<Integer> queue = new LinkedList<Integer>();
// Mark the current node as visited and enqueue it
visited[s]=true;
queue.add(s);
while (queue.size() != 0)
{
// Dequeue a vertex from queue and print it
s = queue.poll();
System.out.print(s+" ");
// Get all adjacent vertices of the dequeued vertex s
// If a adjacent has not been visited, then mark it
// visited and enqueue it
Iterator<Integer> i = adj[s].listIterator();
while (i.hasNext())
{
int n = i.next();
if (!visited[n])
{
visited[n] = true;
queue.add(n);
}
}
}
}
What you have is not a tree, it's a Directed Acyclic Graph (DAG):
The algorithm you are looking for is a Spanning Tree Algorithm. One of the simplest ways to find it is to run through your graph depth-first, and mark graph nodes as you find them. If an edge takes you to a node that you have already seen, remove the edge and continue. Once you are done with the depth-first walk, the remaining graph is a tree.
What you want to implement is a self balancing binary tree. An AVL tree is one such. The Wiki page has some well commented pseudo code which should't be terribly difficult to implement in Java.
A web search will reveal plenty of examples.
// **Assuming we are maintaining a isVisited flag inside tree node. We can implement this in separate array but for simplicity I assumed it to be inside the node.**
boolean removeBadEdge(Node root) {
if (root == null)
return false;
if (root.left != null && root.left.isVisited)
{
root.left = null; // Removing the bad edge
return true;
}
if (root.right!= null && root.right.isVisited)
{
root.right= null; // Removing the bad edge
return true;
}
root.isVisited = true;
boolean leftEdgeRemoved = removeBadEdge(root.left);
boolean rightEdgeRemoved = false;
if (!leftEdgeRemoved) { // call right only if not removed in left for optimization
rightEdgeRemoved = removeBadEdge(root.right);
}
return leftEdgeRemoved || rightEdgeRemoved;
}

Swap collections during iteration

I have a List of Nodes which contains nested list of child nodes. I am trying to iterate through all of them to find a particular node.Currently I start at the child nodes from the root level, then go one level deep to sub child node and so on using for-each loop.
This is my code:
List<Node> children = root.getChildren();
boolean found = false;
while (!found) {
for (Node node : children) {
if (!node.getData().toString().toUpperCase().contains("BRANCH")) {
if(condition){//some processing}
} else {
//swap children with sub children
if (children.get(0) != null) {
children = children.get(0).getChildren(); // this operation is not possible during iteration
}
}
} else {
continue;
}
}
}
}
If child node doesn't find any match, then I need to swap the collection with sub child node and continue iteration and so on.
Is there a better way to iterate through a nested nodelist of children?
Instead of swapping the collections, you could add the elements to a queue, and keep iterating till the queue is empty (i.e. you didn't find a match). Or you do find a match and return early.
public static void algorithm(Node root) {
Queue<Node> q = new LinkedList<>();
q.add(root);
while(!q.isEmpty()) {
Node current = q.poll();
if(current .getData().toString().toUpperCase().contains("BRANCH")) {
continue;
}
if(condition){
//some processing
return;
} else {
q.addAll(current.getChildren());
}
}
}
algorithm(root);
You can't swap like this mid-iteration. Remember that your for loop is translated in Java like this:
for (Iterator<Node> it = children.iterator(); it.hasNext(); ) {
Node node = it.next();
// The rest of it
}
So even if you change what children is, your iterator stays as it is.
I would suggest using a Queue to help you here.
PS Do you really want to skip all of the non-first children? That appears to be what you're currently doing.

adding and removing from a singly linked list

I thought I had understanding of this in my previous question about linked lists, but I was terribly mistaken, I'm just as lost as I was when I initially posted.
I realize that I'm technically asking two questions, but hopefully getting at least one should make the other easy (assuming they are just reverse of each other).
I have 3 classes already given to me, they are:
SLinkedList.java
package chapter3.linkedList;
public class SLinkedList<V> {
// instance variables. Add the tail reference.
protected Node<V> head, tail;
protected long size;
// methods, empty list constructor first
public SLinkedList () {
head = null;
tail = null;
size = 0;
} // end constructor of a SLinkedList
// method to add nodes to the list. Storage space for the node
// is already allocated in the calling method
public void addFirst (Node<V> node) {
// set the tail only if this is the very first node
if (tail == null)
tail = node;
node.setNext (head); // make next of the new node refer to the head
head = node; // give head a new value
// change our size
size++;
} // end method addFirst
// addAfter - add new node after current node, checking to see if we are at the tail
public void addAfter (Node<V>currentNode, Node<V>newNode) {
if (currentNode == tail)
tail = newNode;
newNode.setNext (currentNode.getNext ());
currentNode.setNext (newNode);
// change our size
size++;
} // end method addAfter
// addLast - add new node after the tail node. Adapted from Code Fragment 3.15, p. 118.
// Mike Qualls
public void addLast (Node<V> node) {
node.setNext (null);
tail.setNext (node);
tail = node;
size++;
} // end method addLast
// methods to remove nodes from the list. (Unfortunately, with a single linked list
// there is no way to remove last. Need a previous reference to do that. (See
// Double Linked Lists and the code below.)
public Node<V> removeFirst () {
if (head == null)
System.err.println("Error: Attempt to remove from an empty list");
// save the one to return
Node<V> temp = head;
// do reference manipulation
head = head.getNext ();
temp.setNext(null);
size--;
return temp;
} // end method removeFirst
// remove the node at the end of the list. tail refers to this node, but
// since the list is single linked, there is no way to refer to the node
// before the tail node. Need to traverse the list.
public Node<V> removeLast () {
// // declare local variables/objects
Node<V> nodeBefore;
Node<V> nodeToRemove;
// make sure we have something to remove
if (size == 0)
System.err.println("Error: Attempt to remove fron an empty list");
// traverse through the list, getting a reference to the node before
// the trailer. Since there is no previous reference.
nodeBefore = getFirst ();
// potential error ?? See an analysis and drawing that indicates the number of iterations
// 9/21/10. size - 2 to account for the head and tail nodes. We want to refer to the one before the
// tail.
for (int count = 0; count < size - 2; count++)
nodeBefore = nodeBefore.getNext ();
// save the last node
nodeToRemove = tail;
// now, do the pointer manipulation
nodeBefore.setNext (null);
tail = nodeBefore;
size--;
return nodeToRemove;
} // end method removeLast
// method remove. Remove a known node from the list. No need to search or return a value. This method
// makes use of a 'before' reference in order to allow list manipulation.
public void remove (Node<V> nodeToRemove) {
// declare local variables/references
Node<V> nodeBefore, currentNode;
// make sure we have something to remove
if (size == 0)
System.err.println("Error: Attempt to remove fron an empty list");
// starting at the beginning check for removal
currentNode = getFirst ();
if (currentNode == nodeToRemove)
removeFirst ();
currentNode = getLast ();
if (currentNode == nodeToRemove)
removeLast ();
// we've already check two nodes, check the rest
if (size - 2 > 0) {
nodeBefore = getFirst ();
currentNode = getFirst ().getNext ();
for (int count = 0; count < size - 2; count++) {
if (currentNode == nodeToRemove) {
// remove current node
nodeBefore.setNext (currentNode.getNext ());
size--;
break;
} // end if node found
// change references
nodeBefore = currentNode;
currentNode = currentNode.getNext ();
} // end loop to process elements
} // end if size - 2 > 0
} // end method remove
// the gets to return the head and/or tail nodes and size of the list
public Node<V> getFirst () { return head; }
public Node<V> getLast () { return tail; }
public long getSize () { return size; }
} // end class SLinkedList
There's also Node.java
package chapter3.linkedList;
public class Node<V>
{
// instance variables
private V element;
private Node<V> next;
// methods, constructor first
public Node ()
{
this (null, null); // call the constructor with two args
} // end no argument constructor
public Node (V element, Node<V> next)
{
this.element = element;
this.next = next;
} // end constructor with arguments
// set/get methods
public V getElement ()
{
return element;
}
public Node<V> getNext ()
{
return next;
}
public void setElement (V element)
{
this.element = element;
}
public void setNext (Node<V> next)
{
this.next = next;
}
} // end class Node
and finally GameEntry.java
package Project_1;
public class GameEntry
{
protected String name; // name of the person earning this score
protected int score; // the score value
/** Constructor to create a game entry */
public GameEntry(String name, int score)
{
this.name = name;
this.score = score;
}
/** Retrieves the name field */
public String getName()
{
return name;
}
/** Retrieves the score field */
public int getScore()
{
return score;
}
/** Returns a string representation of this entry */
public String toString()
{
return name + ", " + score + "\n";
}
}
EDIT POINT
I created a driver called Scores.java, in it so far all I have is **I have added what I THINK i need for the classes, I'm probably wrong though:
package Project_1;
import chapter3.linkedList.*;
import java.util.*;
/** Class for storing high scores in an array in non-decreasing order. */
public class Scores
{
//add function
public SLinkedList<GameEntry> add(GameEntry rank, SLinkedList<GameEntry> scores)
{
Node<GameEntry> currentNode = scores.getFirst();
Node<GameEntry> nextNode = null;
Node<GameEntry> previousNode = null;
Node<GameEntry> newNode = new Node<GameEntry>();
newNode.setElement(rank);
if(scores.getSize() == 0)
{
scores.addFirst(newNode);
}
else
{
while(currentNode != null)
{
nextNode = currentNode.getNext();
if(nextNode == null)
{
scores.addLast(newNode);
}
else
{
scores.addAfter(currentNode, newNode);
break;
}
previousNode = currentNode;
currentNode = currentNode.getNext();
}
}
return scores;
}
//remove function
public void remove(int i)
{
}
//print function
/*gameenter printing;
printing=node.Getelement; //pseudo code for making it work right
print(printing.getscore)
print(print.getname)
*/
public void print(SLinkedList<GameEntry> scores)
{
Node<GameEntry> currentNode = scores.getFirst();
GameEntry currentEntry = currentNode.getElement();
System.out.printf("[");
for(int i = 0; i < scores.getSize(); i++)
{
System.out.printf(", %s", currentEntry.toString());
currentNode = currentNode.getNext();
currentEntry = currentNode.getElement();
}
System.out.println("]");
}
}
I have my test driver called ScoresTest.java, that I have pretty much filled out:
package Project_1;
import chapter3.linkedList.SLinkedList;
public class ScoresTest {
/**
* #param args
*/
public static void main(String[] args)
{
SLinkedList<GameEntry> highScores = new SLinkedList<GameEntry>(); //Linked List for Game Entry
GameEntry entry;
Scores rank = new Scores();
entry = new GameEntry("Flanders", 681);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Krusty", 324);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Otto", 438);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Bart", 875);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Homer", 12);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Lisa", 506);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Maggie", 980);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Apoo", 648);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Smithers", 150);
highScores = rank.add(entry, highScores);
entry = new GameEntry("Burns", 152);
highScores = rank.add(entry, highScores);
System.out.println("The Original High Scores");
rank.print(highScores);
entry = new GameEntry("Moe", 895);
highScores = rank.add(entry, highScores);
System.out.println("Scores after adding Moe");
rank.print(highScores);
//highScores = rank.remove(4);
System.out.println("Scores after removing Apoo");
rank.print(highScores);
}
}
That's entirely finished, pretty sure I have nothing left to add for it.
I'm not looking for someone to answer it for me, but I have no clue where to start or how to make the add or remove function, in any way. This is an intermediate course, the book does nothing for explaining linked lists (go ahead and look for yourself if you don't believe me, text is called Datastructures and Algorithms in Java, 5th edition). It shows how to do such with an array quite easily...which works perfectly for a linked list, but apparently the teacher does not want us doing it this way, so sadly I am now utterly lost on how to do this.
I've tried looking at other peoples answers on here, and google, and so far nothing has clicked or made any sense at all, I just can't grasp how it works, and the teacher's explanation and example was only to draw boxes on the board, I've never seen a sort, add, or remove function coded for a linked list...can't know what I've not been taught or can't locate.
Any help is greatly appreciated, and thank you in advance!
EDIT
I looked at the import java.util.*; and the commands within it for linked lists, they seem painfully easy. to remove I'd just use list.sublist(i, i).clear(); and the value I wish to remove is removed, super easy, it seems to be just trying to utilize the slinkedlist.java and node.java, I just can't seem to follow them in any way shape or form. I believe the teacher did indeed write them, and I've tried asking for his assistance, stayed 2 hours after class trying to get any understanding from him, and as you can see it did not help much at all. Thank you again for the assistance!
EDIT
I also apologize if this seems like it is vague, but I don't have a specific point where my confusion seems linked, I understand linked lists if we're talking about the java.util.linkedList;, but as far as using what I've been given in this circumstance, I can't follow the logic at all, leaving me quite lost and unsure of where to begin.
In pseudo-code (please note I am not including bound checking etc, simply the logic)
To add a node to the front of the list:
newNode->nextNode = startNode
startNode = newNode
To add to a specific index:
index = 0
currentNode = startNode
// find the node in the list. here you will need to do all kinds of bound checking
while index is less than position
currentNode = currentNode.nextNode // move your node pointer to the position
increment index
// so here we basically insert the new node into the list. what needs to happen is
// to NOT break the list by forgetting the node after the current node. this is why
// we first set the new nodes' next one, to the current nodes' (the one already in
// the list) next node. this way, we still have all the information we need. then,
// when we set the current nodes' next node to the new node, we essentially "break"
// the link and "repair" it by adding the new link.
newNode.nextNode = currentNode.nextNode // some more bound checking required
currentNode.nextNode = newNode
To remove from a specific index:
index = 0
delNode = startNode
// find the node in the list. here you will need to do all kinds of bound checking
while index is less than (position - 1)
delNode = delNode.nextNode // move your node pointer to the position
increment index
delNode.nextNode = delNode.nextNode.nextNode
// that's it. by setting the node's (before the one you whish to delete)
// next node to the node AFTER the one you want to delete, you basically
// "skip" over that node. since it is no longer referenced, the garbage
// collector will take care of the rest. if you wish to return that node
// you can do it quite easily by remembering it.
storeNode = delNode.nextNode // some more bound checking required
delNode.nextNode = delNode.nextNode.nextNode // some more bound checking required
// now you still have a reference to the deleted node in storeNode
UPDATE
OK, so if I understand correctly, you need to create a linked list that stores scores in a ascending order. As far as I can see, the entire linked list has been implemented for you, you simply need to use the classes provided, and add the logic in Scores.java to keep the list sorted.
First off, I see your nodes are not comparable. If you are at all allowed to change the source given to you, I would suggest having them implement Comparable<Node> and also override the equals(Object o) so that you have logic to compare them. Two nodes can contain the same element, but that does not mean that they are equal.
Please note the change in the method signatures!
//add function
public void add(Node<GameEntry> score) {
// adding is where you now want to keep everything sorted. so I highly
// recommend that you implement `Comparable` as I mentioned above. if not,
// you have to put the logic in here.
Node<GameEntry> currentNode = highScored.getFirst();
Node<GameEntry> prevNode = null;
// if the list is empty, or the new node must go in before the head,
// simply add it as the head.
if (highScores.size() == 0 || score.compareTo(currentNode) < 0) {
highScores.addFirst(score);
}
// search for the position of the new node. while the node has a higher score
// than the current node, we need to continue on so we can place it in the
// correct place.
while (currentNode != null && currentNode.compareTo(score) > 0) {
prevNode = currentNode;
currentNode = currentNode.getNext();
}
// if the currentNode is null, it means it is the highest score, so
// we can simply add it to the end
if (currentNode == null) {
highScores.addLast(score);
} else {
// otherwise just add it after the correct node
highScores.addAfter(prevNode, score);
}
}
//remove function
public void remove(Node<GameEntry> score) {
// removing an element should be as described above. if you keep
// your list sorted during the ADD method, removing any element
// should not break the order.
// find the element - removal from a linked list is O(n),
// since we need to know what the element BEFORE the one
// is that you want to remove. assuming you have implemented
// the equals method to check equality of nodes:
Node<GameEntry> currentNode = highScores.getFirst();
Node<GameEntry> prevNode = null;
while (currentNode != null && !currentNode.equals(score)) {
prevNode = currentNode;
currentNode = currentNode.getNext();
}
// if currentNode is null, the node we wanted to remove was not
// in the list.
if (currentNode == null) {
System.out.println("Node not found");
return;
}
// now, we need to check if there is a node after the one we want
// to remove.
if (prevNode.getNext().getNext() != null) {
// if there is, we follow the logic from the pseudo code
prevNode.setNext(prev.getNext().getNext());
} else {
// if not, we only need to remove the last entry (since the
// one we want to remove is the last one)
highScores.removeLast();
}
}
IMPORTANT
Please just double check the logic here. I did it really quickly without an IDE as I'm not at my development computer at the moment. If anyone finds any issues, please leave a comment and I'll fix it.
If this is not exactly what you asked (your question is a bit vague), let me know.
UPDATE 2
Read up on Comparators here, here and here.

Categories

Resources