286 lines
7.6 KiB
C++
286 lines
7.6 KiB
C++
/************************************************
|
|
* Laboration 4 i
|
|
* Datastrukturer och Algoritmer
|
|
* Dijkstras Shortest Path
|
|
*************************************************
|
|
* Christian Ohlsson
|
|
* Karlstads universitet, 1999
|
|
*
|
|
* graf.cpp
|
|
* Innehåller de funktioner programmet
|
|
* använder sig av för att beräkna
|
|
* den kortaste vägen
|
|
*************************************************/
|
|
|
|
#include "header.h"
|
|
/*===============================================
|
|
* graphNode
|
|
* Construktor.
|
|
* Skapar en graphNode
|
|
-------------------------------------------------*/
|
|
graphNode::graphNode() {
|
|
startCity = -1;
|
|
endCity = -1;
|
|
Start = 0;
|
|
End = 0;
|
|
}
|
|
|
|
/*===============================================
|
|
* Operator ==
|
|
* Operatoröverlagring
|
|
-------------------------------------------------*/
|
|
|
|
int graphNode::operator==(graphNode node) {
|
|
if(Start != node.Start || End != node.End ||
|
|
startCity != node.startCity || endCity != node.endCity)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/*===============================================
|
|
* Operator =
|
|
* Operatoröverlagring
|
|
-------------------------------------------------*/
|
|
void graphNode::operator=(graphNode node) {
|
|
startCity = node.startCity;
|
|
endCity = node.endCity;
|
|
Start = node.Start;
|
|
End = node.End;
|
|
}
|
|
|
|
/*===============================================
|
|
* Operator >
|
|
* Operatoröverlagring
|
|
-------------------------------------------------*/
|
|
int graphNode::operator>(graphNode node) {
|
|
if(Start <= node.Start)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
/*===============================================
|
|
* dijkstraNode
|
|
* Construktor.
|
|
* Skapar en Dijkstra node
|
|
-------------------------------------------------*/
|
|
dijkstraNode::dijkstraNode() {
|
|
deleted = false;
|
|
lastCity = 0;
|
|
Totaltime = MAXINT; //Tiden sätts till max
|
|
}
|
|
|
|
/*===============================================
|
|
* ~dijkstraNode
|
|
* Destruktor.
|
|
* Tar bort en nod
|
|
-------------------------------------------------*/
|
|
dijkstraNode::~dijkstraNode() {}
|
|
|
|
/*===============================================
|
|
* graph
|
|
* Construktor
|
|
* Skapar en graph
|
|
-------------------------------------------------*/
|
|
graph::graph() {
|
|
visitedCities = 0;
|
|
table = NULL;
|
|
lastPath = NULL;
|
|
prevSize = 0;
|
|
lastTime = 0;
|
|
}
|
|
|
|
/*===============================================
|
|
* ~graph
|
|
* Destruktor
|
|
* Anropar deleteGraph
|
|
-------------------------------------------------*/
|
|
graph::~graph() { deleteGraph(); }
|
|
|
|
/*===============================================
|
|
* deleteGraph
|
|
* Tömmer grafen på info
|
|
-------------------------------------------------*/
|
|
void graph::deleteGraph() {
|
|
if(table != NULL)
|
|
delete[] table;
|
|
if(lastPath != NULL)
|
|
delete[] lastPath;
|
|
table = NULL;
|
|
lastPath = NULL;
|
|
visitedCities = 0;
|
|
prevSize = 0;
|
|
lastTime = 0;
|
|
}
|
|
|
|
/*===============================================
|
|
* makeGraph
|
|
* Skapar en graf med size stycken städer.
|
|
* Tar först bort eventuell gammal graf.
|
|
* Returnerar true om allt gick bra
|
|
-------------------------------------------------*/
|
|
int graph::makeGraph(int size) {
|
|
deleteGraph();
|
|
table = new list<graphNode>*[size];
|
|
if(table == NULL)
|
|
return false;
|
|
for(int index = 0; index < size; index++)
|
|
table[index] = new list<graphNode>[size];
|
|
if(table == NULL)
|
|
return false;
|
|
visitedCities = size;
|
|
return true;
|
|
}
|
|
|
|
/*===============================================
|
|
* connect
|
|
* Skapar förbindelse mellan noderna i grafen
|
|
-------------------------------------------------*/
|
|
void graph::connect(int startvertex, int endvertex, graphNode node) {
|
|
if(startvertex < 0 || startvertex > visitedCities-1 ||
|
|
endvertex < 0 || endvertex > visitedCities-1)
|
|
return;
|
|
node.startCity = startvertex;
|
|
node.endCity = endvertex;
|
|
table[startvertex][endvertex].insert(node);
|
|
}
|
|
|
|
/*===============================================
|
|
* shortestPath
|
|
* Letar reda på den kortaste
|
|
* vägen mellan två noder
|
|
-------------------------------------------------*/
|
|
graphNode graph::shortestPath(int startvertex, int endvertex, int time) {
|
|
int index, time1, time2;
|
|
graphNode node1, node2;
|
|
if(startvertex < 0 || startvertex > visitedCities-1 ||
|
|
endvertex < 0 || endvertex > visitedCities-1)
|
|
return node1;
|
|
int connections = table[startvertex][endvertex].listLength();
|
|
if(connections == 0) return node1;
|
|
node1 = table[startvertex][endvertex].printElement(1);
|
|
time1 = getTime(node1, time);
|
|
for(index = 2; index <= connections; index++) {
|
|
node2 = table[startvertex][endvertex].printElement(index);
|
|
time2 = getTime(node2, time);
|
|
if(time1 > time2) {
|
|
node1 = node2;
|
|
time1 = time2;
|
|
}
|
|
}
|
|
return node1;
|
|
}
|
|
|
|
/*===============================================
|
|
* getTime
|
|
* Returnerar antalet timmar mellan tiden
|
|
* time och tiden som finns i noden
|
|
-------------------------------------------------*/
|
|
int graph::getTime(graphNode node, int time) {
|
|
int total;
|
|
if(node.Start >= time && node.End > time && node.Start < node.End)
|
|
total = node.End - time;
|
|
else if(node.Start > node.End)
|
|
total = ( (24 - time + node.Start) + (24 - node.Start + node.End) );
|
|
else
|
|
total = (24 - time + node.End);
|
|
return total;
|
|
}
|
|
|
|
/*===============================================
|
|
* dijkstra
|
|
* Beräknar den kortaste sträckan dvs. tiden
|
|
* mellan två städer i NeverNeverLand
|
|
-------------------------------------------------*/
|
|
void graph::dijkstra(int startvertex, int endvertex, int time) {
|
|
delPath();
|
|
if(startvertex == endvertex || startvertex < 0 ||
|
|
startvertex > visitedCities-1 || endvertex < 0 ||
|
|
endvertex > visitedCities-1)
|
|
return;
|
|
|
|
dijkstraNode *temparray = new dijkstraNode[visitedCities];
|
|
if(temparray == NULL) return;
|
|
int min, index, parent = 0, temptime;
|
|
graphNode tempnode;
|
|
temparray[startvertex].Totaltime = 0;
|
|
temparray[startvertex].deleted = true;
|
|
min = startvertex;
|
|
while(min != endvertex) {
|
|
for(index = 0; index < visitedCities; index++) {
|
|
if(!temparray[index].deleted) {
|
|
tempnode = shortestPath(min, index, time);
|
|
if(tempnode.startCity != -1) {
|
|
temptime = getTime(tempnode, time);
|
|
if((temptime + temparray[min].Totaltime)
|
|
< temparray[index].Totaltime) {
|
|
temparray[index].Totaltime =
|
|
temptime + temparray[min].Totaltime;
|
|
if(parent == 0)
|
|
temparray[index].lastCity = 0;
|
|
else
|
|
temparray[index].lastCity = min;
|
|
temparray[index].Node = tempnode;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
min = getMinTime(temparray);
|
|
temparray[min].deleted = true;
|
|
time = temparray[min].Node.End;
|
|
parent++;
|
|
}
|
|
calcPath(temparray, min);
|
|
}
|
|
|
|
/*===============================================
|
|
* calcPath
|
|
* Skapar en array med information
|
|
* om den kortaste vägen.
|
|
-------------------------------------------------*/
|
|
void graph::calcPath(dijkstraNode *array, int start) {
|
|
graphNode *path = new graphNode[visitedCities];
|
|
if(path == NULL)
|
|
return;
|
|
int temp = 1, index = start;
|
|
while(array[index].lastCity > 0) {
|
|
temp++;
|
|
index = array[index].lastCity;
|
|
}
|
|
prevSize = temp;
|
|
lastTime = array[start].Totaltime;
|
|
for(index = temp-1; index >= 0; index--) {
|
|
path[index] = array[start].Node;
|
|
start = array[start].lastCity;
|
|
}
|
|
lastPath = path;
|
|
}
|
|
|
|
/*===============================================
|
|
* getMinIndex
|
|
* Hittar den minsta noden i en array och
|
|
* returnerar dess index i arrayen
|
|
-------------------------------------------------*/
|
|
int graph::getMinTime(dijkstraNode *temptable) {
|
|
int temp = 0, index;
|
|
while(temptable[temp].deleted)
|
|
temp++;
|
|
for(index = temp+1; index < visitedCities; index++) {
|
|
if(!temptable[index].deleted) {
|
|
if(temptable[temp].Totaltime > temptable[index].Totaltime)
|
|
temp = index;
|
|
}
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
/*===============================================
|
|
* delPath
|
|
* Tar bort det som lastpath pekar på
|
|
-------------------------------------------------*/
|
|
void graph::delPath() {
|
|
if(lastPath != NULL)
|
|
delete[] lastPath;
|
|
lastPath = NULL;
|
|
prevSize = 0;
|
|
}
|