I am trying to make the Dijkstra algorithm to take input from the text file. I found this example (https://www.programiz.com/dsa/dijkstra-algorithm) for Dijkstra, which does exactly what I need - finds the shortest path between two nodes and prints it together with a cost.
How can I fill the graph from the given text file? Thanks in advance for any replies.
Code example, updated to use decimal weights:
// Dijkstra's Algorithm in C++
#include <iostream>
#include <vector>
#include <limits.h>
using namespace std;
void DijkstrasTest();
int main() {
DijkstrasTest();
return 0;
}
class Node;
class Edge;
void Dijkstras();
vector<Node*>* AdjacentRemainingNodes(Node* node);
Node* ExtractSmallest(vector<Node*>& nodes);
double Distance(Node* node1, Node* node2);
bool Contains(vector<Node*>& nodes, Node* node);
void PrintShortestRouteTo(Node* destination);
vector<Node*> nodes;
vector<Edge*> edges;
class Node {
public:
Node(char id)
: id(id), previous(NULL), distanceFromStart(INT_MAX) {
nodes.push_back(this);
}
public:
char id;
Node* previous;
double distanceFromStart;
};
class Edge {
public:
Edge(Node* node1, Node* node2, double distance)
: node1(node1), node2(node2), distance(distance) {
edges.push_back(this);
}
bool Connects(Node* node1, Node* node2) {
return (
(node1 == this->node1 &&
node2 == this->node2) ||
(node1 == this->node2 &&
node2 == this->node1));
}
public:
Node* node1;
Node* node2;
double distance;
};
///////////////////
void DijkstrasTest() {
Node* a = new Node('a');
Node* b = new Node('b');
Node* c = new Node('c');
Node* d = new Node('d');
Node* e = new Node('e');
Node* f = new Node('f');
Node* g = new Node('g');
Edge* e1 = new Edge(a, c, 1.74);
Edge* e2 = new Edge(a, d, 2.156);
Edge* e3 = new Edge(b, c, 2.516);
Edge* e4 = new Edge(c, d, 1.321);
Edge* e5 = new Edge(b, f, 3.51);
Edge* e6 = new Edge(c, e, 3.11);
Edge* e7 = new Edge(e, f, 2.2);
Edge* e8 = new Edge(d, g, 1.1);
Edge* e9 = new Edge(g, f, 1.5);
a->distanceFromStart = 0; // set start node
Dijkstras();
PrintShortestRouteTo(f);
}
///////////////////
void Dijkstras() {
while (nodes.size() > 0) {
Node* smallest = ExtractSmallest(nodes);
vector<Node*>* adjacentNodes =
AdjacentRemainingNodes(smallest);
const int size = adjacentNodes->size();
for (int i = 0; i < size; ++i) {
Node* adjacent = adjacentNodes->at(i);
double distance = Distance(smallest, adjacent) +
smallest->distanceFromStart;
if (distance < adjacent->distanceFromStart) {
adjacent->distanceFromStart = distance;
adjacent->previous = smallest;
}
}
delete adjacentNodes;
}
}
// Find the node with the smallest distance,
// remove it, and return it.
Node* ExtractSmallest(vector<Node*>& nodes) {
int size = nodes.size();
if (size == 0) return NULL;
int smallestPosition = 0;
Node* smallest = nodes.at(0);
for (int i = 1; i < size; ++i) {
Node* current = nodes.at(i);
if (current->distanceFromStart <
smallest->distanceFromStart) {
smallest = current;
smallestPosition = i;
}
}
nodes.erase(nodes.begin() + smallestPosition);
return smallest;
}
// Return all nodes adjacent to 'node' which are still
// in the 'nodes' collection.
vector<Node*>* AdjacentRemainingNodes(Node* node) {
vector<Node*>* adjacentNodes = new vector<Node*>();
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
Node* adjacent = NULL;
if (edge->node1 == node) {
adjacent = edge->node2;
} else if (edge->node2 == node) {
adjacent = edge->node1;
}
if (adjacent && Contains(nodes, adjacent)) {
adjacentNodes->push_back(adjacent);
}
}
return adjacentNodes;
}
// Return distance between two connected nodes
double Distance(Node* node1, Node* node2) {
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
if (edge->Connects(node1, node2)) {
return edge->distance;
}
}
return -1; // should never happen
}
// Does the 'nodes' vector contain 'node'
bool Contains(vector<Node*>& nodes, Node* node) {
const int size = nodes.size();
for (int i = 0; i < size; ++i) {
if (node == nodes.at(i)) {
return true;
}
}
return false;
}
///////////////////
void PrintShortestRouteTo(Node* destination) {
Node* previous = destination;
cout << "Distance from start: "
<< destination->distanceFromStart << endl;
while (previous) {
cout << previous->id << " ";
previous = previous->previous;
}
cout << endl;
}
// these two not needed
vector<Edge*>* AdjacentEdges(vector<Edge*>& Edges, Node* node);
void RemoveEdge(vector<Edge*>& Edges, Edge* edge);
vector<Edge*>* AdjacentEdges(vector<Edge*>& edges, Node* node) {
vector<Edge*>* adjacentEdges = new vector<Edge*>();
const int size = edges.size();
for (int i = 0; i < size; ++i) {
Edge* edge = edges.at(i);
if (edge->node1 == node) {
cout << "adjacent: " << edge->node2->id << endl;
adjacentEdges->push_back(edge);
} else if (edge->node2 == node) {
cout << "adjacent: " << edge->node1->id << endl;
adjacentEdges->push_back(edge);
}
}
return adjacentEdges;
}
void RemoveEdge(vector<Edge*>& edges, Edge* edge) {
vector<Edge*>::iterator it;
for (it = edges.begin(); it < edges.end(); ++it) {
if (*it == edge) {
edges.erase(it);
return;
}
}
}
Fragment of the input file, number of lines is unknown:
source_id,target_id,weight
1,2,0.17
2,3,0.13
3,4,0.15
3,5,0.02
4,5,0.09
5,2,0.01
Your input is a list of node links.
Your algorithm requires an adjacency matrix, which is a vector containing vectors of the nodes adjacent to each node.
To convert from a list of links to an adjacency matrix, you need a graph class that among other things will populate the adjacency martrix using a function such as AddLink( int src, int dst, double cost )
There are many such classes available for you to copy or modify to your particular situation. I'll mention just one: PathFinder
Below is the PathFinder code to do the conversion. You will need something slightly different to handle the format of your file. Here is the format that PathFinder is reading
while (std::getline(myFile, line))
{
std::cout << line << "\n";
auto token = ParseSpaceDelimited(line);
if (!token.size())
continue;
switch (token[0][0])
{
case 'g':
if (myFinder.linkCount())
throw std::runtime_error("cPathFinderReader:: g ( directed ) must occurr before any links");
myFinder.directed();
break;
case 'l':
if (weights && (token.size() != 4))
throw std::runtime_error("cPathFinder::read bad link line");
else if (3 > token.size() || token.size() > 4)
throw std::runtime_error("cPathFinder::read bad link line");
if (weights)
cost = atof(token[3].c_str());
else
cost = 1;
if (cost < maxNegCost)
maxNegCost = cost;
myFinder.addLink(
token[1],
token[2],
cost);
break;
case 's':
if (token.size() != 2)
throw std::runtime_error("cPathFinder::read bad start line");
myFinder.start(token[1]);
break;
case 'e':
if (token.size() != 2)
throw std::runtime_error("cPathFinder::read bad end line");
myFinder.end(token[1]);
break;
}
}
Related
Everything works fine apart from the array that's supposed to remember the connected nodes for each node, although it counts only some of them and I'm not sure why. I believe the problem is here:
if (G->v[j] != NULL || G->v[i] != NULL)
However, I'm not sure how to change it.
#include <iostream>
#include <time.h>
#include <list>
#include <iterator>
#include <stack>
#include <queue>
#include "Profiler.h"
using namespace std;
# define MAX_SIZE 20
class Node
{
public:
int key;
int colour; // -1 not visited(white), 0 under visit(gray), 1 visited(black)
Node* p;
int d, f;
list<Node*> adj;
};
Node* newNode(int key) //constructor
{
Node* node = new Node();
node->key = key;
node->colour = -1; // white, not visited
node->d = 0;
node->f = 0;
node->p = NULL;
return node;
}
class Edge
{
public:
Node *v1,*v2;
};
Edge* newEdge(Node* u, Node* v)
{
Edge* edge = new Edge();
edge->v1 = u;
edge->v2 = v;
return edge;
}
class Graph
{
public:
Node* v[MAX_SIZE];
list<Edge*> e;
};
Graph* newGraph(int nb_of_vertices, int nb_of_edges)
{
Graph* G = new Graph();
int i, j;
for (i = 0; i < nb_of_vertices; i++)
{
G->v[i] = NULL;
}
for (i = 0; i < nb_of_vertices; i++)
{
Node* v1 = newNode(i);
G->v[i] = v1;
do
j = rand() % (nb_of_vertices-1);
while (j == i);
if (G->v[j] != NULL || G->v[i] != NULL)
{
Node* v2 = newNode(j);
G->v[j] = v2;
G->v[i]->adj.push_back(v2);
Edge* edge = newEdge(v1, v2);
G->e.push_back(edge);
}
}
return G;
}
void printGraph(Graph* G, int n)
{
list <Node*> ::iterator it;
for (int i = 0; i < n; i++)
{
cout << G->v[i]->key << '\t' << G->v[i]->colour << '\t' << G->v[i]->d << '\t' << G->v[i]->f << '\t';// << G->v[i]->p << '\t';
for (it = G->v[i]->adj.begin(); it != G->v[i]->adj.end(); ++it)
{
cout << (*it)->key << ' ';
}
cout << '\n';
}
list <Edge*> ::iterator it2;
for (it2 = G->e.begin(); it2 != G->e.end(); ++it2)
{
cout << (*it2)->v1->key << "-" << (*it2)->v2->key << ' ';
}
cout << '\n';
}
queue <Node*> solution;
stack <Node*> topsort;
int no_cycle = 1;
void DFSvisit(Graph* G, Node* v, int& time)
{
Node* node = newNode(0);
time++;
v->d = time;
v->colour = 0;
while (!v->adj.empty())
{
node = v->adj.front();
v->adj.pop_front();
if (v->colour == 0)
no_cycle = 0;
if (node->colour == -1)
{
node->p = v;
DFSvisit(G, node, time);
}
}
v->colour = 1;
time++;
v->f = time;
solution.push(v);
topsort.push(v);
}
void DFS(Graph* G, int n)
{
int time = 0, i;
for (i = 0; i < n; i++)
{
if (G->v[i]->colour == -1)
DFSvisit(G, G->v[i], time);
}
}
int main()
{
srand(time(NULL));
int nb_of_vertices = 10, nb_of_edges = 3;
Graph* G = newGraph(nb_of_vertices, nb_of_edges);
printGraph(G, nb_of_vertices);
DFS(G, nb_of_vertices);
printGraph(G, nb_of_vertices);
// DFS traversal
cout << "\nDFS TRAVERSAL\n";
while (!solution.empty())
{
cout << solution.front()->key << " ";
solution.pop();
}
cout << '\n';
// Tarjan's algorithm
// Topological sort
if (no_cycle)
{
cout << "\nTOPOLOGICAL SORTING\n";
while (!topsort.empty())
{
cout << topsort.top()->key << " ";
topsort.pop();
}
}
else
cout << "\nImpossible to perform topological sort, the generated graph contains cycles.\n";
return 0;
}
I have a problem with my C++ code. It says that the all the functions starting with isPerfectRec() couldn't be resolved...Why? I tried a lot of things but apparently they don't work. I have a lot of assigments like to verify if the binary search tree is perfect, to find the second largest element in a binary search tree and so on..
#include <stdio.h>
#include<iostream>
#include<stack>
template<typename T> class BinarySearchTree {
public:
BinarySearchTree<T> *root, *left_son, *right_son, *parent;
T *pinfo;
BinarySearchTree() {
left_son = right_son = NULL;
root = this;
pinfo = NULL;
}
void setInfo(T info) {
pinfo = new T;
*pinfo = info;
}
void insert(T x) {
if (pinfo == NULL)
setInfo(x);
else
insert_rec(x);
}
bool isPerfectRec(BinarySearchTree *root, int d, int level = 0)
{
// An empty tree is perfect
if (*root == NULL)
return true;
// If leaf node, then its depth must be same as
// depth of all other leaves.
if (*root->left_son == NULL && root->*right_son == NULL)
return (d == level+1);
// If internal node and one child is empty
if (root->*left_son == NULL || root->*right_son == NULL)
return false;
// Left and right subtrees must be perfect.
return isPerfectRec(root->*left_son, d, level+1) &&
isPerfectRec(root->*right_son, d, level+1);
}
// Wrapper over isPerfectRec()
bool isPerfect(BinarySearchTree *root)
{
int d = findADepth(root);
return isPerfectRec(root, d);
}
int findADepth(BinarySearchTree *node)
{
int d = 0;
while (node != NULL)
{
d++;
node = node->left_son;
}
return d;
}
// A function to find 2nd largest element in a given tree.
void secondLargestUtil(BinarySearchTree *root, int &c)
{
// Base cases, the second condition is important to
// avoid unnecessary recursive calls
if (root == NULL || c >= 2)
return;
// Follow reverse inorder traversal so that the
// largest element is visited first
secondLargestUtil(root->right_son, c);
// Increment count of visited nodes
c++;
// If c becomes k now, then this is the 2nd largest
if (c == 2)
{
std::cout << "2nd largest element is "
<< root->pinfo;
printf("\n___\n");
return;
}
// Recur for left subtree
secondLargestUtil(root->left_son, c);
}
void secondLargest(BinarySearchTree *root)
{
// Initialize count of nodes visited as 0
int c = 0;
// Note that c is passed by reference
secondLargestUtil(root, c);
}
bool hasOnlyOneChild(int pre[], int size)
{
int nextDiff, lastDiff;
for (int i=0; i<size-1; i++)
{
nextDiff = pre[i] - pre[i+1];
lastDiff = pre[i] - pre[size-1];
if (nextDiff*lastDiff < 0)
return false;;
}
return true;
}
BinarySearchTree * readListInter(){
BinarySearchTree* root = NULL;//returning object
BinarySearchTree* temp;
BinarySearchTree* input;//new node to add
int x;
std::cout << "enter number (>0 to stop): ";
std::cin >> x;
while(x>=0){
input = BinarySearchTree(x);
if(root == NULL){//if root is empty
root = input;
temp = root;//temp is use to store value for compare
}
else{
temp = root; //for each new addition, must start at root to find correct spot
while(input != NULL){
if( x < temp->pinfo){//if smaller x to add to left
if(temp->left_son == NULL){//left is empty
temp->left_son = input;
input = NULL;//new node added, exit the loop
}
else{//if not empty set temp to subtree
temp = temp->left_son;//need to move left from the current position
}
}
else{//otherwise x add to right
if(temp->right_son == NULL){//right is empty
temp->right_son = input;
input = NULL;//new node added, exit the loop
}
else{
temp = temp->right_son;//need to move right from the current position
}
}
}
}
std::cin >> x;
}
return root;
}
};
int main() {
BinarySearchTree<int> *r = new BinarySearchTree<int>;
BinarySearchTree<int> *r1 = new BinarySearchTree<int>;
BinarySearchTree<int> *p = new BinarySearchTree<int>;
p = readListInter();
r->insert(6);
r->insert(8);
r->insert(1);
r->insert(9);
r->insert(10);
r->insert(4);
r->insert(13);
r->insert(12);
printf("\n___\n");
r1->insert(6);
r1->insert(8);
r1->insert(1);
r1->insert(9);
r1->insert(10);
r1->insert(4);
r1->insert(13);
r1->insert(12);
printf("\n___\n");
r->isPerfect(r);
int pre[] = {8, 3, 5, 7, 6};
int size = sizeof(pre)/sizeof(pre[0]);
if (hasOnlyOneChild(pre, size) == true )
printf("Yes");
else
printf("No");
s
return 0;
}
I think you need to write BinarySearchTree<T> instead of BinarySearchTree as a datatype in those functions.
I tried to implement BFS for graphs using link list but i have some issues with it, using a queue it only displays the nodes of that origin and not after it. The answer should be 2031 but i only get 203.
The code is below:
#include <iostream>
#include <cmath>
#include <vector>
#include <stdlib.h>
#include <queue>
using namespace std;
class linkListNode
{
public:
linkListNode *next;
int destination;
bool visited;
linkListNode()
{
next = NULL;
destination =0;
visited=false;
}
};
class linkList
{
public:
linkListNode *head;
linkList()
{
head = NULL;
}
// append type insert
void insert(int value)
{
linkListNode *temp2 = new linkListNode;
temp2->destination = value;
temp2->next = NULL;
linkListNode *nodePtr = new linkListNode;
if (head == NULL)
{
head = temp2;
temp2->next = NULL;
}
else
{
nodePtr = head;
while (nodePtr->next)
{
nodePtr = nodePtr->next;
}
nodePtr->next = temp2;
}
}
void display()
{
linkListNode *temp = new linkListNode;
temp = head;
while (temp)
{
cout << temp->destination << " --> ";
temp = temp->next;
}
cout << endl;
}
int size()
{
linkListNode *temp = head;
int sizer = 0;
while (temp)
{
sizer++;
temp = temp->next;
}
return sizer;
}
};
class edge
{
public:
int origin;
linkList final;
bool visited;
edge()
{
//origin = NULL;
//cost=0;
visited=false;
}
};
class graph
{
private:
vector <edge> vectorOfEdges;
int vertices;
public:
graph(int v)
{
vertices = v;
vectorOfEdges.clear();
}
void addRoute(int ori, int dest)
{
int counter = 0;
for (int i = 0; i<vectorOfEdges.size(); i++)
{
edge e = vectorOfEdges[i];
if (e.origin== ori)
{
counter = 1; // means element was present in the list
e.final.insert(dest);
}
vectorOfEdges[i] = e;
}
if (counter == 0) // when counter is set to zero, this means that the element was not found in the vector and needs to be pushed
{
edge e;
e.origin = ori;
e.final.insert(dest);
vectorOfEdges.push_back(e);
}
}
void printGraph()
{
edge e;
for (int i = 0; i<vectorOfEdges.size(); i++)
{
e = vectorOfEdges[i];
cout << e.origin << ":- ";
e.final.display();
cout << endl;
}
}
int sizeOfEdge(edge e)
{
int x = e.final.size() + 1;
return x;
}
int max(int one, int two)
{
if (one > two)
{
return one;
}
else
{
return two;
}
}
void BFS(int start)
{
edge e;
queue <int> q;
int save_index=0;
for (int i=0;i<vectorOfEdges.size();i++)
{
e=vectorOfEdges[i];
if (e.origin == start)
{
save_index=i;
q.push(e.origin);
e.visited=true;
break;
}
}
while (!q.empty())
{
int x=q.front();
cout << x << " " ;
q.pop();
linkListNode *l = e.final.head;
while (l)
{
if (l->visited == false)
{
q.push(l->destination);
l->visited=true;
l=l->next;
}
else
{
l=l->next;
}
}
}
}
};
int main()
{
graph g(4);
g.addRoute(0, 1);
g.addRoute(0, 2);
g.addRoute(1, 2);
g.addRoute(2, 0);
g.addRoute(2, 3);
// g.printGraph();
//cout << "Following is Breadth First Traversal (starting from vertex 2) \n";
g.BFS(1);
}
Your code is only running for the node that you have provided as the starting value for your BFS traversal.
void BFS(int start)
{
queue<int> q;
bool startFound = false;
for (int i = 0; i < vectorOfEdges.size(); i++)
{
edge e = vectorOfEdges[i];
if (e.origin == start)
{
q.push(e.origin);
check.push_back(e.origin);
e.visited = true;
startFound = true;
break;
}
}
if (!startFound)
{
cout << "Start vertex not found in the graph" << endl;
return;
}
while (!q.empty())
{
int x = q.front();
cout << x << " ";
q.pop();
for (int i = 0; i < vectorOfEdges.size(); i++)
{
edge e = vectorOfEdges[i];
if (e.origin == x)
{
linkListNode *l = e.final.head;
while (l != NULL)
{
bool found = false;
if (l->visited == false)
{
l->visited = true;
for (int i = 0; i < check.size(); i++)
{
if (check[i] == l->destination)
{
found = true;
break;
}
}
if (found == false)
{
check.push_back(l->destination);
q.push(l->destination);
}
}
l = l->next;
}
}
}
}
}
Instead, do this to run it for every node.
I am attempting to sort a linked list of points based on their distance to the origin. The closer the point, it should be the first/next in the linked list. Example: If a user inputs (2,2) (4,4) (1,1) (3,3) the linked list should be reordered using the next pointer to (1,1) (2,2) (3,3) (4,4). It works except that the points in main are not affected by the sorting and the points are not interchanged, so if (1,1) is 3rd like in the example it will be the smallest point the 2nd time around the loop again when compared to (4,4).
#include <iostream>
#include <math.h>
using namespace std;
class List {
public:
int x;
int y;
List *next;
};
void init(List *root) {
int x, y;
List *traverse;
traverse = root;
while(traverse != 0) {
cout<<"Enter coordinate x: ";
cin>>x;
traverse->x = x;
cout<<"Enter coordinate y: ";
cin>>y;
traverse->y = y;
traverse = traverse->next;
}
}
void display(List *root) {
List *traverse;
traverse = root;
while(traverse->next != 0) {
cout<<"("<<traverse->x<<","<<traverse->y<<") ";
traverse = traverse->next;
}
cout<<"("<<traverse->x<<","<<traverse->y<<")"<<endl;
}
void sort(List *root, int n) {
List *traverse;
List *stable;
traverse = root;
stable = root;
double d1, d2;
for(int i = 0; i < n; i++) {
d1 = sqrt(pow(traverse->x, 2) + pow(traverse->y, 2));
d2 = sqrt(pow(stable->x, 2) + pow(stable->y, 2));
if(d1 < d2) {
root = traverse;
}
traverse = traverse->next;
}
}
void collinear(List *root) {
int x[3] = {0}, y[3] = {0};
int value;
List *traverse;
traverse = root;
for(int i = 0; i < 3; i++) {
if(traverse != 0) {
x[i] = traverse->x;
y[i] = traverse->y;
traverse = traverse->next;
}
}
if(x[2] != 0) {
value = x[0] * (y[1] - y[2]) + x[1] * (y[2] - y[0]) + x[2] * (y[0] - y[1]);
if(value == 0) {
traverse = root;
for(int i = 0; i < 3; i++) {
cout<<"("<<traverse->x<<","<<traverse->y<<") ";
traverse = traverse->next;
}
cout<<"collinear!"<<endl;
}
else {
traverse = root;
for(int i = 0; i < 3; i++) {
cout<<"("<<traverse->x<<","<<traverse->y<<") ";
traverse = traverse->next;
}
cout<<"non-collinear!"<<endl;
}
}
else {
cout<<"Not a group of 3 points cannot calculate collinearity!"<<endl;
}
}
int main() {
List *root;
root = new List;
List *traverse;
traverse = root;
List *node1;
node1 = new List;
List *node2;
node2 = new List;
List *node3;
node3 = new List;
root->next = node1;
node1->next = node2;
node2->next = node3;
node3->next = 0;
init(traverse);
display(traverse);
/*for(int i = 0; i < 2; i++) {
collinear(traverse);
traverse = traverse->next;
}
traverse = root;*/
traverse = root;
int n = 4;
for(int i = 0; i < 4; i++) {
List *traverse2;
traverse2 = traverse;
sort(traverse2, n);
traverse = traverse->next;
n--;
}
traverse = root;
display(traverse);
return 0;
}
If you want to be able to change the root you'll need to pass it as a **.
However even then I dont think your sort function will work it will just return a truncated list missing everything before the smallest element.
Is their any reason your using a custom linked list and sort alogorithm?
The standard library takes care of things like containers and sorting:
#include <vector>
#include <algorithm>
#include <iostream>
class Point
{
public:
Point(int x_, int y_) :
x(x_),
y(y_)
{
}
// no need to square root to compare distance from origin
int distanceSquared() const
{
return (x*x)+(y*y);
}
// define an operator< so we can sort containers holding this class
bool operator< ( const Point& rhs ) const
{
return distanceSquared() < rhs.distanceSquared();
}
// declare a friend function for outputing the values in a user friendly way
friend std::ostream& operator<<(std::ostream& os, const Point& p);
int x;
int y;
};
// and define the friend function outside the class
std::ostream& operator<<(std::ostream& os, const Point& p)
{
os << "(" << p.x << ", " << p.y << ")";
return os;
}
int main()
{
// std::vector to store user entered points
std::vector<Point> points;
// temp storage for user input
int x, y;
// entering anything non-numberic will exit this loop
while( true )
{
std::cout << "Enter X coordinate : ";
std::cin >> x;
if( std::cin.fail() )
break;
std::cout << "Enter Y coordinate : ";
std::cin >> y;
if( std::cin.fail() )
break;
// we've read in a valid x,y so add a new point to vector
points.push_back( Point(x, y) );
}
// sort will use the operator< function in Point class
std::sort(points.begin(), points.end());
// use the stream operator to debug out our point
for( auto it = points.begin(); it != points.end(); ++it )
{
std::cout << *it << std::endl;
}
}
I have searched through the other questions and none of them seem to apply
exactly.
I am writing a program that finds a route through a maze,
the only real thing im having a problem with is this one compiler error.
It has to do with the one function I have the returns a Node ( struct).
Header file: (I cut the define stuff off)
#include <iostream>
#include <string>
using namespace std;
class Graph {
private:
struct Node {
int id; //int id
Node * north; //north path node
Node * south; //south path node
Node * east; //east path node
Node * west; //went path node
bool visited; // visited bool
};
//this struct holds the path that is found.
struct Elem {
int id; //The id of the node
string last; //the door that it passed through
Elem * back; //back one path
Elem * next; //forward one path
};
//This is a graph with a very smart struct
//This is the main node that makes up the graph.
Node * start;
Node ** initArr;
int arrLen;
Elem * head;
Elem * tail;
int path;
public:
Graph();
//Constructs empty graph
Graph(const Graph &v);
//copy constructor
~Graph();
//destructor
Graph & operator = (const Graph &v);
//assignment operator
void output(ostream & s) const;
//Prints the graph
void input(istream & s);
//input and creates the graph
Node * find(int id);
//finds the node in the graph
void makePath();
//makes a path through the maze
bool findPath(Node* cur, string room);
//worker function for recursion
void pathOut(ostream & s) const;
//Outputs the found path
void removeTail();
//Removes the last element
void addTail(Node* n, string door);
//Adds the element to the tail
//Mutators
void setId(Node* n ,int x);
void setVisited(Node* n, bool v);
//Elem Mutator
void seteId(Elem* e, int x);
//Elem Accessor
int geteId(Elem* e);
//Accessors
int getId(Node* n);
bool getVisited(Node* n);
};
And my actual code file.
#include <iostream>
#include "graph.h"
using namespace std;
//Constructs empty graph
Graph::Graph()
{
start = 0;
head = tail = 0;
path = 0;
}
//copy constructor
Graph::Graph(const Graph &v)
{
//not implemented
}
//destructor
Graph::~Graph()
{
for(int i = 0; i < arrLen + 1; i++)
{
delete initArr[i];
}
while(head != 0)
{
Elem* p = head;
head = head->next;
delete p;
}
delete[] initArr;
}
//assignment operator
Graph & Graph::operator = (const Graph &v)
{
//not implemented
}
//Prints the graph
void Graph::output(ostream & s) const
{
s<<"Node"<<'\t'<<"North"<<'\t'<<"East"<<'\t'<<"South"<<'\t'<<"West"<<'\n';
for(int i = 1; i < arrLen + 1; i++)
{
Node* temp = initArr[i];
s<<temp->id<<'\t';
if(temp->north != 0)
s<<temp->north->id<<'\t';
else
s<<"--"<<'\n';
if(temp->east != 0)
s<<temp->east->id<<'\t';
else
s<<"--"<<'\n';
if(temp->south != 0)
s<<temp->south->id<<'\t';
else
s<<"--"<<'\n';
if(temp->west != 0)
s<<temp->west->id<<'\t';
else
s<<"--"<<'\n';
s<<'\n';
}
}
//input and creates the graph
void Graph::input(istream & s)
{
int length = 0;
s>>length;
arrLen = length;
if(s)
{
//define array
initArr = new Node*[length + 1];
int temp = 0;
for(int i = 1; i < length + 1; i++)
{
//Create node
s>>temp;
Node* n = new Node;
n->id = temp;
n->visited = false;
//Add to array
initArr[i] = n;
}
//Make Exit Node
Node *x = new Node;
x->id = 0;
x->visited = false;
initArr[0] = x;
//Loop through all of the node input
int tn = 0;
for(int f = 0; f < length; f++)
{
//Set Pointers
s>>tn;
Node* curNode = find(tn);
int n = 0;
int e = 0;
int st = 0;
int w = 0;
s>>n>>e>>st>>w;
curNode->north = find( n );
curNode->east = find( e );
curNode->south = find( st );
curNode->west = find( w );
}
//set Entry point to graph
int last = 0;
s>>last;
start = find(last);
}
}
//finds the node in the array
Node* Graph::find(int id)
{
if( id == 0)
{
return initArr[0];
}
if(id == -1)
{
return 0;
}
else
{
for(int i = 1; i < arrLen + 1; i++)
{
if(initArr[i]->id == id)
{
return initArr[i];
}
}
cerr<<"NOT FOUND IN GRAPH";
return 0;
}
}
//makes a path through the maze
void Graph::makePath()
{
if(findPath(start->north, "north") == true)
{
path = 1;
return;
}
else if( findPath(start->east, "east") == true)
{
path = 1;
return;
}
else if( findPath(start->south, "south") == true)
{
path = 1;
return;
}
else if( findPath(start->west, "west") == true)
{
path = 1;
return;
}
return;
}
//finds a path to the outside
bool Graph::findPath(Node* cur, string room)
{
addTail(cur, room);
if(cur = initArr[0])
{
return true;
}
if(cur->north != 0 && cur->north->visited == false)
{
cur->visited = true;
findPath(cur->north, "north");
}
else if(cur->east != 0 && cur->east->visited == false)
{
cur->visited = true;
findPath(cur->north, "east");
}
else if(cur->south !=0 && cur->south->visited == false)
{
cur->visited = true;
findPath(cur->north, "south");
}
else if(cur->west != 0 && cur->west->visited == false)
{
cur->visited = true;
findPath(cur->north, "west");
}
else
{
cur->visited = false;
removeTail();
}
}
//Outputs the found path
void Graph::pathOut(ostream & s) const
{
if(path == 1)
{
Elem *p;
p = head->next;
while(p != 0)
{
s<<p->id<<"--> "<<p->last;
p= p->next;
}
}
else if(path == 0)
{
}
}
//Removes the last element in the chain
void Graph::removeTail()
{
Elem* temp = 0;
temp = tail;
tail = tail->back;
delete temp;
}
//Adds the element to the tail
void Graph::addTail(Node* n, string door)
{
if(head != 0)
{
Elem* temp = new Elem;
temp->id = n->id;
tail->next = temp;
tail->last = door;
temp->back = tail;
temp->next = 0;
tail = 0;
}
else
{
Elem *p = new Elem;
p->last = "";
p->back = 0;
p->next = 0;
head = p;
tail = p;
}
}
//Mutators
void Graph::setId(Node *n ,int x)
{
n->id = x;
}
void Graph::setVisited(Node *n, bool v)
{
n->visited = v;
}
//Elem Mutator
void Graph::seteId(Elem *e, int x)
{
e->id = x;
}
//Elem Accessor
int Graph::geteId(Elem *e)
{
return e->id;
}
//Accessors
int Graph::getId(Node *n)
{
return n-> id;
}
bool Graph::getVisited(Node *n)
{
return n->visited;
}
/*
//This is a graph with a very smart struct
//This is the main node that makes up the graph.
struct Node {
int id; //int id
Node *north; //north path node
Node *south; //south path node
Node *east; //east path node
Node *west; //went path node
bool visited; // visited bool
};
//this struct holds the path that is found.
struct Elem {
int id; //The id of the node
string last; //the door that it passed through
Elem* back; //back one path
Elem* next; //forward one path
};
Node* Start;
Node ** initArr;
Elem* head;
Elem* tail;
*/
//outputs using named operation
ostream & operator << (ostream &s, const Graph & v)
{
v.output(s);
return s;
}
The error is occurring on the find function.
In the cpp file, Node is not in global scope. It's nested inside Graph as such, you need to qualify it in a return type:
Graph::Node* Graph::find(int id){
// ...
}
Inside the function, you're in the scope of Graph again, as such you do not need to qualify it.
You have both Node and Element defined as structs inside the class Graph. It would be better to define them outside the class Graph. You can define a separate Node class and store the element struct as its private members. The error happens because Node is a private member of Graph, which can be accessed as Graph::Node. E.g. Graph::Node* find(...).