I am fairly new to java and I have been struggling with this exercise for two weeks now(It's an homework exercise in my school). I need to create a topological sort and print out all of the possible connections. I have read a lot about topological sorting now, but we have this certain line of code that we have to work with. I'm pretty sure I could do the topological sorting when I have the list of vertices. My problem is, I don't know how to list all of the vertices from this given code. Could anyone give me some tips or leads or perhaps an example, I would really really appreciate it.
Here is the given code we need to work with:
import java.util.*;
public class Answer {
public static void main (String[] args) {
Answer a = new Answer();
a.run();
}
public void run() {
// TODO!!! YOUR TESTS HERE!
Graph g = new Graph ("G");
Vertex a = new Vertex ("A");
Vertex b = new Vertex ("B");
Vertex c = new Vertex ("C");
g.first = a;
a.next = b;
b.next = c;
Edge ab = new Edge ("AB");
Edge ac = new Edge ("AC");
Edge ba = new Edge ("BA");
Edge ca = new Edge ("CA");
a.first = ab;
b.first = ba;
c.first = ca;
ab.next = ac;
ab.target = b;
ac.target = c;
ba.target = a;
ca.target = a;
System.out.println (g);
}
class Vertex {
String id;
Vertex next;
Edge first;
Vertex (String s, Vertex v, Edge e) {
id = s;
next = v;
first = e;
}
Vertex (String s) {
this (s, null, null);
}
#Override
public String toString() {
return id;
}
// TODO!!! Your Vertex methods here!
} // Vertex
class Edge {
String id;
Vertex target;
Edge next;
Edge (String s, Vertex v, Edge e) {
id = s;
target = v;
next = e;
}
Edge (String s) {
this (s, null, null);
}
#Override
public String toString() {
return id;
}
// TODO!!! Your Edge methods here!
} // Edge
class Graph {
String id;
Vertex first;
Graph (String s, Vertex v) {
id = s;
first = v;
}
Graph (String s) {
this (s, null);
}
#Override
public String toString() {
String nl = System.getProperty ("line.separator");
StringBuffer sb = new StringBuffer (nl);
sb.append (id + nl);
Vertex v = first;
while (v != null) {
sb.append (v.toString() + " --> ");
Edge e = v.first;
while (e != null) {
sb.append (e.toString());
sb.append ("(" + v.toString() + "->"
+ e.target.toString() + ") ");
e = e.next;
}
sb.append (nl);
v = v.next;
}
return sb.toString();
}
// TODO!!! Your Graph methods here!
} // Graph
}
Apparently, the graph has a reference to the first vertex, and the vertices themselves are linked together into a singly linked list. This code should be all you need to collect the vertices into a Java list:
public List<Vertex> allVertices(Graph g) {
final List<Vertex> vertices = new ArrayList<>();
for (Vertex v = g.first; v != null; v = v.next)
vertices.add(v);
return vertices;
}
I would suggest that you add a "lastvisited" integer field to the edge which is set to zero, or use a boolean "visited"(true/false). Then start at one vertex. Assuming the graph is connected, you will reach all vertexes by going over the unvisited edges for one vertex, then following the edges to the vertex it leads to, marking the edge as followed, and calling your count function for this vertex recursively.
I.E.: count(node) = sum(my unvisited edges) mark_edge_as_visited(edge), count(edge.target)
Please note that you also have to consider that the graph appears to be a directed graph, so an edge leading from a to b and from b to a is counted as two edges.
Edit: I made a mistake, you also need to mark the vertex as visited, or it will be visited twice (I was thinking of an undirected graph).
Related
Below is my bfs algorithm, the algorithm works and finds the node given the start and target. But I want to save edges for the used path in a linkedList to draw the path.
My BFS:
public DGPath breadthFirstSearch(String startId, String targetId) {
V start = this.getVertexById(startId);
V target = this.getVertexById(targetId);
if (start == null || target == null) return null;
DGPath path = new DGPath();
path.start = start;
path.visited.add(start);
// easy target
if (start == target) return path;
// TODO calculate the path from start to target by breadth-first-search
// register all visited vertices while going, for statistical purposes
// if you hit the target: complete the path and bail out !!!
Queue<V> fifoQueue = new LinkedList<>();
Map<V,V> visitedFrom = new HashMap<>();
fifoQueue.offer(start);
visitedFrom.put(start, null);
while (!fifoQueue.isEmpty()) {
V current = fifoQueue.poll();
for (E e : current.getEdges()) {
V neighbour = e.getTo();
path.visited.add(neighbour);
if (neighbour == target) {
while (current != null) {
path.getEdges().addFirst(e);
current = visitedFrom.get(current);
}
return path;
} else if (!visitedFrom.containsKey(neighbour)) {
visitedFrom.put(neighbour,current);
fifoQueue.offer(neighbour);
}
}
}
// no path found, graph was not connected ???
return null;
}
The DGPath is the class that creates the path as shown below:
public class DGPath {
private V start = null;
private LinkedList<E> edges = new LinkedList<>();
private double totalWeight = 0.0;
private Set<V> visited = new HashSet<>();
/**
* representation invariants:
* 1. The edges are connected by vertices, i.e. FOR ALL i: 0 < i < edges.length: edges[i].from == edges[i-1].to
* 2. The path begins at vertex == start
* 3. if edges is empty, the path also ends at vertex == start
* otherwise edges[0].from == start and the path continues along edges[i].to for all 0 <= i < edges.length
**/
#Override
public String toString() {
StringBuilder sb = new StringBuilder(
String.format("Weight=%f Length=%d Visited=%d (",
this.totalWeight, 1 + this.edges.size(), this.visited.size()));
sb.append(start.getId());
for (E e : edges) {
sb.append(", " + e.getTo().getId());
}
sb.append(")");
return sb.toString();
}
public V getStart() {
return start;
}
public LinkedList<E> getEdges() {
return edges;
}
public double getTotalWeight() {
return totalWeight;
}
public Set<V> getVisited() {
return visited;
}
}
I want to save the right edges in de linkedlist edges from the BGPath class (called path in my BFS algo method). So I already saved the used vertices in a map to go back to the root. But when I add the edge to the path it just saves the last edge used multiple times.. The problem is the vertex can have multiple edges, so I need to add the edge from the previous that was pointing to the last "current" until I'm back to the root. But I cant wrap my head around the right way to do this.
The line where I now add the edge to the list of edges is: path.getEdges().add(e)
I think, your problem is the same line, where your are adding the edges, that line is adding the same edge in inner while loop again and again, so you are only traversing back but not adding those nodes to your edges list.
I think, it should be like this
while (!fifoQueue.isEmpty()) {
V current = fifoQueue.poll();
for (E e : current.getEdges()) {
V neighbour = e.getTo();
path.visited.add(neighbour);
if (neighbour == target) {
path.getEdges().addFirst(e):
while (current != null) {
path.getEdges().addFirst(current) ;
current = visitedFrom.get(current);
}
return path;
} else if (!visitedFrom.containsKey(neighbour)) {
visitedFrom.put(neighbour,current);
fifoQueue.offer(neighbour);
}
}
}
// no path found, graph was not connected ???
return null;
}
I have been trying to fix this Depth First Search problem but I cant figure it out. I want to print all paths but somehow it only prints some paths. I can figure out the mistake here for such a long time:
void printAllPathsUtil(Vertex v, Vertex d, ArrayList<Vertex> path){
v.state = VISITED;
path.add(v);
if (v == d) {
for (Vertex p : path) {
System.out.print("Print: " + p.value + " ");
}
System.out.println();
}
else {
for (Vertex city : v.outboundCity){
if (city.state == UNVISITED) {
printAllPathsUtil(city, d, path);
}
}
}
path.remove(v);
v.state = UNVISITED;
}
void printAllPaths(Vertex v, Vertex u){
clearStates();
ArrayList<Vertex> path = new ArrayList<>();
printAllPathsUtil(v, u, path);
}
Vertex Class is something like this:
public class Vertex{
String value;
Vertex previous = null;
int minDistance = Integer.MAX_VALUE;
List<Vertex> inboundCity;
List<Vertex> outboundCity;
State state;
}
I think you should have this two lines inside the loop:
path.remove(v);
v.state = UNVISITED;
You should remove vertexes from path and "unvisit" them right after your recursion is terminated, not when you end the loop
So I creating a minecraft plugin where I am in need of a graph to create a navigation system. I researched a bit and found out that I should be able to use Dijkstra, but I have a problem. When searching for the shortest path I am sometimes getting an infinite loop(not always, it usally works the first 2-3 runs but after that it goes into the loop).
When the player wants to get to a destination I search for the closest vertex and use computePaths with that vertex as parameter. When I then run the getShortestPathTo it sometimes gets stuck in an infinite loop and I run out of memory(which makes sence since im adding the same vertexes to the list). Can you see why it is getting stuck? As far as I knew Dijkstra should be able to handle going from A node to B node and from B node to A node right?
Below is my code:
public class Dijkstra {
public static void computePaths(Vertex source) {
source.minDistance = 0.;
PriorityQueue<Vertex> vertexQueue = new PriorityQueue<Vertex>();
vertexQueue.add(source);
while (!vertexQueue.isEmpty()) {
Vertex u = vertexQueue.poll();
// Visit each edge exiting u
for (Edge e : u.adjacencies) {
Vertex v = e.target;
double weight = e.weight;
double distanceThroughU = u.minDistance + weight;
if (distanceThroughU < v.minDistance) {
vertexQueue.remove(v);
v.minDistance = distanceThroughU;
v.previous = u;
vertexQueue.add(v);
}
}
}
}
public static List<Vertex> getShortestPathTo(Vertex target) {
List<Vertex> path = new ArrayList<Vertex>();
for (Vertex vertex = target; vertex != null; vertex = vertex.previous) {
path.add(vertex);
}
Collections.reverse(path);
return path;
}
}
and the vertex class:
public class Vertex implements Comparable<Vertex>
{
public final String name;
public Edge[] adjacencies;
public double minDistance = Double.POSITIVE_INFINITY;
public Vertex previous;
public Location location;
public Vertex(String argName) { name = argName; }
public Vertex(String argName,Location l) { name = argName; location = l;}
public String toString() { return name; }
public int compareTo(Vertex other)
{
return Double.compare(minDistance, other.minDistance);
}
}
When first the plugin is enabled I load all the vertexes from a config file looking something like this(It is the test one i am using)
I am adding vertexes and edges here(not sure if relevent but thought it might be?):
public void loadAllVertex() {
ConfigurationSection section = nodeConfig.config.getConfigurationSection("nodes");
for (String key: section.getKeys(false)) {
String locationString = nodeConfig.getString("nodes." + key + ".location");
if (locationString == null)
return;
String[] locationSplit = locationString.split(",");
if (locationSplit.length <=1) {
log.log(Level.SEVERE, "Location is not specified correctly in nodes.yml");
return;
}
Location l = new Location(Bukkit.getWorlds().get(0),Integer.parseInt(locationSplit[0]),Integer.parseInt(locationSplit[1]),Integer.parseInt(locationSplit[2]));
Vertex tmpVertex = new Vertex(key, l);
allNodes.add(tmpVertex);
}
for (Vertex v : allNodes) {
String path = "nodes." + v.name + ".connectedTo";
List<String> connectedTo = nodeConfig.getStringList(path,true);
List<Edge> edges = new ArrayList<>();
for (String sideNodeName : connectedTo) {
Vertex vertexCon = GraphUtils.getVertexByName(allNodes, sideNodeName);
if (vertexCon == null) {
log.warning("The '" + sideNodeName + "' node is not defined");
return;
}
//A.adjacencies = new Edge[]{ new Edge(M, 8) };
edges.add(new Edge(vertexCon,vertexCon.location.distance(v.location)));
}
Edge[] arrayEdges = new Edge[edges.size()];
arrayEdges = edges.toArray(arrayEdges);
v.adjacencies = arrayEdges;
}
}
Think i found the error, so I never had any loops the first time I ran the compute path and findshortestpath so I finally figured out that I could not be resetting things correctly(should have been obvious I know) - I didn't update the vertexes afterwards. So I added a method to reset the mindistance and previous attributes and this seems to have done the trick.
I have some problem checking if my adjacency list has a cycle or not.
I want to make a function that checks if my adjacency list has existing at least one cycle.
Based on my program. First, I have to input the Root Node, followed by a number of nodes, the nodes in the graph, number of edges, and the adjacency list representing the edges. Each entry in the adjacency list contains a pair of nodes.
Sample input:
Root node: "A"
Number of nodes: 3
Vertices/Nodes:
A
B
C
Number of edges: 3
A
B
B
C
C
A
A --> B
B --> C
C --> A
The sample input above has a cycle: [ A --> B --> C --> A ] I want to output whether it has a cycle or not.
This is my program so far:
import java.util.Scanner;
class Neighbor {
public int vertexNum;
public Neighbor next;
public Neighbor(int vnum, Neighbor nbr) {
this.vertexNum = vnum;
next = nbr;
}
}
class Vertex {
String name;
Neighbor adjList;
Vertex(String name, Neighbor neighbors) {
this.name = name;
this.adjList = neighbors;
}
}
public class DirectedCycle {
Vertex[] adjLists;
public DirectedCycle() {
Scanner sc = new Scanner(System.in);
//Root Node
System.out.print("Root node: ");
String rn = sc.nextLine();
//Number of nodes
System.out.print("Number of vertices/nodes: ");
int nodes = sc.nextInt();
adjLists = new Vertex[nodes];
//List of nodes
System.out.println("Vertices:");
for (int v=0; v < adjLists.length; v++) {
String letter = sc.next();
adjLists[v] = new Vertex(letter, null);
}
//Number of edges
System.out.print("Number of edges: ");
int edges = sc.nextInt();
System.out.println("<v1> <v2>");
for(int i=0; i<edges; i++) {
int v1 = indexForName(sc.next());
int v2 = indexForName(sc.next());
adjLists[v1].adjList = new Neighbor(v2, adjLists[v1].adjList);
}
}
int indexForName(String name) {
for (int v=0; v < adjLists.length; v++) {
if (adjLists[v].name.equals(name)) {
return v;
}
}
return -1;
}
public void print() {
System.out.println();
for (int v=0; v < adjLists.length; v++) {
System.out.print(adjLists[v].name);
for (Neighbor nbr=adjLists[v].adjList; nbr != null; nbr=nbr.next) {
String name = adjLists[nbr.vertexNum].name;
System.out.print(" --> " + name);
}
System.out.println("\n");
}
}
public static void main(String[] args) {
DirectedCycle graph = new DirectedCycle();
graph.print();
}
}
My program above doesn't have yet a function that checks cycle and also I want to implement the root node thing.. If anyone can improve my program above just answer me and give me some code I can rely. Thanks! (I'm beginner!)
The most efficient way to detect a cycle in Floyd's Cycle detection algo., which is basically moving two pointers over the linked list, one moving at normal one step at a time slow pointer and the other with double the speed of the slow pointer, i.e fast pointer.
Java code for the same.
boolean detectloop(Node list) {
if(list == null)
return false;
Node slow, fast;
slow = fast = list;
while(true) {
slow = slow.next;
if(fast.next != null)
fast = fast.next.next;
else
return false;
if(slow == null || fast == null)
return false;
if(slow == fast)
return true;
}
}
To check a cycle of a linked list, you want to iterate though with two different pointers, one moving through the list twice as fast. If there is a cycle, it will eventually be detected using this method. Also, for the end condition, you can check to see if all nodes have been visited, and if so, there is no cycle.
I am implementing depth first traversal of a graph drawn by the user using jung.
I have following code at this moment:
public <V,E> void dftdraw(Graph<V,E> g) {
V start = null;
for (V v:g.getVertices()){
if(v.toString().equals("0"))
start = v;
}
Set visited = new HashSet();
LinkedList stack = new LinkedList();
stack.add(start);
System.out.println(start.toString());
// traverse through graph in depth-first order
while (!stack.isEmpty())
{
V v = (V)stack.removeFirst();
visited.add(v);
Set neighbors = (Set) g.getNeighbors(v);
for (Iterator n_it = neighbors.iterator(); n_it.hasNext(); )
{
V w = (V)n_it.next();
if (!visited.contains(w)){
System.out.println(w.toString());
stack.addFirst(w);
}
}
}
}
But this is not doing depth first, it's first printing out the vertices connected to the starting vertex, and not like, traversing first connected vertex, then traversing through it's connected vertices.
That's because you're printing the vertex too soon. If you want them printed in the visiting order, you need to print at the time you're visiting (after you remove the vertex from stack). Otherwise the algorithm seems OK.
So , now I am doing Depth first traversal , by recursion using the following code :
public <V, E> void dftdraw(Graph<V, E> g) {
V start = null;
for (V v : g.getVertices()) {
if (v.toString().equals(jTextField2.getText())) {
start = v;
}
}
if(!visiteddfs.contains(start)) {
dfspath(g,start);
}
for(int i=0;i<l2.size();i++){
jTextField4.setText(jTextField4.getText() + " " + l2.get(i));
}
}
public <V,E> void dfspath(Graph<V,E> g,V v){
visiteddfs.add(v);
l2.add(v);
Set neighbors = (Set) g.getNeighbors(v);
//System.out.println(v);
for (Iterator n_it = neighbors.iterator(); n_it.hasNext();) {
V w = (V) n_it.next();
if(!visiteddfs.contains(w)){
dfspath(g,w);
}
}
finisheddfs.add(v);
}
and with slight modifications , the code posted in the question is used for breadth first traversal . Here's the code for that :
public <V, E> void bstdraw(Graph<V, E> g) {
V start = null;
for (V v : g.getVertices()) {
if (v.toString().equals(jTextField1.getText())) {
start = v;
}
}
Set visited = new HashSet();
LinkedList stack = new LinkedList();
stack.add(start);
visited.add(start);
l.add(start);
// traverse through graph in depth-first order
while (!stack.isEmpty()) {
V v = (V) stack.removeFirst();
Set neighbors = (Set) g.getNeighbors(v);
//System.out.println(v);
for (Iterator n_it = neighbors.iterator(); n_it.hasNext();) {
V w = (V) n_it.next();
if (!visited.contains(w)) {
l.add(w);
g2.addEdge("edge" + w, (Integer) v, (Integer) w);
jPanel4.repaint();
jPanel4.updateUI();
visited.add(w);
stack.addLast(w);
}
}
}
for (int i = 0; i < l.size(); i++) {
jTextField3.setText(jTextField3.getText() + " " + l.get(i));
}
}