package GKA.Graph;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.sql.RowSet;
public class NearestNeighbour
{
private final Set<GKAEdge> edgeSet = new HashSet<>();
private final GKAGraphInterface dupGraph;
private final GKAGraphInterface tour;
private List<String> way = new ArrayList<>();
private double length = 0.0;
private long runTime = 0;
public List<String> getWay() {
return way;
}
public double getLength() {
return length;
}
public long getRunTime() {
return runTime;
}
public NearestNeighbour(GKAGraphInterface graph, String source)
{
long startTime = System.nanoTime();
if(graph.getjGraph().vertexSet().size() < 2 )
{
way = new ArrayList<>(graph.getjGraph().vertexSet().size());
dupGraph = graph;
tour = graph;
}
else
{
dupGraph = generateDuplicatedGraph(this);
tour = generateNearestNeighbour(graph, dupGraph,source);
}
runTime = System.nanoTime() - startTime;
}
private GKAEdge getShortestEdge(Set<GKAEdge> neighbourEdges)
{
Iterator<GKAEdge> i = neighbourEdges.iterator();
GKAEdge shortestEdge = null;
if(i.hasNext())
{
shortestEdge = (GKAEdge) i.next();
}
while(i.hasNext())
{
GKAEdge currentEdge = (GKAEdge) i.next();
if(currentEdge.getWeight() < shortestEdge.getWeight())
{
shortestEdge = currentEdge;
}
}
return shortestEdge;
}
private GKAGraphInterface generateNearestNeighbour(GKAGraphInterface graph, GKAGraphInterface dupGraph, String source)
{
GKAGraphInterface tour = GKAGraphInterface.newGraph(GraphType.UndirectedWeighted);
List<String> visitedVertexes = new ArrayList<>();
String edgeSource = source;
visitedVertexes.add(edgeSource);
Set<GKAEdge> neighbourEdges = new HashSet<>();
Set<GKAEdge> shortestEdges = new HashSet<>();
GKAEdge shortestEdge = null;
Set<GKAEdge> edgesToSource = new HashSet<>();
GKAEdge edgeToSource = null;
while(visitedVertexes.size() < graph.getjGraph().vertexSet().size())
{
Set<GKAEdge> moveableEdges = new HashSet<>(graph.getjGraph().edgesOf(edgeSource));
for(GKAEdge edge: moveableEdges)
{
if(((edge.getSource().toString().equals(edgeSource) && !visitedVertexes.contains(edge.getTarget()))) ||
(edge.getTarget().toString().equals(edgeSource) && !visitedVertexes.contains(edge.getSource())))
{
neighbourEdges.add(edge);
}
shortestEdge = getShortestEdge(neighbourEdges);
}
shortestEdges.add(shortestEdge);
if((shortestEdge.getSource().toString().equals(edgeSource)))
{
edgeSource = shortestEdge.getTarget().toString();
}
else
{
edgeSource = shortestEdge.getSource().toString();
}
visitedVertexes.add(edgeSource);
neighbourEdges.clear();
}
if(visitedVertexes.size() == graph.getjGraph().vertexSet().size())
{
Set<GKAEdge> edgesFromLast = new HashSet<>(graph.getjGraph().edgesOf(visitedVertexes.get(visitedVertexes.size() -1)));
Set<GKAEdge> edgesFromSource = new HashSet<>(graph.getjGraph().edgesOf(source));
for(GKAEdge lastEdge : edgesFromLast)
{
if(lastEdge.getTarget().equals(source) || lastEdge.getSource().equals(source))
{
edgesToSource.add(lastEdge);
}
}
for(GKAEdge lastEdge : edgesFromSource)
{
if(lastEdge.getTarget().equals(visitedVertexes.get(visitedVertexes.size() -1)) || lastEdge.getSource().equals(visitedVertexes.get(visitedVertexes.size() -1)))
{
edgesToSource.add(lastEdge);
}
}
Iterator<GKAEdge> i = edgesToSource.iterator();
if(i.hasNext())
{
edgeToSource = (GKAEdge) i.next();
}
while(i.hasNext())
{
GKAEdge currentLastEdge = (GKAEdge) i.next();
if(currentLastEdge.getWeight() < edgeToSource.getWeight())
{
edgeToSource = currentLastEdge;
}
}
}
shortestEdges.add(edgeToSource);
visitedVertexes.add(source);
for(GKAEdge edge : shortestEdges)
{
String start = edge.getSource().toString();
String target = edge.getTarget().toString();
String name = null;
Double weight = edge.getWeight();
length = length + weight;
tour.addEdge(start, target, name, weight);
}
way = visitedVertexes;
return tour;
}
public Set<GKAEdge> getEdgeSet()
{
return Collections.unmodifiableSet(edgeSet);
}
private GKAGraphInterface generateDuplicatedGraph(NearestNeighbour graph)
{
GKAGraphInterface dupGraph = GKAGraphInterface.newGraph(GraphType.DirectedWeighted);
for(GKAEdge edge: graph.getEdgeSet())
{
dupGraph.addEdge(edge.getSource().toString(), edge.getTarget().toString(), null, edge.getWeight());
dupGraph.addEdge(edge.getTarget().toString(), edge.getSource().toString(), null, edge.getWeight());
}
return dupGraph;
}
public GKAGraphInterface getNearestNeighbourTour()
{
return tour;
}
}