How to write BFS function in C++? - c++

#include <iostream>
#include <string>
#include <queue>
using namespace std;
void BFS(const string&, const string[], int[][10]);
int main()
{
const int CAP = 10;
string states[CAP] = { "Arizona", "California", "Idaho", "Nevada", "Oregon", "Utah", "Washington" };
string Point;
int matrix[CAP][CAP] =
{
{0,1,0,1,0,1,0},
{1,0,0,1,1,0,0},
{0,0,0,1,1,1,1},
{0,1,1,1,0,0,1},
{1,1,1,1,0,0,0},
{0,0,1,0,1,0,0},
{0,0,1,0,1,0,0}
};
BFS("California", states, matrix);
}
void BFS(const string& Point, const string states[], int matrix[][10])
{
int SPoint = 0;
queue<string> visited;
queue<string> Queue;
string temp = Point;
visited.push(temp);
do
{
for (int i = 0; i < 10; i++)
{
if (states[i] == temp)
{
SPoint = i;
}
}
for (int i = 0; i < 10; i++)
{
if (matrix[SPoint][i] == 1)
{
Queue.push(states[i]);
}
}
visited.push(Queue.front());
Queue.pop();
temp = visited.back();
} while (!Queue.empty());
for (int i = 0; i < 10; i++)
{
cout << visited.front();
visited.pop();
}
}
I'm doing an exercise where I have to make a function that does Breadth-First Search and prints out the visited path. But my function wouldn't print anything. What am I doing wrong here?
Note: The matrix is alphabetical order and represents the connection between states.
My expected output: California Arizona Oregon Nevada Utah Idaho Washington
Exercise description

While I won't offer a complete solution, I can help identify some of the issues the code exhibits.
Major issues
Since you have a cyclic graph, it's important to mark nodes as visited during the BFS else you'll wind up with an infinite loop (which is why nothing gets printed in your current implementation). Your visited queue could be an unordered_set. When nodes are visited, add them to the set and write a conditional to avoid visiting them again.
The adjacency matrix doesn't appear correct. Since it's an undirected graph, I would anticipate that the matrix would be mirrored from top left to bottom right, but it's not. Also, there are no self-edges in the graph yet Nevada appears to have an edge to itself in the matrix.
There's no need to loop over the adjacency matrix--you can index into it by mapping digit indexes and string names appropriately. If you do need to loop, running to 10 is out of bounds on a 7x7 matrix.
Minor issues
There's no sense in arbitrarily restricting the matrix size. Although the assignment enforces this, it's a poor design choice because the code needs to be rewritten any time you want to use a different input graph.
A matrix seems like a slightly awkward data structure here because it introduces an extra layer of indirection to translate strings into integers and back. Although the project doesn't permit it, I'd prefer using a structure like:
std::unordered_map<std::string, std::vector<std::string>> graph({
{"California", {"Oregon", "Nevada", "Arizona"}},
// ... more states ...
});
Ideally, these would be Node objects with neighbor vector members instead of strings.
C++ offers std::vector and std::array which are preferable to C arrays. I assume they haven't been introduced yet in your class or aren't permitted on the assignment, but if you're stuck, you can try writing the code using them, then re-introducing your instructor's constraints after you get it working. If nothing else, it'd be a learning experience.
Avoid using namespace std;.
Reserve uppercase variable names for class names. Objects and primitives should be lowercase.
Pseudocode for BFS
This assumes the preferred data structure above; it's up to you to convert to and from strings and adjacency matrix indexes as needed.
func BFS(string start, unordered_map<string, vector<string>> graph):
vector traversal
queue worklist = {start}
unordered_set visited = {start}
while !worklist.empty():
curr = worklist.pop_front()
traversal.push_back(curr)
for neighbor in graph[curr]:
if neighbor not in visited:
visited.insert(neighbor)
worklist.push(neighbor)
return traversal
Since this is an assignment, I'll leave it at this and let you take another crack at the code. Good luck.

Related

Sorting a vector of structures based on one of the elements

I was writing a program to input the marks of n students in four subjects and then find the rank of one of them based on the total scores (from codeforces.com: https://codeforces.com/problemset/problem/1017/A). I thought storing the marks in a structure would help keeping track of the various subjects.
Now, what I did is simply implement a bubble sort on the vector while checking the total value. I want to know, is there a way that I can sort the vector based on just one of the members of the struct using std::sort()? Also, how do we make it descending?
Here is what the code looks like right now:
//The Structure
struct scores
{
int eng, ger, mat, his, tot, rank;
bool tommyVal;
};
//The Sort (present inside the main function)
bool sorted = false;
while (!sorted)
{
sorted = true;
for (int i = 0; i < n-1; i++)
{
if (stud[i].tot < stud[i + 1].tot)
{
std::swap(stud[i], stud[i + 1]);
sorted = false;
}
}
}
Just in case you're interested, I need to find the rank of a student named Thomas. So, for that, I set the value of tommyVal true for his element, while I set it as false for the others. This way, I can easily locate Thomas' marks even though his location in the vector has changed after sorting it based on their total marks.
Also nice to know that std::swap() works for swapping entire structs as well. I wonder what other data structures it can swap.
std::sort() allows you to give it a predicate so you can perform comparisons however you want, eg:
std::sort(
stud.begin(),
stud.begin()+n, // <-- use stud.end() instead if n == stud.size() ...
[](const scores &a, const scores &b){ return a.tot < b.tot; }
);
Simply use return b.tot < a.tot to reverse the sorting order.

Finding the number of edges and performing a topo sort in my graph implementation

I have been working on a graph implementation for the last few days. All of this is really new to me, and I am stuck on two parts of my implementation. I am implementing a digraph of courses from an input file. From the file, I can determine which courses are prereqs for other courses. I then create a digraph with courses as nodes, and edges connecting courses that are prereqs. I also want to find the total number of nodes and edges, and perform a topological sort on the graph (I will later be adding weights to the edges). Here is my implementation.
Digraph.h
class vertex{
public:
typedef std::pair<int, vertex*> ve;
std::vector<ve> adjacency;
std::string course;
vertex(std::string c){
course = c;
}
};
class Digraph{
public:
void addVertex(std::string&);
void addEdge(std::string& from, std::string& to, int cost);
typedef std::map<std::string, vertex *> vmap;
vmap work;
int getNumVertices();
int getNumEdges();
void getTopoSort();
};
Digraph.cpp
void Digraph::addVertex(std::string& course){
vmap::iterator iter = work.begin();
iter = work.find(course);
if(iter == work.end()){
vertex *v;
v = new vertex(course);
work[course] = v;
return;
}
}
void Digraph::addEdge(std::string& from, std::string& to, int cost){
vertex *f = (work.find(from)->second);
vertex *t = (work.find(to)->second);
std::pair<int, vertex *> edge = std::make_pair(cost, t);
f->adjacency.push_back(edge);
}
Finding the number of nodes was easy just return work.size. I have confirmed this is working properly. I am lost on how I would return the number of edges in my graph. It seems it would be simple, but everything I tried doesn't work. Secondly, I am completely lost on how to perform a topological sort on this graph. Any assistance is appreciated.
A simple way would be to iterate through all vertices in your graph, add up their neighbor counts and then divide by two:
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count / 2;
}
To use the range based for loop, you need to use c++11. With g++ that would be --std=c++11 on the command line.
EDIT:
I just realized you have a directed graph, and you probably want to count one for each direction. In such case: don't divide by two!
int Digraph::getNumEdges(){
int count = 0;
for (const auto & v : work) {
count += v.second->adjacency.size();
}
return count;
}
First, for the number of edges, it would be simpler to count them directly when you build the graph (just add a counter in your Digraph class and increment it each time you add an edge … )
For the topological sort, first I have a question: your edges are from prereqs to dependant courses ? That is you have a link A -> B if A is a prereq of B ? If this not the case, you need to invert your graph.
You to main algorithm in order to build a topological sort: one based on a simple DFS (http://en.wikipedia.org/wiki/Depth-first_search) and the other relying on in-degrees (http://en.wikipedia.org/wiki/Directed_graph#Indegree_and_outdegree) of your vertices (courses in your case.)
Normally, you need to verify that your graph doesn't contain any cycle, which will normally be the case if your data are coherent.
Let's consider the DFS based algorithm: a DFS traverses each vertices from a given root following edges as they appear. We can easily prove that order of last encounter of a vertex forms a reverse topological order. So, all we need is to push in a stack the current vertex after the calls on its successors.
I made a quick and dirty implementation for you, using C++11 again.
First, add the following to the Digraph class:
typedef std::unordered_set<vertex*> marks_set;
marks_set marks;
typedef std::deque<vertex*> stack;
stack topo;
void dfs(vertex* vcur);
Then here comes the code:
void Digraph::dfs(vertex* vcur) {
marks.insert(vcur);
for (const auto & adj : vcur->adjacency) {
vertex* suc = adj.second;
if (marks.find(suc) == marks.end()) {
this->dfs(suc);
} // you can detect cycle in the else statement
}
topo.push_back(vcur);
}
void Digraph::getTopoSort() {
// It should be a good idea to separate this algorithm from the graph itself
// You probably don't want the inner state of it in your graph,
// but that's your part.
// Be sure marks and topo are empty
marks.clear();
topo.clear();
// Run the DFS on all connected components
for (const auto & v : work) {
if (marks.find(v.second) == marks.end()) {
this->dfs(v.second);
}
}
// Display it
for (const auto v : topo) {
std::cout << v->course << "\n";
}
}
The code compiles but I haven't tested. If for any reasons you have an issue with the recursive algorithm (the function Digraph::dfs), it can be derecursified using a stack containing the parent of the target vertex and the iterator to the current successor, the iterator reach the end of the adjacency list, you can push the parent in the topological sort.
The other algorithm is almost as simple: for each vertices you need to count the number of predecessor (in-degree) which can be done while building the graph. In order to compute the topological sort, you look for the first vertex with a in-degree of 0 (no predecessor), you then decrease the in-degree of all its successors and continue with the next vertex with 0. If the graph has no cycle, there will always be a vertex with a in-degree of 0 (at beginning of course, but also during the algorithm run as you decrease it) until all vertices have been seen. The order of vertices encounter form a topological sort (this is related to the Bellman shortest-path algorithm.)
Note that these 2 algorithms are listed here: http://en.wikipedia.org/wiki/Topological_sorting. The one using in-degree is described in terms of removing edges which we simply simulate by decreasing the in-degree (a far less destructive approach … )

Faster way to sort an array of structs c++

I have a struct called count declared called count with two things in it, an int called frequency and a string called word. To simplify, my program takes in a book as a text file and I count how many times each word appears. I have an array of structs and I have my program to where it will count each time a word appears and now I want a faster way to sort the array by top frequency than the way I have below. I used the bubble sorting algorithm below but it is taking my code way too long to run using this method. Any other suggestions or help would be welcome!! I have looked up sort from the algorithm library but don't understand how I would use it here. I am new to c++ so lots of explanation on how to use sort would help a lot.
void sortArray(struct count array[],int size)
{
int cur_pos = 0;
string the_word;
bool flag= true;
for(int i=0; i<(size); i++)
{
flag = false;
for(int j=0; j< (size); j++)
{
if((array[j+1].frequency)>(array[j].frequency))
{
cur_pos = array[j].frequency;
the_word = array[j].word;
array[j].frequency = array[j+1].frequency;
array[j].word = array[j+1].word;
array[j+1].frequency = cur_pos;
array[j+1].word = the_word;
flag = true;
}
}
}
};
You just need to define operator less for your structures,
and use std::sort, see example:
http://en.wikipedia.org/wiki/Sort_%28C%2B%2B%29
After you created a pair of for the data set, you can use std::map as container and insert the pairs into it. If you want to sort according to frequency define std:map as follows
std::map myMap;
myMap.insert(std::make_pair(frequency,word));
std::map is internally using a binary tree so you will get a sorted data when you retrieve it.

BFS using adjacency lists in STL

I am trying to write a program for implementing BFS in C++ using STL. I am representing the adjacency list using nested vector where each cell in vector contains a list of nodes connected to a particular vertex.
while(myQ.size()!=0)
{
int j=myQ.front();
myQ.pop();
int len=((sizeof(adjList[j]))/(sizeof(*adjList[j])));
for (int i=0;i<len;i++)
{
if (arr[adjList[j][i]]==0)
{
myQ.push(adjList[j][i]);
arr[adjList[j][i]]=1;
dist(v)=dist(w)+1;
}
}
}
myQ is the queue i am using to keep the nodes along whose edges i will be exploring the graph. In the notation adjList[j] represents the vector pointing to the list and adjList[j][i] represents a particular node in that list. I am storing whether i have explored a particular node by inputting 1 in the array arr. Also dist(v)=dist(w)+1 is not a part of the code but i want to know how i can write it in the correct syntax where my v is the new vertex and w is the old one which discovers v i.e w=myQ.front().
If I have understood your problem, then you want a data structure to store the distances of the graph nodes.
This can be easily done using map.
Use this:
typedef std::map <GraphNode*, int> NodeDist;
NodeDist node_dist;
Replace dist(v)=dist(w)+1; with:
NodeDist::iterator fi = node_dist.find (w);
if (fi == node_dist.end())
{
// Assuming 0 distance of node w.
node_dist[v] = 1;
}
else
{
int w_dist = (*fi).second;
node_dist[v] = w_dist + 1;
}
Please let me if I have misunderstood your problem or the given solution does not work for you. We can work on that.

Finding occurrence of vector entries in another vector without nested for loops

I have a piece of code that I'm migrating from Fortran to C++, and I'd like to avoid some of the nested for loop structures I had to create in the original F77 code.
The problem is this: I have a vector of objects called nodes that each include a vector holding (among other important info) the indices of other node objects to which each is connected (a connection graph). Like this
struct Node {
vector<int> conNode;
};
vector<Node> listOfNodes;
vector<int> nodeListA; // a subset of nodes of interest stored as their vector indices
I need to look for nodes that nodes in nodeListA are connected to, but only if those nodes are also in nodeListA. Right now, my code looks something like this:
// Loop over the subset of node indices
for (int i=0; i<nodeListA.size(); i++) {
// Loop over the nodes connected to the node i
for (int j=0; j<listOfNodes[nodeListA[i]].conNode.size(); j++) {
// Loop over the subset of node indices again
for (int k=0; k<nodeListA.size(); k++) {
// and determine if any of node i's connections are in the subset list
if (nodeListA[k] == listOfNodes[nodeListA[i]].conNode[j]) {
// do stuff here
}
}
}
}
There HAS to be a much simpler way to do this. It seems like I'm making this way too complicated. How can I simplify this code, possibly using the standard algorithm library?
If your variable should express a set of values, use std::set instead of std::vector. Then you'll have
typedef std::set<int> SetOfIndices;
SetOfIndices setOfIndices; // instead of nodeListA
for(SetOfIndices::const_iterator iter = setOfIndices.begin(); iter != setOfIndices.end(); ++iter)
{
Node const & node = listOfNodes[*iter];
for (int j = 0; j < node.conNode.size(); ++j)
{
if (setOfIndices.find(node.conNode[j]) != setOfIndices.end())
{
// do stuff here
}
}
}
EDIT
As Jerry Coffin suggests, std::set_intersection can be used in outer loop:
struct Node {
SetOfIndices conNode;
}
typedef std::set<int> SetOfIndices;
SetOfIndices setOfIndices; // instead of nodeListA
for(SetOfIndices::const_iterator iter = setOfIndices.begin(); iter != setOfIndices.end(); ++iter)
{
Node const & node = listOfNodes[*iter];
std::vector<int> interestingNodes;
std::set_intersection(setOfIndices.begin(), setOfIndices.end(),
node.conNode.begin(), node.conNode.end(),
std::back_inserter(interestingNodes));
for (int j = 0; j < interestingNodes.size(); ++j)
{
// do stuff here
}
}
ANOTHER EDIT
About efficiency - it depends what is the dominant operation. The number of executions of part described as "do stuff here" will not vary. The difference is in time of traversing your collections:
Your original code - nodeListA.size()^2 * [average conNode size]
My first solution - nodeListA.size() * log(nodeListA.size()) * [average conNode size]
After Jerry Coffin suggestion - nodeListA.size()^2 * [average number of interesting conNode elements]
So it seems that set_intersection use doesn't help in this case.
I'd suggest using a dictionary (an O(log n) one like std::set, or better a hash-based one like std::unordered_set from C++11) for nodeListA. The following is a C++11 code example.
#include <unordered_set>
#include <vector>
struct Node {
std::vector<int> conNode;
};
int main()
{
std::vector<Node> listOfNodes;
std::unordered_set<int> nodeListA;
for (int node_id : nodeListA)
for (int connected_id : listOfNodes[node_id].conNode)
if (nodeListA.find(connected_id) != end(nodeListA))
/* Do stuff here.. */
;
return 0;
}
The advantage of using a std::unordered_set is that look-ups (i.e. searching for a given node-id) are extremely fast. The implementation included in your standard library, however, may not be particularly fast. Google's sparse hash and dense hash implementation is an alternative that provides the same interface and is known to be very good for most purposes: http://code.google.com/p/sparsehash/
Depending on what you want to do with the resulting nodes, it may be possible to replace the inner loop of the above code with an STL algorithm. For example, if you want to put all the nodes identified by the algorithm in a vector, you could code it as follows (use this as a replacement for both loops together):
std::vector<int> results;
for (int node_id : nodeListA)
std::copy_if(begin(listOfNodes[node_id].conNode),
end(listOfNodes[node_id].conNode),
back_inserter(results),
[&nodeListA](int id){return nodeListA.find(id) != end(nodeListA);});
Again, this is C++11 syntax; it uses a lambda as function argument.