Trouble with List or Pointers, Adjacency Representaiton of Graph - c++

The following code is the the beginning of an adjacency list representation of a graph.
In the buildGraph, which is immediately called by main, two vertices are created, then an edge is created between them. But then asking for the size of the edgelist of a vertex should return 1, not 0. I have tried putting couts in various places, and I'm just not able to figure out what the problem is, but I suspect it's due to a misunderstanding of pointers in some way. Thank you for your help!
#include "MinCut.h"
#include <iostream>
#include <list>
void buildGraph(undirected_graph *);
class vertex;
struct edge
{
vertex * start;
vertex * end;
};
class vertex
{
int vertexNumber;
std::list<edge> edges;
public:
int getVertexNumber(){return vertexNumber;}
std::list<edge> getEdges(){return edges;}
vertex(int n){vertexNumber=n;}
};
class undirected_graph
{
private:
std::list<vertex> graph;
public:
void addVertex(vertex v){graph.push_back(v);}
void createEdge(vertex * v1, vertex * v2);
};
void undirected_graph::createEdge(vertex * v1, vertex * v2)
{
std::list<edge> e1 = v1->getEdges();
std::list<edge> e2 = v2->getEdges();
edge e;
e.start=v1;
e.end=v2;
e1.push_back(e);
e2.push_back(e);
}
int main()
{
undirected_graph myGraph;
buildGraph(&myGraph);
return 0;
}
void buildGraph(undirected_graph * g)
{
vertex v1(1);
vertex v2(2);
g->addVertex(v1);
g->addVertex(v2);
g->createEdge(&v1,&v2);
std::list<edge> e = v1.getEdges();
std::cout<< "? " << e.size();
}

In createEdge() you have this:
e.start=v1;
e.start=v2;
Should it instead be
e.start=v1;
e.end=v2;
EDIT: Your problem is in createEdge, e1 and e2 are just copies, so changes don't affect the actual vertex objects.
Here's my solution, seems to be working:
Add a function to vertex like so:
void addEdge(edge &e){edges.push_back(e);}
Then in createEdge():
edge e;
e.start=v1;
e.end=v2;
v1->addEdge(e);
v2->addEdge(e);

In addition to #PatLillis's answer, I think you're also going to run into problems here:
vertex v1(1);
vertex v2(2);
g->addVertex(v1);
g->addVertex(v2);
g->createEdge(&v1,&v2);
The pointers &v1 and &v2 refer to v1 and v2 in your main function. However:
Since you're passing v1 and v2 by value to addVertex, you're going to get copies of those vertices in addVertex. That means your pointers in main will be pointing one place, and the copies will be somewhere else.
Since you're storing your vertices by value in a std::list, you'll have the same problem again. The list will hold copies of the copies in addVertex, and your pointers will still be pointing to the originals in main.
One way to fix this is to deal with vertex* in e.g. addVertex and in your std::list. Alternatively, if you want your graph to "own" the vertices (as opposed to them having potentially separate lifetimes from the graph) you could switch to std::unique_ptr<vertex>.

Related

Parameter in class that has this class type

class Vertex {
public:
Vertex* previous_vertex_id;
Vertex::Vertex() {}
Vertex::~Vertex() {}
}
Now it compiles, but I need strictly previous_vertex_id without pointer, it's for further code, that uses this property. How can I achieve that?
You can't have a class with itself as a member, the size of such an object would be infinite. A Vertex which contains a Vertex which contains a Vertex etc.
It seems, from this question, and one you posted earlier, that you want something java-like, but in C++. You want something like this:
class Vertex {
public:
Vertex* previous_vertex_id;
...
void setPrevious(Vertex &v) {
previous_vertex_id = &v;
}
Vertex &getPrevious() {
return (*previous_vertex_id); // trusting that the pointer will still be valid.
}
}
Now, it is important to know when in C++, an object is copied and when an object is referenced. With the Vertex class I just described:
Vertex v1{}; // construct a new vertex
Vertex v2{}; // construct a new vertex
// v3 is a copy of v1, they are separate objects at different memory locations.
Vertex v3 = v1;
// v4 is a reference to v1, they are the same object under a different name.
Vertex &v4 = v1;
// v1.previous_vertex_id is a pointer to v2.
v1.setPrevious(v2);
// v5 is a copy of v2. A different object at a different memory location.
Vertex v5 = v1.getPrevious();
// v6 is a reference to v2, they are the same object under a different name.
Vertex &v6 = v1.getPrevious();
Now you can use getPrevious to access the previous vertex as a non-pointer. Just be careful in which way you assign it, so you only copy it when intended (v5/v6 example).
just write
Vertex previous_vertex_id;
in the private section. don't use *

Segmentation fault in dijkstra's algorithm

I am writing a c++ program to code for dijkstra's algorithm. Here is the code.
#include <iostream>
#include <vector>
#include <map>
using namespace std;
class vertex;
class node
{
public:
int value;
//bool exp=false;
char c;
};
class edge
{
public:
vertex* head;
vertex* tail;
int length;
edge(vertex*h,vertex* t, int l)
{
head=h;
tail=t;
length=l;
}
};
class vertex:public node
{
public:
vector<edge*> a;
vertex& operator|(vertex &p)
{
int l;
cout<<"Give the length of edge "<<this->c<<p.c<<endl;
cin>>l;
edge q(&p,this,l);
a.push_back(&q);
}
vertex(char a)
{
c=a;
}
};
int main()
{
vertex e('e');
vertex d('d');
vertex b('b');
vertex c('c');
vertex a('a');
vertex s('s');
s.value=1;
a.value=2;
b.value=3;
c.value=4;
d.value=5;
e.value=6;
s|a;
s|b;
a|c;
b|c;
b|d;
c|d;
c|e;
d|e;
cout<<"4";
map <char ,int >A;
vector<edge*>::iterator minin;
vector<edge*>::iterator j;
int min=0;
vector<vertex*> X;
X.push_back(&s);
A['s']=0;
vector<vertex*>::iterator i=X.begin();
for(; i<X.end(); i++)
{
cout<<"1";
j=((*i)->a).begin();
for(; j<((*i)->a).end(); j++)
{
cout<<"2";
if((*j)->length+A[((*j)->tail)->c]>min)
{
cout<<"3";
minin=j;
min=(*j)->length+A[((*j)->tail)->c];
}
}
}
X.push_back((*minin)->head);
A[((*minin)->tail)->c]=min;
cout<<((*minin)->head)->value;
}
The program returns a segmentation fault. I have used various cout statements to check where the fault occured but nothing is printed in console. However, I am able to input the edge length in the console but after giving the input it directly gives segmentation fault.
In
a.push_back(&q);
you are storing the address of a local object, which will cease to exist once the function terminates.
Why are you creating a class to keep your vertices/nodes?. I think you should use plain integers from 0 to N - 1 to avoid get things more complicated. If vertices are identified by a string or something else, you could use a hash/map data structure to transform the keys to an integer. That will help you to avoid moving complex vertex structures and using pointers.
The Edge class seems fine because the Dijkstra's algorithms needs all that data to work (start, end vertices, and the weight/cost of the path).
Having said that, the algorithm could be implemented using a binary heap data structure to prioritize the edge selection. You could also use a priority queue (http://en.cppreference.com/w/cpp/container/priority_queue) if you don't want to implement a binary heap.
Finally, I would use a Edge vector to iterate over the adjacent vertices of every vertex.

Initializing a vector to a list of integers

To represent a Graph in adjacency-list style, I'm using a vector containing pointers to a list of adjacent.
class Graph
{
public:
Graph(int V)
{
vector<list<int> *> vertices(V);
}
// Member functions for Graph class
void addEdge();
void print();
void type(string);
private:
vector<list<int> *> vertices;
};
Getting the number of vertices from the user in main function-> passing it to the constructor, it all works, meaning the vector is being initialized of the desired size! But right after the program comes back from the header file to the main function, Things change! as in tracing the value of vertices: the size is somehow being reset somewhere that I don' know of!!!
int size;
cout << "Enter the number of vertices in the Graph: ";
cin >> size;
Graph g(size);
Immona need help with this, what could possibly go wrong?!
You're creating a temporary vector (local variable) in your constructor :
Graph(int V)
{
vector<list<int> *> vertices(V);
}
You need to initialize your member variable instead :
Graph(int V) : vertices(V) {}
Also, I would suggest using std::unique_ptr<list<int>> instead of raw pointers if you really need to use pointers, else simply store plain std::list<int>.

Using Vector of pointers to Objects which have pointers c++

I have a loop which adds pointers to a vector;
vector<Material *> materials;
and my Material class has 4 attributes :
int id;
float *ambiance;
float *diffuse;
in my loop :
while(input_read_from_the_file !=NULL){
int id=someval1;
float x[2]={someval2,someval3};
float y[2]={someval4,someval5};
materials.push_back(new Material(id,x,y));
}
When I read my materials vector in a for loop I see that ids are different but ambiance and diffuse are same for all the elements.Thats probably because it uses the same pointer in the while loop but I couldnt find an alternative.What should be the best approach here?
Thanks
I'd try to avoid pointers as much as I can.
Let's start with your vector. Why does it need to be vector<Material*> and not vector<Material>?
Unless Material is an inherited class, you can use a vector of Material objects instead of pointers.
That way, you don't need the destructor of the class that has vector<Material*> to iterate and destroy each of them (by using shared_ptr, you can avoid this too).
Now, as mentioned in the comments, the problem is that Material uses pointers for the ambiance and diffuse members. No reason for that too.
Technically, you want it to be Vector3 or Vector4 when you're writing a renderer or material system, but lets go with float[2] instead.
C++11 (0x) has cool move semantics that you can use to avoid the creation of a temporary object (since we're going to push an object into the vector and without move semantics, a temporary object is created while doing so)
So, your code looks like:
class Material {
int id;
float ambiance[2]; // you really ought to use Vector2 instead. pointers are evil.
float diffuse[2];
Material (const int _id, const float _amb[], const float _dif[]) : id(_id) {
ambiance[0] = _amb[0]; ambiance[1] = _amb[1]; // actual copy is made
diffuse[0] = _dif[0]; diffuse[1] = _dif[1];
}
}
-----
vector<Material> materials;
while(input_read_from_the_file !=NULL){
int id = someval1;
float x[2]= {someval2,someval3};
float y[2]= {someval4,someval5};
materials.emplace_back(Material(id,x,y)); // or even materials.emplace_back(id, x, y);
}

STL List to hold structure pointers

I have a structure called vertex and I created some pointers to them. What I want to do is add those pointers to a list. My code below, when it tries to insert the pointer into the list, creates a segmentation fault. Can someone please explain what is going on?
#include <iostream>
#include <list>
#define NUM_VERTICES 8
using namespace std;
enum { WHITE, GRAY, BLACK };
struct vertex
{
int color;
int distance;
char parent;
};
int main()
{
//create the vertices
vertex r = {WHITE, NULL, NULL};
//create pointer to the vertex structures
vertex *pr = &r;
//create a list to hold the vertices
list<vertex*> *r_list = new list<vertex*>;
list<vertex*>::iterator it;
r_list->insert(it, pr);
}
There are several things wrong here.
First off, you aren't initializing the iterator, like other's have said:
list<vertex*>::iterator it = r_list->begin();
Do this and your code will be fine. But your code is done in a bad manner.
Why are you allocating the list from the heap? Look at your code: you have a memory leak. You aren't calling delete r_list anywhere. This is why you should use smart pointers (std::unique_ptr, std::shared_ptr if you have C++11, boost equivalents otherwise : boost::scoped_ptr and boost::shared_ptr)
But better yet, just do it on the stack:
//create a list to hold the vertices
list<vertex*> r_list;
list<vertex*>::iterator it = r_list->begin();
r_list.insert(it, pr);
In addition, using the iterator to insert is going about things the long way. Just use push front() or push back():
//create a list to hold the vertices
list<vertex*> r_list;
r_list.push_back(pr);
Another thing: if your list outlives the vertex you've constructed, it will be pointing to something invalid.
For example:
// global
list<vertex*> r_list;
void some_function(void)
{
//create the vertices
vertex r = {WHITE, NULL, NULL};
//create pointer to the vertex structures
vertex *pr = &r;
r_list.push_back(pr);
} // right here, vertex r stops existing: the list now contains an
// invalid pointer.
One solution is to store pointers to heap-allocated vertices:
// global
list<vertex*> r_list;
void some_function(void)
{
//create the vertices
vertex *r = new vertex;
r->color = WHITE;
r->distance = 0;
r->parent = 0;
r_list.push_back(r);
}
Now even after the function the list is pointing to a valid heap-allocated vertex. This now has the problem that when you're done using the list, you need to go through the lsit and call delete on each element. This problem is assisted by using the Boost Pointer Container Library.
The best way, though, is to just store vertices themselves (rather than pointers to them):
//create a list to hold the vertices
list<vertex> r_list;
//create the vertices
vertex r = {WHITE, NULL, NULL};
r_list.push_back(r);
If you give vertex a constructor, you can even just construct them in-place:
struct vertex
{
int color;
int distance;
char parent;
vertex(int _color, int _distance, char _parent) :
color(_color),
distance(_distance),
parent(_parent)
{
}
};
//create a list to hold the vertices
list<vertex> r_list;
r_list.push_back(vertex(WHITE, NULL, NULL));
(these are now outside your problem)
Firstly, NULL is generally only used when dealing with pointers. Since distance and parent are not pointers, use 0 to initialize them, rather than NULL:
//create the vertices
vertex r = {WHITE, 0, 0};
Secondly, use constants rather than #define:
#define NUM_VERTICES 8 // <- bad
const int NumberVertices = 8; // <- good
Lastly, give your enum a name, or place it in a namespace:
enum Color { WHITE, GRAY, BLACK };
Hope these help!
You haven't initialised the iterator, so it's not valid to insert with. You could use r_list->push_back(pr) instead, for example.
Also, the pointers in your list aren't going to be valid once r goes out of scope. Obviously that's not a problem in this case since it's in main(), but I assume this isn't the exact example where you're going to use the code, so it may come back to bite you...
First of all, you aren't initializing it to anything. Do you mean:
list<vertex*>::iterator it = r_list->begin();
Also, why are you initializing an int and char to NULL? Usually people use NULL for pointers.
Also, how about naming your enum and benefiting from the type safety of enums, instead of using them as ints?
Also, no need to create a new variable to make a pointer to the vertex. When you call insert, you can pass in &r.
Also, as Peter points out, why not just use push_back()?
Your code should look more like this:
using namespace std;
enum Color {
WHITE,
GRAY,
BLACK
};
struct vertex
{
Color color;
int distance;
char parent;
};
int main(int argc, char** argv) {
//create the vertices
vertex r = {WHITE, 0, ''};
//create a list to hold the vertices
list* r_list = new list();
list::iterator it = r_list->begin();
r_list->insert(it, &r);
// Or even better, use push_back (or front)
r_list->push_back(&r);
}
You have not initialized it, so you're inserting at a random/uninitialized place/pointer.
Normal ways of adding items to a std::list include its methods push_back and push_front; you'd normally use insert only if you had previously otherwise determined the specific spot in which you want to insert one more item.