I've been working on a project for college and ran into a rather large problem. I'm supposed to make a function that gets the shortest path through a directed graph from point A to point B and display the path in order.
EX. if the node holds a state name and we want to find the shortest path between California and Utah the output would show california -> nevada -> utah
Currently, my traversal shows all nodes searched with bfs instead of the list of nodes that we took to get from point A to point B.
Below is my implementation of the assignment. My only real question is how would I go about keeping track of the nodes I actually traversed instead of all nodes searched.
bool DirectedGraph::GetShortestPath(
const string& startNode, const string& endNode,
bool nodeDataInsteadOfName, vector<string>& traversalList) const
{
//Nodes are the same
if (startNode.compare(endNode) == 0)
return false;
//Stores the location of our nodes in the node list
vector<int> path;
//Queue to hold the index of the node traversed
queue<int> q;
//Create our boolean table to handle visited nodes
bool *visited = new bool[m_nodes.size()];
//initialize bool table
memset(visited, false, sizeof(bool) * m_nodes.size());
//Label the start node as visited
visited[GetNodeIndex(startNode)] = true;
//Push the node onto our queue
q.push(GetNodeIndex(startNode));
while (!q.empty())
{
//Store the nodes index
int index = q.front();
path.push_back(q.front());
q.pop();
int i = 0;
for (i = 0; i < m_nodes[index]->Out.size(); i++)
{
//If this node matches what we are looking for break/return values
if (m_nodes[index]->Out[i]->targetI == GetNodeIndex(endNode))
{
path.push_back(m_nodes[index]->Out[i]->targetI);
if (nodeDataInsteadOfName)
{
path.push_back(m_nodes[index]->Out[i]->targetI);
for (int x = 0; x < path.size(); x++)
{
traversalList.push_back(m_nodes[path[x]]->Data);
}
}
else
{
for (int x = 0; x < path.size(); x++)
{
traversalList.push_back( m_nodes[path[x]]->Name);
}
}
return true;
}
//Continue through the data
if (!visited[m_nodes[index]->Out[i]->targetI])
{
visited[m_nodes[index]->Out[i]->targetI] = true;
q.push(m_nodes[index]->Out[i]->targetI);
}
}
}
// You must implement this function
return false;
}
//definition of graph private members
struct Edge
{
int srcI; // Index of source node
int targetI; // Index of target node
Edge(int sourceNodeIndex, int targetNodeIndex)
{
srcI = sourceNodeIndex;
targetI = targetNodeIndex;
}
};
struct Node
{
string Name;
string Data;
Node(const string& nodeName, const string& nodeData)
{
Name = nodeName;
Data = nodeData;
}
// List of incoming edges to this node
vector<Edge*> In;
// List of edges going out from this node
vector<Edge*> Out;
};
// We need a list of nodes and edges
vector<Node*> m_nodes;
vector<Edge*> m_edges;
// Used for efficiency purposes so that quick node lookups can be
// done based on node names. Maps a node name string to the index
// of the node within the nodes list (m_nodes).
unordered_map<string, int> m_nodeMap;
The first problem is with the if inside the for loop. Your path variable can only contain two items: the starting and the ending nodes. I suggest you do no track the path with the for loop. Instead, assign each node a distance.
struct Node
{
string Name;
string Data;
int Distance;
Node(const string& nodeName, const string& nodeData)
{
Name = nodeName;
Data = nodeData;
Distance = INT_MAX;
}
// List of incoming edges to this node
vector<Edge*> In;
// List of edges going out from this node
vector<Edge*> Out;
};
and set the distance of the starting node to zero, before looping.
m_nodes[GetNodeIndex(startNode)]->Distance = 0;
At each iteration, pick a node from the queue (you called it index), loop through its adjacency list (outgoing arcs) and test if the adjacent node is visited. If the node is visited, skip it. If the node is not visited, visit it by setting its distance to
m_nodes[index]->Distance + 1
After updating the distance of each node, check if it is the final node, if so break out of the loops.
At this point you have the distance's updated properly. Work your way from the end node backwards, each time selecting the node from the adjacency list with (distance = current node's distance - 1). You can do this using m_edges vector, each time you actually know targetI, so you can check for its corresponding scrI's with the distance value mentioned above.
Related
I need to implement a breadth-first search and I am having trouble with the adjList (neighbor's list) for my vertex temp. First I find the vertex in my vertexList list then mark as visited and enqueue it. Then while the queue is not empty I check for all neighbors of the enqueued vertex: temp who are not visited, mark as visited and enqueue, and so on. But I don't know for what reason it says my adjList (neighbors list) is empty, which is not according to my display method when I actually print all vertices and its neighbors.
void testBreadthFirstSearch(string x)
{
vertex * s = findVertex(x);
list<vertex*> q;
s->visited = true;
s->predecessor = s;
q.push_back(s);
while (!q.empty()) {
vertex * temp = q.front();
q.pop_front();
for (list<vertex*>::iterator itr = temp->adjList.begin(); itr != temp->adjList.end(); itr++) {
if ((*itr)->visited == false) {
(*itr)->visited = true;
(*itr)->predecessor = s;
q.push_back(*itr);
}
}//end for
}//end while
Here is my graph and vertex class:
class directedGraph
{
private:
class vertex
{
public:
string data;
bool visited;
vertex * predecessor;
list<vertex*> adjList;
vertex(string x)
{
data = x;
visited = false;
}
};
list<vertex*> vertexList;
I want to make a binary tree in c++ that perform insert operation the inserted values are 4 on a node that is
name, type , order, and color
The use will enter these 4 as INSERT corn oil 3 yellow. It create a new node with name as corn and 3 child node as type ,order and color.
If again user enter same thing but change any other except name that exists like
INSERT corn oil 4 red as corn name exist this will update node
preorder and postorder traversal with remove and find any node
Here is how i am going ?
struct TreeNode {
string itemname; // The data in this node.
TreeNode *left; // Pointer to the left subtree.
TreeNode *right; // Pointer to the right subtree.
};
1- Name node will have 2 values left right where 4th will be place
2- The hierarchy of tree is like root have only names that have 2 left right node so root have many nodes with names that have only 2 further node but no more node will be added to child node of names is it really a tree
Since you are using binary tree, I am not sure you can use string as a key for TreeNode (well I have always used intigers). So what I suggest is that you have structure like this:
// I am not sure about types, but I assumed them by name
struct Element {
char* name;
int type;
int order;
char* color;
};
struct TreeNode {
int key;
Element *element;
TreeNode *left, *right;
};
Then you would somehow calculate hash of Element::name to get a numeric value, which a is key. Now you would just traverse tree from root to the left or right depending on key. You would check on each node if key you are inserting is same as one in current node and if answer is yes, then you would swap values in that node, otherwise continue traversing the tree to the left or right. If you get to the bottom it means you haven't find a node with that key, so you create a new one and attach it as a leaf.
You can look this link to generate hash. However, keep in mind that for some string you can get same hash value, so you may need to keep more than one element at the current tree node.
UPDATE
Here is the code, however you can optimize it more by using pointers. But as mentioned in comments, if you are not strictly bound to use binary tree, you should use HashTable or std::map.
std::map<std::string, struct Element*> elements
and for retrieving element:
Element *e = elements["corn"]
Binary Tree implementation:
#include <iostream>
#include <vector>
#define A 54059 /* a prime */
#define B 76963 /* another prime */
#define C 86969 /* yet another prime */
#define FIRSTH 37 /* also prime */
struct Element {
std::string name;
std::string type;
int order;
std::string color;
};
struct TreeNode {
int key;
std::vector<Element> values;
struct TreeNode *left;
struct TreeNode *right;
};
/**
* see: https://stackoverflow.com/questions/8317508/hash-function-for-a-string
*/
int calculateHash(const char *s)
{
int h = FIRSTH;
while (*s) {
h = (h * A) ^ (s[0] * B);
s++;
}
return h; // or return h % C;
}
void printElement(Element element)
{
std::cout
<< element.name
<< " "
<< element.type
<< " "
<< element.order
<< " "
<< element.color
<< std::endl;
}
void preOrder(TreeNode* node)
{
if( node == NULL )
return;
for(size_t i=0; i<node->values.size(); i++) {
printElement(node->values[i]);
}
preOrder(node->left);
preOrder(node->right);
}
void insert(TreeNode** root, Element element, int key)
{
if( *root == NULL ) {
TreeNode* node = new TreeNode();
node->key = key;
node->values.push_back(element);
*root = node;
return;
};
if( key == (*root)->key ) {
for(size_t i=0; i<(*root)->values.size(); i++) {
if( (*root)->values[i].name == element.name ) {
(*root)->values[i].type = element.type;
(*root)->values[i].order = element.order;
(*root)->values[i].color = element.color;
break;
}
}
}
else if( key < (*root)->key ) {
insert( &((*root)->left), element, key );
}
else {
insert( &((*root)->right), element, key );
}
}
int main()
{
TreeNode *node = NULL;
insert(&node, {"corn1", "oil", 3, "yellow"}, calculateHash("corn1"));
insert(&node, {"corn2", "oil", 3, "yellow"}, calculateHash("corn2"));
insert(&node, {"corn3", "oil", 3, "yellow"}, calculateHash("corn3"));
insert(&node, {"corn2", "aaa", 32, "blue"}, calculateHash("corn2"));
preOrder(node);
return 0;
}
After extensive testing and debugging, I cannot for the life of my find out why my topological sort algorithm produces the incorrect output. It simply lists the values of the nodes in descending order instead of sorting them topologically. I have listed all relevant classes/input files. Any hints or help is appreciated, thanks in advance.
Header for class graph:
/*
2/19/2016
This is the header for class graph. It includes the definition of a node
and the function signatures
*/
#pragma once
#include <iostream>
using namespace std;
struct node
{
// actual value at each node
int value;
// discovered time
int d;
// finished time
int f;
// keep track of how many edges each vertex has
int numEdges;
// keep track of color of node
char color;
// parent (previous) node
node* p;
// next node
node* next;
};
// Class to represent a graph
class Graph
{
public:
// constructor, give number of vertexes
Graph(int V);
// depth first search
void DFS();
// function to print sorted nodes
void print();
// function for reading file into adjacency list
void readFile(istream& in);
private:
// private function called in depth first search, visits every vertex
// of each edge in the graph
void DFSVisit(node* u);
// number of vertices
int V;
// array of node pointers, first node in each array is
// the vertex and following nodes are edges
node* adj[9];
// linked list to keep track of the sorted list found from depth first search
node* sorted;
// keep track of when each node is discovered/finished
int time;
// keep track of number of backedges
int backEdge;
};
The cpp file for class graph
/*
2/19/2016
This is the cpp file for class graph. It defines function behavior
*/
#include "Graph.h"
using namespace std;
#include <iostream>
#include <string>
Graph::Graph(int V)
{
// set graph's number of vertexes to number input
this->V = V;
this->backEdge = 0;
}
// Depth first search
void Graph::DFS()
{
// initialize all colors to white and parent to null
for (int i = 0; i < V; i++)
{
adj[i]->color = 'w';
adj[i]->p = NULL;
}
// initialize time to 0
time = 0;
// for each vertex, if it is white, visit its adjacent nodes
for (int i = 0; i < V; i++)
{
if (adj[i]->color == 'w') {
DFSVisit(adj[i]);
}
}
}
// Visit node used by depth first search
void Graph::DFSVisit(node* u)
{
// increment time
time++;
// set u's discovered time
u->d = time;
// set color to grey for visited but not finished
u->color = 'g';
// visit each adjacency, number of adjacencies stored by numEdges
for (int i = 0; i < u->numEdges; i++)
{
// create node pointing at u next
node* v = u->next;
// if the node is already grey, then it is a backedge
if (v->color == 'g') {
backEdge++;
}
// if it is white and undiscovered, set its parent to u and visit v's next nodes
else if (v->color == 'w') {
v->p = u;
DFSVisit(v);
}
}
// set last node to black
u->color = 'b';
// increment time
time++;
// set finishing time
u->f = time;
if (backEdge == 0) {
// adds a node to front of linked list that contains sorted values
node* newNode = new node;
newNode->next = sorted;
newNode->value = u->value;
sorted = newNode;
}
}
void Graph::print()
{
if (backEdge == 0) {
node* curr = sorted;
if (sorted == NULL) {
return;
}
else {
cout << "Sorted List:\n";
for (; curr; curr = curr->next)
{
cout << curr->value << " ";
}
cout << endl;
}
}
else cout << "Backedges: " << backEdge << endl;
}
void Graph::readFile(istream& in)
{
// create node pointers to use later
node* head;
node* prev;
node* curr;
// temp string to use while reading file
string temp;
int j;
// loop iterate vertex number of times
for (int i = 0; i < V; i++)
{
// 3rd character in string holds name of first edge
j = 3;
// read line by line
getline(in, temp);
// debug print out adjacency list
// cout << temp << endl;
// create head node, set value to value of vertex, put it at beginning of each linked list
head = new node;
head->value = i + 1;
adj[i] = head;
// set numEdges to 0 when row is started
adj[i]->numEdges = 0;
// set prev to head at end of each outer loop
prev = head;
// read every adjacency for each vertex, once j goes outside of string reading is done
while (j < temp.length()) {
// increment numEdges, meaning vertex has one more adjacency
adj[i]->numEdges++;
// create node and put in value, found by moving j up two spaces and subtracting 48
// because it is a char casted as an int
curr = new node;
curr->value = (int)temp.at(j) - 48;
// connect node, increment j by 2 because adjacencies separated by a whitespace
prev->next = curr;
prev = curr;
j += 2;
}
}
}
The driver for the program
/*
2/19/2016
This is the driver for the topological sort project. It reads a file of
vertexes and edges into an adjacency list and performs a depth first
search on that graph representation, creating a topological sort
if no backedges exist, this indicates a DAG or directed acyclic graph
if backedges do exist, this indicates a graph containing cycles meaning
it cannot be topologically sorted
*/
#include <iostream>
#include <fstream>
#include <string>
#include "Graph.h"
using namespace std;
string FILE_NAME = "graphin-DAG.txt";
int NUM_VERTICES = 9;
int main()
{
// create graph object giving number of vertices
Graph myGraph(NUM_VERTICES);
// open file
ifstream fin(FILE_NAME);
// validate that file was successfully opened, without file print
// error and exit program
if (!fin.is_open()) {
cerr << "Error opening " + FILE_NAME + " for reading." << endl;
exit(1);
}
// read file into adjacency list
myGraph.readFile(fin);
// perform depth first search
myGraph.DFS();
// if graph is a DAG, print topological sort, else print backedges
// this is handled by the print function checking backedges data member
myGraph.print();
}
And the input file
1: 2
2: 3 8
3: 4
4: 5
5: 9
6: 4 7
7: 3 8
8: 9
9:
Also a visual representation of the graph represented by the adjacency list:
http://i.imgur.com/6fEjlDY.png
I think the main problem was that there was some confusion between the 'real' nodes and the nodes in your adjacency list. At least I got confused, so I split the structure into struct Node and struct Adj. The graph now has a Node* nodes[9] for the nodes.
struct Node;
struct Adj
{
Node* node;
Adj* next;
};
struct Node
{
// actual value at each node
int value;
// discovered time
int d;
// finished time
int f;
// keep track of color of node
char color;
// the list od adjacencies for the node
Adj* adj;
};
and things almost instantly seem to work. The answer
Sorted List:
6 7 3 4 5 1 2 8 9
seems correct, [6 7 3 4 5] and [1 2 8 9]. See working example here
Please note that there are still numerous issues with the code, esp. with regard to memory management. Consider using a vector<Node> and a std::vector<Adj>. There are also uninitialized variables in the structs.
I have built a BST that holds a name as it's primary data, along with the weight associated with that name (as in when the info is inserted it goes in as Tom - 150, but is sorted in the tree by Tom). I need to be able to determine who has the lowest weight and I am not sure how to go about it. Below is the code for the class and the add method, I have plenty others, but don't feel the need to post them as they seem unrelated (I can if needed though).
#include <iostream>
using namespace std;
class tNode
{
public:
string name;
int wt;
tNode *left, *right;
tNode()
{
left = right = 0;
}
tNode(string name, int wt, tNode *l = 0, tNode *r = 0)
{
this->name = name;
this->wt = wt;
left = l;
right = r;
}
};
class bSTree
{
public:
tNode *root;
bSTree()
{
root = 0;
}
bool add(string name, int wt)
{
tNode *temp = root, *prev = 0;
while (temp != 0)
{
prev = temp;
if (name < temp->name)
{
temp = temp->left;
}
else
{
temp = temp->right;
}
}
if (root == 0)
{
root = new tNode(name, wt);
}
else if (name < prev->name)
{
prev->left = new tNode(name, wt);
}
else if (name > prev->name)
{
prev->right = new tNode(name, wt);
}
else
{
return false;
}
return true;
}
Anyways, what is the technique of doing this? I found the lowest name value (alphabetically) by just going down the left of the tree as far as it could, but I am not 100% sure on the technique for finding the lowest weight, since the tree is not sorted by the weight. I'm not experienced as I'd like to be in c++ and the only thing I can think of is going through every weight, inputting the data to an int, then sorting the ints to find the lowest. I can't imagine this is the correct way to do it, or at least the most efficient. Any help is always appreciated. Thanks!
EDIT:
This is what I have came up with so far:
void searchWeight(tNode* temp)
{
// DETERMINE LOWEST WEIGHT CONTAINED IN TREE
if (temp != 0)
{
cout << temp->wt << endl;
searchWeight(temp->left);
searchWeight(temp->right);
}
}
This will output all of the weights to the console, but I'm not sure how to go through each one and determine the lowest. I've tried putting another if statement in there where
if(currwt < minwt)
minwt = currwt
but no luck with it outputting properly in the end.
You do not have to sort the tree to get the node with minimum weight.
Just do a traversal of the tree and store the lowest weight and the person who has the lowest weight. Update the two variables if the current node's weight is less than the minimum weight. You will have the lowest weight at the end of the traversal.
The pseudocode will look something like,
minWeight = 0
minWeightPerson = ""
for each node in the tree:
if ( minWeight > weight of current node):
minWeight = weight of current node
minWeightPerson = person in current node
return minWeightPerson
You will need to loop through the entire BST since you're not searching by the tree's primary key. You can use any of the tree traversal algorithms.
If you need to search by weight a large number of times (and simply searching the entire tree isn't fast enough), then it will be worth it to build an "index", i.e. a second BST that points to the nodes in the first BST, but is sorted on the secondary key.
Looping through the tree once will be O(n), but looping through the tree m times will be O(m*n). Building a second binary search tree with different index will be O(n*log(n)), and then searching the second tree m times will be O(m*log(n)), so the entire operation is O(n*log(n)+m*log(n)) = O((n+m)*log(n)).
I'm having trouble creating a Depth First Search for my program. So far I have a class of edges and a class of regions. I want to store all the connected edges inside one node of my region. I can tell if something is connected by the getKey() function I have already implemented. If two edges have the same key, then they are connected. For the next region, I want to store another set of connected edges inside that region, etc etc. However, I am not fully understanding DFS and I'm having some trouble implementing it. I'm not sure when/where to call DFS again. Any help would be appreciated!
class edge
{
private:
int source, destination, length;
int key;
edge *next;
public:
getKey(){ return key; }
}
class region
{
edge *data;
edge *next;
region() { data = new edge(); next = NULL; }
};
void runDFS(int i, edge **edge, int a)
{
region *head = new region();
aa[i]->visited == true;//mark the first vertex as true
for(int v = 0; v < a; v++)
{
if(tem->edge[i].getKey() == tem->edge[v].getKey()) //if the edges of the vertex have the same root
{
if(head->data == NULL)
{
head->data = aa[i];
head->data->next == NULL;
} //create an edge
if(head->data)
{
head->data->next = aa[i];
head->data->next->next == NULL;
}//if there is already a node connected to ti
}
if(aa[v]->visited == false)
runDFS(v, edge, a); //call the DFS again
} //for loop
}
assuming n is total number of edges, k is final number of regions.
Creating adjacency list for the requisite DFS might be too costly O(n^2) (if k=1 i.e. all edges belong to same region) and hence dfs will cost you O(V+E) i.e. O(n^2) in the worst case.
Otherwise problem is easily solvable in O(n * log(k)) as follows:
Traverse through all edges adding them to the head of corresponding regions (using balanced bst eg. stl-map) [you may use hashing for this too]
traverse through all the regions and connect them in requisite linear fashion
No guaranteed O(n) solution exists for the problem I guess..
I tried to implement a adjacency list creating function.The next pointer of adj_list struct takes you down the adjacency list(there is no relationship between 2 nodes connected by next) and the list pointer is the adjacency list. The node has the address of the adj_list which has its adjacency list.
struct node{
int id;
adj_list* adj;
};
struct adj_list{
adj_list* next;
adj_list* list;
node* n;
adj_list(node& _n){
n = &(_n);
next = NULL;
list = NULL;
}
};
node* add_node(int id,std::queue<int> q , node* root)
{
node* n = new node(id);
adj_list* adj = new adj_list(*n);
n->adj = adj;
if(root == NULL){
return n;
}
std::queue<adj_list*> q1;
while(1){
adj_list* iter = root->adj;
if(q.empty())break;
int k = q.front();
q.pop();
while(iter){
if(iter->n->id == k){
q1.push(iter);
adj_list* temp = iter->list;
iter->list = new adj_list(*n);
break;
}
iter = iter->next;
}
}
adj_list* iter = root->adj;
while(iter->next){
iter = iter->next;
}
iter->next = adj;
while(!q1.empty()){
adj_list* temp = q1.front();
q1.pop();
adj->list = temp;
adj = temp;
}
return root;
}