I'm having trouble figuring out why my code won't parse through the ListNodes in the Lists, in order to add a new String as a ListNode. I'm trying to write the function add(String s), to add a new ListNode to the List. If the list is empty, I just add the String as a ListNode, and if not, I parse through using node and myNext, and then if node.myNext is null, I replace it with the newly created ListNode. What is the reason this isn't working? It either does not throw an output or it says it is out of bounds.
public class List {
private ListNode myHead;
private int mySize;
public List() {
this.myHead = null;
this.mySize = 0;
}
public class ListNode {
public String myData;
public ListNode myNext;
public ListNode(String element, ListNode next) {
this.myData = element;
this.myNext = next;
}
public ListNode(String element) {
this(element, null);
}
public boolean isEmpty() {
return this.length() == 0;
}
public void add(String s) {
if(this.isEmpty() == true) {
this.addToFront(s);
}
else {
this.mySize++;
for(ListNode node = this.myHead; node.myData != null; node = node.myNext) {
if(node.myNext == null) {
ListNode lno = new ListNode(s, null);
node.myNext = lno;
}
else {
node.myData = node.myData;
}
}
}
}
In you ListNode you can't access methods and variables of your List class.
Assuming that you want to add the new String at the top of your List you should do something like this:
public class List {
private ListNode myHead;
private int mySize;
public List() {
this.myHead = null;
this.mySize = 0;
}
public boolean isEmpty() {
return this.mySize == 0;
}
public void add(String s) {
this.myHead = new ListNode(s, myHead);//add new String as head element
this.mySize++;
}
}
public class ListNode {
public String myData;
public ListNode myNext;
public ListNode(String element, ListNode next) {
this.myData = element;
this.myNext = next;
}
public ListNode(String element) {
this(element, null);
}
}
If you want to add it at the end of your List you can try it like this:
public void add(String s) {
if(this.isEmpty()){
this.myHead = new ListNode(s, myHead);//add new String as head element
}else{
ListNode node = this.myHead;
while (node.myNext != null){
node = node.myNext;
}
//now you hav the last node of your list
node.myNext = new ListNode(s,null);
}
this.mySize++;
}
The code you have pasted is not complete.
Also, If I am correct, your List is having the ListNodes and thus, it is your List where you should put methods to check if it is Empty (does not have any ListNodes in it) or add, delete, count, search etc. functions.
For isEmpty(), There is no length() defined, so simply check the size to be == 0.
For add(), if it is empty just point myHead to your new ListNode; If you have to add in end, iterate the myHead using a currentNode reference, till its next is null and add.
If it is to be in middle somewhere, you will need to check for ListNode myData to decide where it fits white moving from myHead towards null and once you find a place to insert, you will need to change the [PrevNode] -> new ListNode -> [nextNode]
I am trying to implement a bi-directional graph search. As I understand, I should somehow merge two breadth-first searches, one which starts at the starting (or root) node and one which starts at the goal (or end) node. The bi-directional search terminates when both breadth-first searches "meet" at the same vertex.
Could you provide me with a code example (in Java, if possible) or link with code for the bidirectional graph search?
Assuming you have Nodes like this (in the file Node.java):
import java.util.HashSet;
import java.util.Set;
public class Node<T> {
private final T data; // The data that you want to store in this node.
private final Set<Node> adjacentNodes = new HashSet<>();
// Constructor
public Node(T data) {
this.data = data;
}
// Getters
/*
* Returns the data stored in this node.
* */
public T getData() {
return data;
}
/*
* Returns a set of the adjacent nodes of this node.
* */
public Set<Node> getAdjacentNodes() {
return adjacentNodes;
}
// Setters
/*
* Attempts to add node to the set of adjacent nodes of this node. If it was not previously added, it is added, and
* true is returned. If it was previously added, it returns false.
* */
public boolean addAdjacent(Node node) {
return adjacentNodes.add(node);
}
}
Then the bidirectional search algorithm (defined in the file BidirectionalSearch.java) would look something like this:
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import java.util.LinkedList;
public class BidirectionalSearch {
/*
* Returns true if a path exists between Node a and b, false otherwise.
* */
public static boolean pathExists(Node a, Node b) {
// LinkedList implements the Queue interface, FIFO queue operations (e.g., add and poll).
// Queue to hold the paths from Node a.
Queue<Node> queueA = new LinkedList<>();
// Queue to hold the paths from Node a.
Queue<Node> queueB = new LinkedList<>();
// A set of visited nodes starting from Node a.
Set<Node> visitedA = new HashSet<>();
// A set of visited nodes starting from Node b.
Set<Node> visitedB = new HashSet<>();
visitedA.add(a);
visitedB.add(b);
queueA.add(a);
queueB.add(b);
// Both queues need to be empty to exit the while loop.
while (!queueA.isEmpty() || !queueB.isEmpty()) {
if (pathExistsHelper(queueA, visitedA, visitedB)) {
return true;
}
if (pathExistsHelper(queueB, visitedB, visitedA)) {
return true;
}
}
return false;
}
private static boolean pathExistsHelper(Queue<Node> queue,
Set<Node> visitedFromThisSide,
Set<Node> visitedFromThatSide) {
if (!queue.isEmpty()) {
Node next = queue.remove();
Set<Node> adjacentNodes = next.getAdjacentNodes();
for (Node adjacent : adjacentNodes) {
// If the visited nodes, starting from the other direction,
// contain the "adjacent" node of "next", then we can terminate the search
if (visitedFromThatSide.contains(adjacent)) {
return true;
} else if (visitedFromThisSide.add(adjacent)) {
queue.add(adjacent);
}
}
}
return false;
}
public static void main(String[] args) {
// Test here the implementation above.
}
}
Logic:
In normal course, BFS is recursive. But here we cannot have it recursive because if we start with recursion, then it will cover all nodes from one side (start or end) and will only stop if it is not able to find the end or finds the end.
So in order to do a bidirectional search, the logic will be explained with the example below:
/*
Let's say this is the graph
2------5------8
/ |
/ |
/ |
1---3------6------9
\ |
\ |
\ |
4------7------10
We want to find the path between nodes 1 and 9. In order to do this we will need 2 DS, one for recording the path form beginning and other from end:*/
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> startTrav = new ArrayList<>();
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> endTrav = new ArrayList<>();
/*Before starting the loop, initialise these with the values shown below:
startTrav --> index=0 --> <1, {1}>
endTrav --> index=0 --> <9, {9}>
Note here that in the HashMap, the key is the node that we have reached and the value is a linkedList containing the path used to reach to that node.
Now inside the loop we will start traversal on startTrav 1st. We will traverse it from index 0 to 0, and while traversing what ever children are there for the node under process, we will add in startTrav. So startTrav will transform like:
startTrav --> index=0 --> <1, {1}>
startTrav --> index=1 --> <2, {1,2}>
startTrav --> index=2 --> <3, {1,3}>
startTrav --> index=3 --> <4, {1,4}>
Now we will check for collision, i.e if either of nodes that we have covered in startTrav are found in endTrav (i.e if either of 1,2,3,4 is present in endTrav's list = 9). The answer is no, so continue loop.
Now do the same from endTrav
endTrav --> index=0 --> <9, {9}>
endTrav --> index=1 --> <8, {9,8}>
endTrav --> index=2 --> <6, {9,6}>
endTrav --> index=3 --> <10, {9,10}>
Now again we will check for collision, i.e if either of nodes that we have covered in startTrav are found in endTrav (i.e if either of 1,2,3,4 is present in endTrav's list = 9,8,6,10). The answer is no so continue loop.
// end of 1st iteration of while loop
// beginning of 2nd iteration of while loop
startTrav --> index=0 --> <1, {1}>
startTrav --> index=1 --> <2, {1,2}>
startTrav --> index=2 --> <3, {1,3}>
startTrav --> index=3 --> <4, {1,4}>
startTrav --> index=4 --> <5, {1,2,5}>
startTrav --> index=5 --> <6, {1,3,6}>
startTrav --> index=6 --> <7, {1,4,7}>
Now again we will check for collision, i.e if either of nodes that we have covered in startTrav are found in endTrav (i.e if either of 1,2,3,4,5,6,7 is present in endTrav's list = 9,8,6,10). The answer is yes. Colission has occurred on node 6. Break the loop now.
Now pick the path to 6 from startTrav and pick the path to 6 from endTrav and merge the 2.*/
Code for this is as below:
class Node<T> {
public T value;
public LinkedList<Node<T>> nextNodes = new LinkedList<>();
}
class Graph<T>{
public HashMap<Integer, Node<T>> graph=new HashMap<>();
}
public class BiDirectionalBFS {
public LinkedList<Node<Integer>> findPath(Graph<Integer> graph, int startNode, int endNode) {
if(!graph.graph.containsKey(startNode) || !graph.graph.containsKey(endNode)) return null;
if(startNode==endNode) {
LinkedList<Node<Integer>> ll = new LinkedList<>();
ll.add(graph.graph.get(startNode));
return ll;
}
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> startTrav = new ArrayList<>();
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> endTrav = new ArrayList<>();
boolean[] traversedNodesFromStart = new boolean[graph.graph.size()];
boolean[] traversedNodesFromEnd = new boolean[graph.graph.size()];
addDetailsToAL(graph, startNode, startTrav, traversedNodesFromStart, null);
addDetailsToAL(graph, endNode, endTrav, traversedNodesFromEnd, null);
int collision = -1, startIndex=0, endIndex=0;
while (startTrav.size()>startIndex && endTrav.size()>endIndex) {
// Cover all nodes in AL from start and add new
int temp=startTrav.size();
for(int i=startIndex; i<temp; i++) {
recordAllChild(graph, startTrav, i, traversedNodesFromStart);
}
startIndex=temp;
//check collision
if((collision = checkColission(traversedNodesFromStart, traversedNodesFromEnd))!=-1) {
break;
}
//Cover all nodes in AL from end and add new
temp=endTrav.size();
for(int i=endIndex; i<temp; i++) {
recordAllChild(graph, endTrav, i, traversedNodesFromEnd);
}
endIndex=temp;
//check collision
if((collision = checkColission(traversedNodesFromStart, traversedNodesFromEnd))!=-1) {
break;
}
}
LinkedList<Node<Integer>> pathFromStart = null, pathFromEnd = null;
if(collision!=-1) {
for(int i =0;i<traversedNodesFromStart.length && (pathFromStart==null || pathFromEnd==null); i++) {
if(pathFromStart==null && startTrav.get(i).keySet().iterator().next()==collision) {
pathFromStart=startTrav.get(i).get(collision);
}
if(pathFromEnd==null && endTrav.get(i).keySet().iterator().next()==collision) {
pathFromEnd=endTrav.get(i).get(collision);
}
}
pathFromEnd.removeLast();
ListIterator<Node<Integer>> li = pathFromEnd.listIterator();
while(li.hasNext()) li.next();
while(li.hasPrevious()) {
pathFromStart.add(li.previous());
}
return pathFromStart;
}
return null;
}
private void recordAllChild(Graph<Integer> graph, ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> listToAdd, int index, boolean[] traversedNodes) {
HashMap<Integer, LinkedList<Node<Integer>>> record=listToAdd.get(index);
Integer recordKey = record.keySet().iterator().next();
for(Node<Integer> child:graph.graph.get(recordKey).nextNodes) {
if(traversedNodes[child.value]!=true) { addDetailsToAL(graph, child.getValue(), listToAdd, traversedNodes, record.get(recordKey));
}
}
}
private void addDetailsToAL(Graph<Integer> graph, Integer node, ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>> startTrav,
boolean[] traversalArray, LinkedList<Node<Integer>> oldLLContent) {
LinkedList<Node<Integer>> ll = oldLLContent==null?new LinkedList<>() : new LinkedList<>(oldLLContent);
ll.add(graph.graph.get(node));
HashMap<Integer, LinkedList<Node<Integer>>> hm = new HashMap<>();
hm.put(node, ll);
startTrav.add(hm);
traversalArray[node]=true;
}
private int checkColission(boolean[] start, boolean[] end) {
for (int i=0; i<start.length; i++) {
if(start[i] && end[i]) {
return i;
}
}
return -1;
}
}
A much more neater and easier to understand approach can be though Arrays. We will replace the complex DS :
ArrayList<HashMap<Integer, LinkedList<Node<Integer>>>>
with a simple
LinkedList<Node<Integer>>[]
Here, the index of the LL will define the numeric value of the node. So if the node has value 7, then the path to reach 7 will be stored at index 7 in the array. Also we will remove the boolean arrays for finding which path to which element is found as that can be achieved with our linkedList array itself. We will add 2
LinkedList<Node<Integer>>
which will be used for storing the children as in case of level order traversal of tree. Lastly, we for storing the path for traversal from end, we will store it in reverse order, so that while merging, we do not need to reverse the elements from the 2nd array. Code for this goes as below:
class Node<T> {
public T value;
public LinkedList<Node<T>> nextNodes = new LinkedList<>();
}
class Graph<T>{
public HashMap<Integer, Node<T>> graph=new HashMap<>();
}
public class BiDirectionalBFS {
private LinkedList<Node<Integer>> findPathUsingArrays(Graph<Integer> graph, int startNode, int endNode) {
if(!graph.graph.containsKey(startNode) || !graph.graph.containsKey(endNode)) return null;
if(startNode==endNode) {
LinkedList<Node<Integer>> ll = new LinkedList<>();
ll.add(graph.graph.get(startNode));
return ll;
}
LinkedList<Node<Integer>>[] startTrav = new LinkedList[graph.graph.size()];
LinkedList<Node<Integer>>[] endTrav = new LinkedList[graph.graph.size()];
LinkedList<Node<Integer>> traversedNodesFromStart = new LinkedList<>();
LinkedList<Node<Integer>> traversedNodesFromEnd = new LinkedList<>();
addToDS(graph, traversedNodesFromStart, startTrav, startNode);
addToDS(graph, traversedNodesFromEnd, endTrav, endNode);
int collision = -1;
while (traversedNodesFromStart.size()>0 && traversedNodesFromEnd.size()>0) {
// Cover all nodes in LL from start and add new
recordAllChild(traversedNodesFromStart.size(), traversedNodesFromStart, startTrav, true);
//check collision
if((collision = checkColission(startTrav, endTrav))!=-1) {
break;
}
//Cover all nodes in LL from end and add new
recordAllChild(traversedNodesFromEnd.size(), traversedNodesFromEnd, endTrav, false);
//check collision
if((collision = checkColission(startTrav, endTrav))!=-1) {
break;
}
}
if(collision!=-1) {
endTrav[collision].removeFirst();
startTrav[collision].addAll(endTrav[collision]);
return startTrav[collision];
}
return null;
}
private void recordAllChild(int temp, LinkedList<Node<Integer>> traversedNodes, LinkedList<Node<Integer>>[] travArr, boolean addAtLast) {
while (temp>0) {
Node<Integer> node = traversedNodes.remove();
for(Node<Integer> child : node.nextNodes) {
if(travArr[child.value]==null) {
traversedNodes.add(child);
LinkedList<Node<Integer>> ll=new LinkedList<>(travArr[node.value]);
if(addAtLast) {
ll.add(child);
} else {
ll.addFirst(child);
}
travArr[child.value]=ll;
traversedNodes.add(child);
}
}
temp--;
}
}
private int checkColission(LinkedList<Node<Integer>>[] startTrav, LinkedList<Node<Integer>>[] endTrav) {
for (int i=0; i<startTrav.length; i++) {
if(startTrav[i]!=null && endTrav[i]!=null) {
return i;
}
}
return -1;
}
private void addToDS(Graph<Integer> graph, LinkedList<Node<Integer>> traversedNodes, LinkedList<Node<Integer>>[] travArr, int node) {
LinkedList<Node<Integer>> ll = new LinkedList<>();
ll.add(graph.graph.get(node));
travArr[node]=ll;
traversedNodes.add(graph.graph.get(node));
}
}
Hope it helps.
Happy coding.
Try this:
Graph.java
import java.util.HashSet;
import java.util.Set;
public class Graph<T> {
private T value;
private Set<Graph> adjacents = new HashSet<>();
private Set<String> visitors = new HashSet<>();
public Graph(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public void addAdjacent(Graph adjacent) {
this.adjacents.add(adjacent);
}
public Set<Graph> getAdjacents() {
return this.adjacents;
}
public void setVisitor(String visitor) {
this.visitors.add(visitor);
}
public boolean hasVisitor(String visitor) {
return this.visitors.contains(visitor);
}
#Override
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("Value [").append(value).append("] visitors[");
if (!visitors.isEmpty()) {
for (String visitor : visitors) {
sb.append(visitor).append(",");
}
}
sb.append("]");
return sb.toString().replace(",]", "]");
}
}
GraphHelper.java
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
public class GraphHelper {
// implements singleton pattern
private static GraphHelper instance;
private GraphHelper() {
}
/**
* #return the instance
*/
public static GraphHelper getInstance() {
if (instance == null)
instance = new GraphHelper();
return instance;
}
public boolean isRoute(Graph gr1, Graph gr2) {
Queue<Graph> queue1 = new LinkedList<>();
Queue<Graph> queue2 = new LinkedList<>();
addToQueue(queue1, gr1, "1");
addToQueue(queue2, gr2, "2");
while (!queue1.isEmpty() || !queue2.isEmpty()) {
if (!queue1.isEmpty()) {
Graph gAux1 = queue1.remove();
Iterator<Graph> it1 = gAux1.getAdjacents().iterator();
while (it1.hasNext()) {
Graph adj1 = it1.next();
System.out.println("adj1 " + adj1);
if (adj1.hasVisitor("2"))
return true;
else if (!adj1.hasVisitor("1"))
addToQueue(queue1, adj1, "1");
}
}
if (!queue2.isEmpty()) {
Graph gAux2 = queue2.remove();
Iterator<Graph> it2 = gAux2.getAdjacents().iterator();
while (it2.hasNext()) {
Graph adj2 = it2.next();
System.out.println("adj2 " + adj2);
if (adj2.hasVisitor("1"))
return true;
else if (!adj2.hasVisitor("2"))
addToQueue(queue2, adj2, "2");
}
}
}
return false;
}
private void addToQueue(Queue<Graph> queue, Graph gr, String visitor) {
gr.setVisitor(visitor);
queue.add(gr);
}
}
GraphTest.java
public class GraphTest {
private GraphHelper helper = GraphHelper.getInstance();
public static void main(String[] args) {
GraphTest test = new GraphTest();
test.testIsRoute();
}
public void testIsRoute() {
Graph commonGraph = new Graph<String>("z");
System.out
.println("Expected true, result [" + helper.isRoute(graph1(commonGraph), graph2(commonGraph)) + "]\n");
commonGraph = new Graph<String>("z");
System.out.println("Expected false, result [" + helper.isRoute(graph1(commonGraph), graph2(null)) + "]\n");
}
private Graph graph1(Graph commonGraph) {
Graph main = new Graph<String>("a");
Graph graphb = new Graph<String>("b");
Graph graphc = new Graph<String>("c");
Graph graphd = new Graph<String>("d");
Graph graphe = new Graph<String>("e");
graphb.addAdjacent(graphc);
graphb.addAdjacent(graphe);
if (commonGraph != null)
graphb.addAdjacent(commonGraph);
graphd.addAdjacent(graphc);
graphd.addAdjacent(graphe);
graphd.addAdjacent(main);
main.addAdjacent(graphb);
main.addAdjacent(graphd);
return main;
}
private Graph graph2(Graph commonGraph) {
Graph main = new Graph<String>("f");
Graph graphg = new Graph<String>("g");
Graph graphh = new Graph<String>("h");
Graph graphi = new Graph<String>("i");
Graph graphj = new Graph<String>("j");
graphg.addAdjacent(graphh);
graphg.addAdjacent(graphj);
if (commonGraph != null)
graphg.addAdjacent(commonGraph);
graphi.addAdjacent(graphh);
graphi.addAdjacent(graphj);
graphi.addAdjacent(main);
main.addAdjacent(graphg);
main.addAdjacent(graphi);
return main;
}
}
Defining a GraphNode as the following structure (using standard arrays) and supposing that you can modify the GraphNode structure by adding two flags used to track the visited nodes (to avoid loops):
public class GraphNode {
public Integer value;
public GraphNode[] nodes;
public boolean markedsource = false;
public boolean markedtarget = false;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GraphNode graphNode = (GraphNode) o;
return Objects.equals(value, graphNode.value);
}
}
This is the solution:
boolean found = bidirectionalSearch(source, target);
// .....
private static boolean bidirectionalSearch(GraphNode sourceNode, GraphNode targetNode) {
HashSet<GraphNode> sourceSet = new HashSet<>();
sourceSet.add(sourceNode);
HashSet<GraphNode> targetSet = new HashSet<>();
targetSet.add(targetNode);
return bidirectionalSearch(sourceSet, targetSet, sourceNode, targetNode);
}
private static boolean bidirectionalSearch(Set<GraphNode> sourceSet, Set<GraphNode> targetSet, GraphNode sourceNode, GraphNode targetNode) {
Set<GraphNode> intersection = sourceSet.stream().filter(targetSet::contains).collect(Collectors.toSet());
if (!intersection.isEmpty()) {
System.out.println("intersection found at: " + intersection.iterator().next().value);
return true;
} else if (sourceSet.contains(targetNode) || targetSet.contains(sourceNode)) {
return true;
} else if (sourceSet.isEmpty() && targetSet.isEmpty()) {
return false;
}
sourceSet = sourceSet.stream().flatMap(BidirectionalSearch::getGraphNodeStreamSource)
.collect(Collectors.toSet());
targetSet = targetSet.stream().flatMap(
BidirectionalSearch::getGraphNodeStreamTarget).collect(Collectors.toSet());
return bidirectionalSearch(sourceSet, targetSet, sourceNode, targetNode);
}
private static Stream<GraphNode> getGraphNodeStreamSource(GraphNode n) {
if (n.nodes != null)
return Arrays.stream(n.nodes).filter(b -> {
if (!b.markedsource) {
b.markedsource = true;
return true;
} else {
return false;
}
});
else {
return null;
}
}
private static Stream<GraphNode> getGraphNodeStreamTarget(GraphNode n) {
if (n.nodes != null)
return Arrays.stream(n.nodes).filter(b -> {
if (!b.markedtarget) {
b.markedtarget = true;
return true;
} else {
return false;
}
});
else {
return null;
}
}
This works by expanding the sourceSet and the targetSet for each iteration, by considering adjacent nodes of the sets in input.
Now let's see advantages against a standard BFS (BreadthFirstSearch). If K is the biggest number of each node and the shortest path from the source to the target node is D, it's possible to shorten time complexity from O(k^D) to 2*O(K^(D/2)).
We have to consider also the added space of the two SETs and the time to check the intersection for every iteration.
With a standard BFS, you need a QUEUE that will have in the worst case all k^d elements of the node at the iteration K. In this case we will have two sets of k^d/2.
Right now I am trying to create a circular list, where when I use hasNext() from an Iterator it should always return true. However right now it is returning that it is not a circular list, and I am also having problems printing out the values (in this example Strings) of the ArrayList. Here is the CircularList class I created, which has a inner Node class for the objects that are put into the list:
public class CircularList<E> implements Iterable{
private Node<E> first = null;
private Node<E> last = null;
private Node<E> temp;
private int size = 0;
//inner node class
private static class Node<E>{ //In this case I am using String nodes
private E data; //matching the example in the book, this is the data of the node
private Node<E> next = null; //next value
//Node constructors, also since in this case this is a circular linked list there should be no null values for previous and next
private Node(E data){
this.data = data;
}
}
//end of inner node class
public void addValue(E item){
Node<E> n = new Node<E>(item);
if(emptyList() == true){ //if the list is empty
//only one value in the list
first = n;
last = n;
}
else{ //if the list has at least one value already
//store the old first value
temp = first;
//the new first is the input value
first = n;
//next value after first is the old first value
first.next = temp;
//if after this there will be only two values in the list once it is done
if(size == 1){
last = temp;
}
//if the list is greater than one than the last value does not change, since any other values will be put before last in this case, and not replace it
//creating the circular part of the list
last.next = first;
}
size++;
}
public boolean emptyList(){
boolean result = false;
if(first == null && last == null){ //if there is no values at all
result = true;
}
return result;
}
#Override
public Iterator<E> iterator() {
// TODO Auto-generated method stub
return new CircularIterator<E>(); //each time this method is called it will be creating a new instance of my Iterator
}
}
Here is the Iterator class I am making:
public class CircularIterator<E> implements Iterator<E> {
#Override
public boolean hasNext() {
return false;
}
#Override
public E next() {
// TODO Auto-generated method stub
return null;
}
#Override
public void remove() {
// TODO Auto-generated method stub
}
}
and finally the Test class:
public class Test {
static CircularList<String> c = new CircularList<String>(); //in this case it is a string list
static Iterator it = c.iterator();
public static void main(String[]args){
c.addValue("Bob");
c.addValue("Joe");
c.addValue("Jaina");
c.addValue("Hannah");
c.addValue("Kelly");
Iterate();
for(String val : c){
System.out.println(val);
}
}
private static boolean Iterate(){
boolean result = false;
if(!it.hasNext()){
System.out.println("Not a circular list!");
}
else{
result = true;
}
return result;
}
}
Again I am trying to get it to always return true, I think the problem lies with my hasNext() method, but I am not completely sure.
The main problem with your approach is you are using static inner classes - this is not necessary. Making the outer class generic is sufficient. The generic parameter is then inherited by the inner classes and all sorts of issues disappear.
Implementing an Iterator properly is subtle.
public static class CircularList<E> implements Iterable<E> {
private Node first = null;
private Node last = null;
private int size = 0;
private class Node {
private E data;
private Node next = null;
private Node(E data) {
this.data = data;
}
}
public void addValue(E item) {
Node n = new Node(item);
if (emptyList()) {
//only one value in the list
first = n;
last = n;
} else { //if the list has at least one value already
//store the old first value
Node temp = first;
//the new first is the input value
first = n;
//next value after first is the old first value
first.next = temp;
//if after this there will be only two values in the list once it is done
if (size == 1) {
last = temp;
}
//if the list is greater than one than the last value does not change, since any other values will be put before last in this case, and not replace it
//creating the circular part of the list
last.next = first;
}
size++;
}
public boolean emptyList() {
boolean result = false;
if (first == null && last == null) { //if there is no values at all
result = true;
}
return result;
}
#Override
public Iterator<E> iterator() {
return new CircularIterator(); //each time this method is called it will be creating a new instance of my Iterator
}
private class CircularIterator implements Iterator<E> {
// Start at first.
Node next = first;
public CircularIterator() {
}
#Override
public boolean hasNext() {
// Stop when back to first.
return next != null;
}
#Override
public E next() {
if (hasNext()) {
E n = next.data;
next = next.next;
if (next == first) {
// We're done.
next = null;
}
return n;
} else {
throw new NoSuchElementException("next called after end of iteration.");
}
}
}
}
public void test() {
CircularList<String> c = new CircularList<>();
c.addValue("A");
c.addValue("B");
c.addValue("C");
c.addValue("D");
for (String s : c) {
System.out.println(s);
}
}
Your main code was essentially correct - all I did was remove the unnecessary generics parameters from the inner classes.
Note that the way you add node to the list means that the items come out backwards. You could adjust that in your addValue method quite easily.
You can simply use following for circular iteration. This Circular list behave as same as other java.util.Lists. But it's iteration is modified. You don't need to care about it's performance tuning additionally. Because it's super class (LinkedList) is already well tested and enough stronger to use.
`public class CircularList extends LinkedList {
#Override
public Iterator<E> iterator() {
return createIterator();
}
//create new iterator for circular process
private Iterator<E> createIterator() {
return new Iterator<E>() {
private int index = 0;
#Override
public boolean hasNext() {
//no elements when list is empty
return isEmpty();
}
#Override
public E next() {
E node = get(index);
//rotate index
index++;
if (index == size()) {
index = 0;
}
return node;
}
};
}
}`
I'm implementing a list interface with links but since "ListADT" implements the Iterable interface. So, I have to have a method that produces an iterator which I'm not sure how to do. I tried using it as it is now and when I created an object for the linkedlist, and then call the iterator() method, I get an overflow. I know the method is supposed to produce an Iterator object but not sure how.
import java.util.Iterator;
public class LinkedList<T> implements ListADT<T>
{
protected int count;
protected LinearNode <T> head, tail;
private int modCount;
public LinkedList()
{
count =0;
head = tail= null;
}
public T removeFirst()
{
T result = head.getElement();
head = head.getNext();
count--;
return result;
}
public T removeLast()
{
// THROW EMPTY EXCEPTION
T result;
LinearNode <T> previous = null;
LinearNode <T> current = head;
while(!current.equals(tail))
{
previous = current;
current = current.getNext();
}
result = tail.getElement();
tail = previous;
tail.setNext(null);
count--;
return result;
}
public T remove(T element)
{
// throw exception
boolean found = false;
LinearNode <T> previous = null;
LinearNode <T> current = head;
while (current != null && !found)
{
if(element.equals(current.getElement()))
found = true;
else
{
previous = current;
current = current.getNext();
}
if (!found)
{
}
else if (current.equals(head))
{
head = current.getNext();
}
else if(current.equals(tail))
{
tail = previous;
tail.setNext(null);
}
else
previous.setNext(current.getNext());
}
count --;
return current.getElement();
}
public T first()
{
return head.getElement();
}
public T last()
{
return tail.getElement();
}
public boolean contains(T target)
{
boolean found = false;
LinearNode <T> previous = null;
LinearNode <T> current = head;
while (current != null && !found)
{
if(target.equals(current.getElement()))
found = true;
else
{
previous = current;
current = current.getNext();
}
}
return found;
}
public boolean isEmpty()
{
boolean result = false;
if( head == null && tail ==null)
{
result = true;
}
return result;
}
public int size()
{
return count;
}
public Iterator<T> iterator()
{
return this.iterator();
}
public String toString()
{
LinearNode <T> current = head;
String result ="";
String line = "";
int loopCount=0;
while(current != null)
{
loopCount++;
line = loopCount + "> " + (String) current.getElement() + "\n";
result = result + line;
current = current.getNext();
}
return result;
}
}
Your problem
You're getting an overflow because the line this.iterator() in your function public Iterator<T> iterator(), calls, you guessed it public Iterator<T> iterator().
Approach 1: The lazy way
If you don't plan on using the iterator for this class, (this looks like a programming assignment) you can always do the super super lazy.
public Iterator<T> iterator() {
throw new UnsupportedOperationException("Pffffft you don't need no iterator");
}
This approach is listed here just for completeness. Seeing as your linked list has no other way to access a random element in the middle without removing everything in front or behind it, I recommend you:
DO NOT DO THIS
Approach 2: The Correct Way
The thing about iterators is that they do a specific subset of what a list does, namely hasNext(), next(), and remove(). If you're unsure what those three methods do, I suggest you take a look at http://docs.oracle.com/javase/7/docs/api/java/util/Iterator.html
You should create a public inner class.
public class LinkedList<T> implements ListADT<T> {
... stuff
private class MyIterator<T> implements Iterator<T> {
//It's best practice to explicitly store the head in the iterator
private LinearNode<T> head;
public MyIterator<T>(LinkedList<T>) {
...
}
#Override
public boolean hasNext() {
...
}
#Override
public T next() {
...
}
#Override
public void remove() {
...
}
}
public Iterator<T> iterator() {
return new MyIterator<T>(this);
}
}
Now if you're really clever, you can rewrite the rest of your code based on the iterator. Note:
DO THIS