I am writing a code for a graph in c++ but there is some problem. It is not working properly. Please help me what is the problem with it? Its code for a graph which can take inputs for graph from user and each edge in graph has specific weight.
Here is the code:
#include <iostream>
#include <vector>
using namespace std;
struct edge {
char src;
char dest;
int weight;
};
class Graph {
public:
vector<edge> edges;
int size,j=0;
//Constructor
Graph(int c) {
size=c;
}
void graphDesign(char s,char d,int w) {
edges[j].src=s;
edges[j].dest=d;
edges[j].weight=w;
j++;
}
void printGraph() {
for(int i=0; i<size; i++) {
cout<<edges[i].src<<"->"<<edges[i].dest<<" :
<<edges[i].weight<<endl;
}
}
};
int main() {
int e,i,w;
char s,d;
cout<<"Enter number of edges of graphs: ";
cin>>e;
Graph graph(e);
for(i=0; i<e; i++) {
cout<<"Enter source: ";
cin>>s;
cout<<"Enter destination: ";
cin>>d;
cout<<"Enter weight of the edge: ";
cin>>w;
graph.graphDesign(s,d,w);
}
graph.printGraph();
return 0;
}
One issue is here:
void graphDesign(char s,char d,int w) {
edges[j].src=s;
edges[j].dest=d;
edges[j].weight=w;
j++;
}
Since edges is an empty vector, accessing edges[j] is an illegal access.
You need to size the edges vector appropriately before you use it.
class Graph {
public:
vector<edge> edges;
//Constructor
Graph(int c) : edges(c) {}
This creates a vector with c entries.
Also, do not use extraneous, unnecessary member variables such as size here. The vector class has a size() member function to tell you how many items are in the container.
Using extraneous variables like size runs the risk of bugs occurring due to having to update this variable anytime the vector changes size. Instead of trying to do this housekeeping yourself, use the size() function provided to you by std::vector.
Related
#include<iostream>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
struct Edge{
int dest, weight;
};
map<int, vector<Edge> > Edges;
void CreateAdj(int src){
if(!Edges.count(src)){
vector<Edge> temp;
Edges[src] = temp;
}
}
void AddEdge(int src, int dest, int weight){
struct Edge temp;
temp.dest = dest;
temp.weight = weight;
Edges[src].push_back(temp);
}
int main(){
int Edges;
cin >> Edges;
int src, dest, weight;
for(int i = 0; i < Edges; i++){
cin >> src >> dest >> weight;
CreateAdj(src);
CreateAdj(dest);
AddEdge(src, dest, weight);
AddEdge(dest, src, weight);
}
int x;
cin >> x;
for(vector<Edge>::iterator it = Edges[x].begin(); it!=Edges[x].end(); ++it){
cout << it->weight;
}
}
I was trying to implement Dikjstra's shortest path. For the adjacency list, I created a map where int was key to a vector of the struct Edge, where Edge contains the weight and the destination.
I have actually made some changes from what I had originally written. I though the vector may not be getting initiated at all, so I added the CreateAdj function which created a vector and mapped it in Edges.
But, I'm not able to iterate through the vector of Edges.
Right now, most variables are global. The error is:
mainI.cpp:43:60: error: subscripted value is not an array, pointer, or vector
for(vector<Edge>::iterator it = Edges[x].begin(); it!=Edges[x].end(); ++it){
When I made Edges local in int, it gave nothing. No error, no output.
int Edges;
cin >> Edges;
for(vector<Edge>::iterator it = Edges[x].begin(); it!=Edges[x].end(); ++it)
"Edges" is just an integer value(not any vector), so you would not be able to iterate over it. integer "Edges" in main would override the map "Edges",which is global.
Moreover, you have not defined any Vector of "Edge" called as "Edges" and you are trying( you are meant) to iterate over map "Edges" ,which is int "Edges" in main.
Please rename you variables and data structures carefully,take care of scopes.
I am trying to use the vector erase function to delete a string that is an element of a vector for a homework assignment. I have tried the line two ways:
vectnames.erase(vectnames[blowup]);
vectnames.erase(blowup);
Does anyone know why the erase function might not be working? As a bit of background, I have to allow the user to enter a planet name to a vector and also let them delete it by name. The example I found online used line #2, but it's not working...
Here is the rest of my code for reference.
#include <iostream>
#include <string>
#include <cmath>
#include <vector>
using namespace std;
class planet
{
private:
string n;
double d, m;
public:
void Density (double d, double m)
{
double Den = m/((4.0/3.0)*M_PI*pow((d/2.0), 3.0));
cout<<"Density: "<<Den<<endl;
}
void SurfaceArea(double d)
{
double S = 4.0*M_PI*pow((d/2.0), 2.0);
cout<<"Surface Area: "<<S<<endl;
}
void Name (string n)
{
string N = n;
cout<<"Name: "<<N<<endl;
}
void Gravity (double G, double m, double d)
{
double F = G*m/pow((d/2.0), 2.0);
cout<<"Force of gravity: "<<F<<endl;
}
};
int main()
{
const double G=6.67384e-11;
int c=0;
string n, N, blowup;
double d=0.0, m=0.0, Den=0.0, S=0.0, F=0.0;
vector<string> vectnames;
vector<double> vectdiam;
vector<double> vectmass;
do
{
cout<<"1. Add a planet\n";
cout<<"2. Delete planet\n";
cout<<"3. Find planet (by name)\n";
cout<<"4. List all planets\n";
cout<<"5. Sort (alphabetical order)\n";
cout<<"6. Quit\n";
cout<<endl;
cout<<"Please select an option from the menu above."<<endl;
cin>>c;
cout<<endl;
if(c==1)
{
planet red;
cout<<"Enter the planet's name: ";
cin>>n;
cout<<"Enter the planet's diameter: ";
cin>>d;
cout<<"Enter the planet's mass: ";
cin>>m;
cout<<endl;
vectnames.push_back(n);
vectdiam.push_back(d);
vectmass.push_back(m);
red.Name(n);
red.Density(d, m);
red.SurfaceArea(d/2.0);
red.Gravity(G, m, d);
cout<<endl;
}
else if (c==2)
{
cout<<"Fire the Death Star's superlaser at: "<<endl;
cin>>blowup;
vectnames.erase(vectnames[blowup]); //This is the part that I'm having trouble with
for (int i=0; i<vectnames.size(); i++)
{
cout<<vectnames[i]<<endl;
}
}
else if (c==4)
{
for (int i=0; i<vectnames.size(); i++)
{
planet red;
cout<<"Planet name: "<<vectnames[i]<<endl;
cout<<"Planet diameter: "<<vectdiam[i]<<endl;
cout<<"Planet mass: "<<vectmass[i]<<endl;
red.Density(vectdiam[i], vectmass[i]);
red.SurfaceArea(vectdiam[i]/2.0);
red.Gravity(G, vectmass[i], vectdiam[i]);
cout<<"************************"<<endl;
cout<<endl;
}
}
} while (c!=6);
system("pause");
return 0;
}
I'm going to work with vector<planet> planets; because it's got a nice ring to it and it's purpose is about as close to obvious as I can get without using an idiotically long name like VectorOfPlanets.
In order to erase an item from a vector you have to know where it is. There are a bunch of ways to do this from brute force searching the vector in a loop until you find the index of the item you want and then calling planets.erase(planets.begin + index);
I thought there was a overload of std::find you could pass a comparator function, but it looks like I'm on crack. Glad I didn't make an ass of myself by suggesting it. Wait... Am I writing out loud? Crap. Hate it when I do that.
Read up on how to create an operator= method in the planet class and you can use std::find. With it you can:
vector<planet> planets;
vector<planet>::iterator it;
it = std::find(planets.begin(), planets.end());
if (it != planets.end())
{
planets.erase(it);
}
I do not know how to work with structures inside a class. I think I have the first part right but nothing works in the main. When I try running my program it says "function does not take 0 arguments" Should I write everything in the main like this:
P.Read(BOX m);
Here's my code so far as below:
#include <iostream>
#include <string>
using namespace std;
template <class T, int n>
class SIX
{
private:
struct BOX
{
T a[n];
string name;
};
public:
void Read(BOX m)
{
cout<<"Enter your name: ";
cin>>m.name;
cout<<m.name<<" please enter "<<n<<" data: ";
for(int i=0;i<n;++i)
cin>>m.a[i];
}
void SortArray(BOX m)
{
sort(m.a, m.a+n);
}
void Display(BOX m)
{
cout<<m.name<<" this is the sorted list of data in your array a: ";
for(int i=0;i<n;++i)
cout<<m.a[i]<<'\t';
cout<<endl;
}
};
int main()
{
SIX <int, 6> P;
SIX <string, 5> Q;
P.Read();
P.SortArray();
P.Display();
cout<<endl;
Q.Read();
Q.SortArray();
Q.Display();
cout<<endl;
system("pause");
return 0;
}
No, define Read as
void Read()
{
cout<<"Enter your name: ";
cin>>BOX.name;
cout<<BOX.name<<" please enter "<<n<<" data: ";
for(int i=0;i<n;++i)
cin>>BOX.a[i];
}
Read is a member function, and it has access to Box, so that's all you have to do.
Same for the other functions, you don't need to specify BOX m as the parameter, replace it by () and replace m by BOX inside the code.
As #Barmar pointed out, your struct BOX just defines a type, you should define a member variable named BOX. Simplest way to do it is to just move BOX to the end of struct declaration,
struct
{
T a[n];
string name;
} BOX;
#ifndef BINARY_TREE_H
#define BINARY_TREE_H
#include<iostream>
#include<vector>
using namespace std;
class Binary_Tree;
static int levelCount=0;
extern vector<vector<Binary_Tree*>> vec;
extern vector<Binary_Tree*> tempVec;
class Binary_Tree
{
public:
Binary_Tree()
{
childNum=0;
data=0;
level=0;
prev=NULL;
next[0]=NULL;
next[1]=NULL;
};
Binary_Tree(int d)
{
childNum=0;
data=d;
level=0;
prev=NULL;
next[0]=NULL;
next[1]=NULL;
levelCount++;
}
void insert_node(int,int,int);
int get_level();
int get_childCount();
friend int set_childNum(Binary_Tree*);
private:
int childNum;
int data;
int level;
Binary_Tree *prev;
Binary_Tree *next[2];
};
#endif // BINARY_TREE_H
Here is the implementation file
#include<iostream>
#include<cmath>
#include "Binary_Tree.h"
using namespace std;
void Binary_Tree::insert_node(int lev, int d, int sib)
{
if(vec.empty())
{
cout<<"You Have to create Root first";
}
else
{
if(set_childNum(vec[lev][sib-1])==0)
{
cout<<"Child cant be created parent Node already has two childs.";
}
else
{
childNum=set_childNum(vec[lev][sib-1]);
data=d;
level=lev+1;
prev=vec[lev][sib];
next[0]=NULL;
next[1]=NULL;
tempVec.clear();
for(int i=0; i<pow(2,(lev+1)); i++)
{
if(i==childNum-1)
{
tempVec.push_back(this);
}
else
tempVec.push_back(vec[lev][i]);
}
vector<vector<Binary_Tree*>>::iterator itr=vec.begin()+(lev+1);
vec.erase(itr);
vec.insert(itr,tempVec);
}
}
}
int set_childNum(Binary_Tree *lstNdAdr)
{
if(lstNdAdr->get_childCount()==0)
return 1;
else if(lstNdAdr->get_childCount()==1)
return 2;
else
return 0;
}
int Binary_Tree::get_level()
{
return level;
}
int Binary_Tree::get_childCount()
{
if(next[0]==NULL)
{
return 0;
}
else if(next[0]!=NULL && next[1]==NULL)
{
return 1;
}
else
{
return 2;
}
}
MAIN.cpp
#include <iostream>
#include<cmath>
#include"Binary_Tree.h"
using namespace std;
vector<vector<Binary_Tree*>> vec;
vector<Binary_Tree*> tempVec;
int main()
{
Binary_Tree tree;
here:
cout<<"Enter your Choice:1.Create Root Of Tree\n"
<<"2.Insert node\n"<<endl;
int choice;
cin>>choice;
switch(choice)
{
case 1:
{
int d;
cout<<"Enter Data to insert: ";
cin>>d;
Binary_Tree treeDummy(d);
tree=treeDummy;
tempVec.push_back(&tree);
vec.push_back(tempVec);
}
break;
case 2:
{
int lev;
int sibbling;
int d;
cout<<"Enter at which level and data and parent's sibling-no.: ";
cin>>lev;
cin>>d;
cin>>sibbling;
if(sibbling>pow(2,lev))
cout<<"Illegal Sibbling Number."<<endl;
else
tree.insert_node(lev,d,sibbling);
}
break;
}
int x;
cin>>x;
if(x==5)
{
cout<<endl<<endl;
goto here;
}
return 0;
}
in above code i am trying to create a binary tree type structure which can be manipulated and traversed dynamically that is any node can be inserted and can be removed at run time (although its incomplete because i am stuck at a problem). While pushing back the tempVec vector the code produces a segmentation fault and i am also doubtful in passing the object stored in vetcor> vec to the functions in the implementation (I am new to Stl and first time dealing with vector of vectors containing pointer to the class types)
The nested vector's entries are only filled if i is set to 1. But you attempt to access its element [0][0] regardless. You have out of bounds access when i is not 1.
There are numerous problems present in your code, that and combined with the poor style and formatting makes it not so fun to debug.
Binary_Tree treeDummy(d);
tree = treeDummy;
tempVec.push_back(&tree);
I'm not sure what you're trying to do here but the above looks wrong. You are shallow copying treeDummy's data over to tree. You'll lose the link to whatever child node tree points to. Afterwards you're pushing that same tree instance into your temporary vector. That means all the elements in your vector ends up pointing to the local variable tree in main. So even if no segfault occurred you would run into aliasing problems since they all refer to the same tree object and not a separate unique BinaryTree instance.
vector< vector<Binary_Tree*> >::iterator itr=vec.begin()+(lev+1);
vec.erase(itr);
vec.insert(itr,tempVec);
Your BinaryTree::insert_node is using an invalidated iterator after performing erase which is undefined behavior.
childNum = set_childNum(vec[lev][sib-1]);
// ...
prev = vec[lev][sib];
The above can access an out-of-bound index in your vector. eg. You push_back a tempVec with only 1 element in it and then call insert_node with sib = 1.
// ...
if(x == 5)
{
cout<<endl<<endl;
goto here;
}
The use of goto is also completely unnecessary here and should be replaced with a traditional while loop that checks for condition != 5.
The higher level problem in your program, however, is that there's no clear constraints and invariants in its design. What assumptions and preconditions do each of those functions need to work? Why use vectors to hold BinaryTree nodes when the class itself should be dealing with that. You should get the overall design sorted out first, otherwise you'll just play whack-a-mole as other bugs crop up.
I am looking for a concise and precise adjacency list representation of a graph in C++. My nodes are just node ids. Here is how I did it. Just want to know what experts think about it. Is there a better way?
This is the class implementation (nothing fancy, right now don't care about public/private methods)
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
class adjList {
public:
int head;
vector<int> listOfNodes;
void print();
};
void adjList :: print() {
for (int i=0; i<listOfNodes.size(); ++i) {
cout << head << "-->" << listOfNodes.at(i) << endl;
}
}
class graph {
public:
vector<adjList> list;
void print();
};
void graph :: print() {
for (int i=0; i<list.size(); ++i) {
list.at(i).print();
cout << endl;
}
}
My main function parses an input file line by line. Where each line is interpreted as following:
<source_node> <node1_connected_to_source_node> <node2_connected_to_source_node <node3_connected_to_source_node> <...>
Here is the main:
int main()
{
fstream file("graph.txt", ios::in);
string line;
graph g;
while (getline(file, line)) {
int source;
stringstream str(line);
str >> source;
int node2;
adjList l;
l.head = source;
while (str >> node2) {
l.listOfNodes.push_back(node2);
}
g.list.push_back(l);
}
file.close();
g.print();
getchar();
return 0;
}
I know I should add addEdge() function inside adjList class instead of directly modifying its variable from main() however, right now I just wonder about the best structure.
EDIT:
There is one shortcoming in my approach. For a complicated graph with large number of nodes, node will indeed be a struct/class and in that case I will be duplicating values by storing the whole object. In that case I think I should use pointers. For example for an undirected graph, I will be storing copies of node objects in the adjList (connection between node 1 and 2 means 1's adjacency list will have 2 and vice versa). I can avoid that by storing pointers of node objects in the adjList instead of the whole object. Check the dfs implementation which get benefited by this approach. There I need to insure that each node gets visited only once. Having multiple copies of the same node will make my life harder. no?
In this case my class definitions will change like this:
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
class node {
public:
node() {}
node(int id, bool _dirty): node_id(id), dirty(_dirty) {}
int node_id;
bool dirty;
};
class adjList {
public:
node *head;
vector<node*> listOfNodes;
void print();
~adjList() { delete head;}
};
void adjList :: print() {
for (int i=0; i<listOfNodes.size(); ++i) {
cout << head->node_id << "-->" << listOfNodes.at(i)->node_id << endl;
}
}
class graph {
public:
vector<adjList> list;
void print();
void dfs(node *startNode);
};
void graph::dfs(node *startNode) {
startNode->dirty = true;
for(int i=0; i<list.size(); ++i) {
node *stNode = list.at(i).head;
if (stNode->node_id != startNode->node_id) { continue;}
for (int j=0; j<list.at(i).listOfNodes.size(); ++j) {
if (!list.at(i).listOfNodes.at(j)->dirty) {
dfs(list.at(i).listOfNodes.at(j));
}
}
}
cout << "Node: "<<startNode->node_id << endl;
}
void graph :: print() {
for (int i=0; i<list.size(); ++i) {
list.at(i).print();
cout << endl;
}
}
And this is how I implemented main() function. I am using a map<> to avoid duplication of objects. Creating a new object only when its not defined earlier. Checking existence of an object by its id.
int main()
{
fstream file("graph.txt", ios::in);
string line;
graph g;
node *startNode;
map<int, node*> nodeMap;
while (getline(file, line)) {
int source;
stringstream str(line);
str >> source;
int node2;
node *sourceNode;
// Create new node only if a node does not already exist
if (nodeMap.find(source) == nodeMap.end()) {
sourceNode = new node(source, false);
nodeMap[source] = sourceNode;
} else {
sourceNode = nodeMap[source];
}
adjList l;
l.head = sourceNode;
nodeMap[source] = sourceNode;
while (str >> node2) {
// Create new node only if a node does not already exist
node *secNode;
if (nodeMap.find(node2) == nodeMap.end()) {
secNode = new node(node2, false);
nodeMap[node2] = secNode;
} else {
secNode = nodeMap[node2];
}
l.listOfNodes.push_back(secNode);
}
g.list.push_back(l);
startNode = sourceNode;
}
file.close();
g.print();
g.dfs(startNode);
getchar();
return 0;
}
SECOND EDIT
After Ulrich Eckhardt suggestion to put adjacency list in node class, here is what I think is a better data structure to store a graph and perform dfs(), dijkstra() kind of operations. Please note that adjacency list is merged in node class.
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
#include <map>
using namespace std;
class node {
public:
node() {
}
node(int id, bool _dirty): node_id(id), dirty(_dirty) {
//cout << "In overloaded const\n";
}
int node_id;
bool dirty;
vector<node*> listOfNodes;
};
class graph {
public:
vector<node*> myGraph;
void dfs(node* startNode);
};
void graph::dfs(node* startNode) {
startNode->dirty = true;
for (int j=0; j<startNode->listOfNodes.size(); ++j) {
if (!startNode->listOfNodes.at(j)->dirty) {
dfs(startNode->listOfNodes.at(j));
}
}
cout << "Node: "<<startNode->node_id << endl;
}
Can we do better than this?
There are a few things that could be improved, but in general your approach is reasonable. Notes:
You are using int as index into a container, which will give you warning from some compilers, because the size of a container could exceed the size representable as int. Instead, use size_t.
Rewrite your for (int i=0; i<list.size(); ++i) to for(size_t i=0, size=list.size(); i!=size; ++i). Using != instead of < will work with iterators. Reading and storing the size once makes it easier to debug and possibly even more efficient.
Inside the loop to print, you have list.at(i).print();. The list.at(i) will verify the index is valid and raise an exception when not. In this very simple case, I am sure that the index is valid, so using list[i] instead is faster. Also, it implicitly documents that the index is valid and not that you expect it to be invalid.
The print() functions should be constant.
I don't understand what the int head is. Is this some kind of ID for the node? And isn't the ID simply the index inside graph::list? If it is the index, you could compute that on demand using the address of the element minus the address of the first element, so there's no need to store it redundantly. Also, consider validating that index when reading, so you don't have any edges going to a vertex that doesn't exist.
If you don't care about encapsulation on a node-level (which is reasonable!), you could also make this a struct, which saves some typing.
Storing pointers instead of indices is tricky but could improve speed. The problem is that for reading, you might need a pointer to a vertex that doesn't exist yet. There is a hack that allows doing that without using additional storage, it requires first storing the indices in the pointer values (using reinterpret_cast) and after reading, making a second pass on the data where you adjust these values to the actual addresses. Of course, you can also use the second pass to validate that you don't have any edges going to vertices that don't exist at all (which is a place where the at(i) function becomes useful) so this second pass to verify some guarantees is a good thing anyway.
On explicit request, here's an example for how to store an index in a pointer:
// read file
for(...) {
size_t id = read_id_from_file();
node* node_ptr = reinterpret_cast<node*>(id);
adjacency_list.push_back(node_ptr);
}
/* Note that at this point, you do have node* that don't contain
valid addresses but just the IDs of the nodes they should finally
point to, so you must not use these pointers! */
// make another pass over all nodes after reading the file
for(size_t i=0, size=adjacency_list.size(); i!=size; ++i) {
// read ID from adjacency list
node* node_ptr = adjacency_list[i];
size_t id = reinterpret_cast<size_t>(node_ptr);
// convert ID to actual address
node_ptr = lookup_node_by_id(id);
if(!node_ptr)
throw std::runtime_error("unknown node ID in adjacency list");
// store actual node address in adjacency list
adjacency_list[i] = node_ptr;
}
I'm pretty sure that this works in general, though I'm not 100% sure if this is guaranteed to work, which was why I'm reluctant to post this here. However, I hope this also makes clear why I'm asking what exactly "head" is. If it is really just the index in a container, there is little need for it, neither inside the file nor in memory. If it is some kind of name or identifier for a node that you retrieved from a file, then you absolutely need it, but then you can't use it as index, the values there could as well start their IDs with 1 or 1000, which you should catch and handle without crashing!