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>.
Related
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.
I am dealing with a task to create a troop of bunnies where they can multiply at each round. So I define a class of Bunny (individual), and then define a class of Troop with a vector point to different bunnies.
My problem is, every time I use new to create an object Bunny in a loop, it will come out an error says:
"Debug assertion failed!!...vector iterator not incrementable..."
Here is a sample of my code:
class Bunny {
private:
string sex;
string color;
string name;
int age;
public:
string getname() { return name;};
Bunny(); // constructor
};
class Troop {
private:
vector<Bunny *> bunpointer;
vector<Bunny *>::iterator it;
public:
void newbunny();
void multiply();
};
void Troop::newbunny() {
Bunny * bun; // pointer to the Bunny class
bun = new Bunny;
cout << "Bunny " << bun->getname() << " is born! \n";
bunpointer.push_back(bun);
}
void Troop::multiply() {
it = bunpointer.begin();
while(it!=bunpointer.end()) {
cout << (*it)->getname() << " gave a birth. ";
newbunny();
++it;
}
it = bunpointer.begin();
}
So if I create 5 bunnies at the beginning, and call function Troop::multiply, there should be 10 bunnies. An interesting observation is, the error will occur after 2 bunnies being born.
I think the problem may lie in the use of new to create new objects in a iterator loop. The new may somehow interrupt the iterator pointer *it. But I am not sure if this is the case, and if it really is, how to deal with this.
modified: so it is actually a problem of using push_back(), which will probably invalidate the iterator!!
Thank you in advance!!
1) Unless you have a reason to, your code does not need to use new at all. The code becomes easier, and no chance of memory leaks. Also, I don't see the need for an iterator member in the Troop class, unless you can justify the reason for it.
2) As to your immediate problem, just use a non-iterator reliant loop. In other words, a simple loop that goes from 0 to the number of current bunnies, less 1.
Here is an example:
#include <vector>
//...
class Troop {
private:
std::vector<Bunny> bunpointer;
public:
void newbunny();
void multiply();
};
void Troop::newbunny() {
bunpointer.push_back(Bunny());
}
void Troop::multiply() {
size_t siz = bunpoiner.size();
for (size_t i = 0; i < siz; ++i ) {
newbunny();
cout << (*it)->getname() << " gave a birth. ";
}
}
The newbunny() function simply creates a Bunny() using a default constructor and adds the item to the vector.
If you want to use a container that doesn't invalidate iterators when inserting items, then you can use a std::list as opposed to a std::vector.
It appears that you are trying to modify the std::vector while iterating over it. This is generally not a good idea, for a variety of reasons.
In particular, when you call newbunny() inside the iterator's loop, it is possible that the iterator you used to hold will be invalidated, because the vector may be resized during the push_back.
See this question for details.
As mentioned by others, the push_back() is your culprit, not the new.
One way to palliate would be this:
size_t const max(bunpointer.size());
for(size_t i(0); i < max; ++i)
{
cout << bunpointer[i]->getname() << " gave a birth. ";
newbunny();
}
This works because you are only adding new bunnies at the end of your existing vector. These new bunnies are not taken in account by the loop (max doesn't change because you call newbunny()...) and the [i] access makes use of the vector in its current state.
That loop would not work if you were deleting items...
As a side note: the name "bunpointer" is not very clear... it's not a pointer, it's a vector of pointers.
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>.
I have struct like this:
struct element{
char ulica[10];
vector<int> dane[3];
int wolne;
int w;
element *lewy, *prawy, *ojciec;
};
And I'm implementing kind of AVL tree. When key's are the same i need to put some int values to dane (dane[0], dane[1], dane[2] describe 3 different value) so I use
tmp2->dane[0].push_back(number)
EDIT. Here is code where I'm adding a values to this vector, it's half of the function because secod half is about rotations in AVL.
void wstaw_wezel(){
element *tmp2; //tmp2 bedzie ojcem nowo wstawionego elementu
tmp2=korzen;
while(tmp2!=NULL){
if(strcmp(tmp2->ulica, tmp->ulica)<0){
if(tmp2->prawy!=NULL){
tmp2=tmp2->prawy;
}
else{
tmp->ojciec=tmp2;
tmp2->prawy=tmp;
cout<<"Wstawiam pod prawy "<<tmp2->ulica<<endl;
if(tmp2->w!=0) tmp2->w=0;
else tmp2->w=-1;
break;
}
}
else if(strcmp(tmp2->ulica, tmp->ulica)>0){
if(tmp2->lewy!=NULL){
tmp2=tmp2->lewy;
}
else{
tmp->ojciec=tmp2;
tmp2->lewy=tmp;
if(tmp2->w!=0) tmp2->w=0;
else tmp2->w=1;
cout<<"Wstawiam pod lewy "<<tmp2->ulica<<endl;
break;
}
}
else{
cout<<"2 bloki na tej samej ulicy"<<endl;
for(int i=0; i<tmp2->dane[0].size(); i++) cout<<tmp2->ulica<<" "<<tmp2->dane[0][i]<<endl;
tmp2->numery.push_back(tmp->numery[0]);
tmp2->dane[0].push_back(tmp->dane[0][0]);
for(int i=0; i<tmp2->dane[0].size(); i++) cout<<tmp2->ulica<<" "<<tmp2->dane[0][i]<<endl;
tmp2->dane[1].push_back(tmp->dane[1][0]);
tmp2->dane[2].push_back(tmp->dane[2][0]);
tmp2->wolne+=tmp->dane[2][0];
break;
}
}
if(tmp->ojciec==NULL){
korzen=tmp;
return;
}
where tmp2 is a pointer to this struct (I checked adrres where it points and every time it's the same adrres).
Where is problem? If I add new value to vector it is until the loop where i do it ends. Finally instead having fe. 4 values in vector i have one, the last added value. Vector don't add new value to the end, just replacing it.
You declare the initial size of a std::vector in its constructor, so one way you can accomplish this is:
struct element
{
char ulica[10];
std::vector<int> dane;
int wolne;
int w;
element *lewy, *prawy, *ojciec;
element() : dane(3) {}
};
If you don't include the constructor, the initial size of the vector will be 0. In any event, to add an element to the back, just use tmp2->dane.push_back(number); This will add the value in number to the back of the vector tmp2->dane which may result in a change in the amount of allocated memory for the vector instance.
UPDATE: Based on the comment from the OP that he needs three vectors try this:
struct element
{
char ulica[10];
std::vector<std::vector<int> > dane;
int wolne;
int w;
element *lewy, *prawy, *ojciec;
element() : dane(3) {}
};
To add elements to the vectors, simply use tmp2->dane[i].push_back(number) where i is the index of the vector to use, and number is the new number to add to the ith vector, which is the same convention you seem to be using in your code segment above.
Update 2: Based on additional information below, I think a redesign of your data structure is called for. You're mixing the meaning of the various components and by more clearly delineating the functions of the data element and the AVL data structure management, you will be able to more clearly distinguish between the two. So try this instead. Have a data structure specifically for the "value" portion of your tree nodes, as in:
struct house
{
int house_number;
int unique_value0;
int unique_value1;
house(int hn, int uv0, int uv2)
: house_number(hn),
unique_value0(uv0),
unique_value1(uv1) {}
};
template <typename VALUE> struct node
{
std::string key;
std::vector<VALUE> values;
int left, right;
node<VALUE> *leftNode, *rightNode, *parentNode;
};
From here, you create a root node:
node<house> *root;
When you want to add a house to a street, node<house> *s, all you need to do is
s->values.push_back(house(a, b, c));
Of course a better alternative is to use what C++ already has for this. That is, there is a structure in the standard library called std::multimap which does pretty much what you're trying to do. In this case, you can simple declare
std::multimap<std::string, house> myMap;
This probably won't use AVL balancing. It more likely will be a Red-Black Tree, but it's all done for you.
How do you alloc the struct element?, it seems that the vector<int> dane[3]; has been initialized successful, but its inner vector does not been initialised.
try to add a ctor method to the struct element?
struct element
{
char ulica[10];
vector<int> dane[3];
int wolne;
int w;
element *lewy, *prawy, *ojciec;
element()
{
dane[0] = vector<int>();
dane[1] = vector<int>();
dane[2] = vector<int>();
}
};
I have a class like this:
classA
{
public:
classA()
{
//Here I am doing something but nothing related to vector
}
void updateVec(int idx, int value)
{
//Here, I want to update vector vector based on args passed
myVec.insert(myVec.begin() + idx, value);
}
std::vector<int> myVec;
}
Now, I am getting segmentation fault on insert statement. Do I need to initialize vector somewhere?
Segmentation fault means you're trying to access/write into memory that has not (yet) been allocated. In your case, depending on value of idx, myVec.begin() + idx can refer to memory that is out of vector's allocated zone. Before inserting, you need to make sure your vector can hold at least idx elements. updateVec should check the current size of the vector, and if it is not big enough, it should call vector::reserve to allocate enough room so new element can be inserted.
From your code it seems that you did not initialize it properly.
initialization for use as local var
Create a vector of ints, size 3, initialized to 0
std::vector<int> myvector (3,0);
Short example of how to initialize(and then resize) a vector in a class's constructor
#include <iostream>
#include <vector>
class A {
public:
A(int size);
~A();
void updateVec(int idx, int value);
void print();
private:
std::vector<int> myVec;
};
A::A(int size) {
myVec.resize(size);
}
A::~A() {
}
void A::updateVec(int idx, int value) {
myVec.insert(myVec.begin() + idx, value);
}
void A::print() {
std::vector<int>::iterator it;
for (it=myVec.begin(); it!=myVec.end(); it++) {
std::cout << " " << *it;
}
}
int main() {
A* a = new A(10);
a->updateVec(2,10);
a->print();
}
Here is documentation/example on how to use a vector in C++
http://www.cplusplus.com/reference/stl/vector/insert/
Yes, you do. Vectors start off empty. Any attempt to access an item past the end of the vector will result in an error.
To suggest a solution we'll need to know if the vector needs to change size dynamically - or if it is a fixed size, at what point in time will you know what size it needs to be.
Also, if you update the 17th elemnt of the vector, but at the time it only contains 10 items, do you want items 11 to 16 to be created as well?