Im trying to write a adjacency matrix representation using vectors of integer vectors , therefore vector> . However when I add members to the vector and later try and print those values nothing has changed. Most likely it has to do with "pass by value" however I have used "pass by reference" to the best of my knowledge.
Here is my header:
#ifndef GRAPH_MATRIX
#define GRAPH_MATRIX
#include <vector>
//header for graph represented via adjacency matrix with minimal functionality
class graph
{
public:
graph(int);
~graph();
void add_edge(int v1, int v2, int weight);
void print_graph();
private:
std::vector<std::vector<int>> vertex_matrix;
int num_of_vertices;
int num_of_edges;
};
#endif
the cpp implementation file:
#include <iostream>
#include "graph_matrix.h"
#include <climits>
using namespace std;
//header for graph represented via adjacency matrix with minimal functionality
graph::graph(int _num_of_vertices) : num_of_vertices(_num_of_vertices)
{
if (_num_of_vertices==0)
{
_num_of_vertices=10;
}
for (int i = 0; i < _num_of_vertices; i++)
{
vertex_matrix.push_back(vector<int> (_num_of_vertices,INT_MAX));
}
}
graph::~graph()
{
vertex_matrix.clear();
}
void graph::add_edge(int v1, int v2, int weight)
{
//vertex_matrix[v1-1][v2-1] == INT_MAX
vector<int> columnVector = vertex_matrix[v1-1];
if (columnVector[v2-1] == INT_MAX)
{
columnVector[v2-1] = weight;
}
}
void graph::print_graph()
{
for (int i=0; i< vertex_matrix.size(); i++)
{
for (int j = 0; j < vertex_matrix.size(); j++)
{
//vertex_matrix[i][j]
std::vector<int> columnVector = vertex_matrix[i];
if (columnVector[j] != INT_MAX)
{
std::cout << columnVector[j] ;
}
else
{
std::cout << "0";
}
}
std::cout << endl;
}//end for printing
}
the main entry:
#include <iostream>
#include "graph_matrix.h"
using namespace std;
int main ()
{
std::cout << " Matrix representation of graph" << std::endl;
graph _graph(4);
_graph.add_edge(1,2,1);
_graph.add_edge(2,3,1);
_graph.add_edge(3,1,1);
_graph.add_edge(3,3,1);
_graph.add_edge(3,4,1);
_graph.add_edge(4,0,0);
_graph.print_graph();
}
When I use the print function I currently getting 0's.
How can I make this proper pass by reference, and have the updated values print.
Thanks
As stated in the comments, you are creating a copy of your column and then modifying the copy. What you want to do is to make a reference to it.
vector<int>& columnVector = vertex_matrix[v1-1];
if (columnVector[v2-1] == INT_MAX)
{
columnVector[v2-1] = weight;
}
Or you can access the element directly.
if (vertex_matrix[v1-1][v2-1] == INT_MAX)
{
vertex_matrix[v1-1][v2-1] = weight;
}
In print_graph you are doing the same, but here you are not modifying anything so that works, but you are making an unnecessary copy for no reason which is not ideal.
A last point is that you are calling vertex_matrix.clear() in your destructor. This is redundant, when the vector goes out of scope it will clear itself up, so you don't need to manage that.
Related
I'm trying to create this function:
std::vector<int> graph::getNeighbors(int n){
int i = 0; for(int el : verteces[n]) i++;
if( i != 0){
auto iter = verteces[n].begin();
std::vector<int> res = std::vector<int>{i};
for(int j=0; j<i; j++)
res[j] = *(iter++);
return res;
}
return std::vector<int>{};
}
As the name itself explain, it is supposed to get the neighbors of a vertex. The graph is made like this:
class graph {
private:
std::vector<std::forward_list<int>> verteces;
unsigned long int n;
ยทยทยท
};
Now, the problem is that whenever i is greater than 0, the program crashes badly with the error:
malloc(): corrupted top size
I don't understand what I am doing wrong.
EDIT
In order to make a reproducible example I am going to show all the three files.
main.cpp:
#include <iostream>
#include <set>
#include "graph/graph.h"
void greedyAlgorithm(graph &G){
std::vector<int> colors{static_cast<int>(G.getSize())};
for(int i=0; i<G.getSize(); i++)
colors[i] = -1;
for(int i=0; i<G.getSize(); i++){ // for each vertex
std::set<int> colorNeigh{};
for(auto &j : G.getNeighbors(i)){
if(colors[j] != -1)
colorNeigh.insert( colors[j] );
}
int col = 0;
for(auto &el : colorNeigh){
if(el == col) col++;
else break;
}
colors[i] = col;
}
}
int main() {
{
std::vector<int> r;
for(int i=0; i<100; i++)
r.push_back(i);
}
graph a = graph(10);
a.addEdge(2, 5);
a.addEdge(2, 5);
a.addEdge(1,2);
a.addEdge(2,3);
a.addEdge(3,4);
greedyAlgorithm(a);
return 0;
}
graph.h:
//
// Created by salvo on 11/08/21.
//
#ifndef P2_GRAPH_H
#define P2_GRAPH_H
#include <forward_list>
#include <vector>
#include <stdexcept>
class node;
// list implementation
class graph {
private:
std::vector<std::forward_list<int>> verteces;
unsigned long int n;
public:
graph();
graph(unsigned long int n); // vertex number
void addEdge(int a, int b);
std::vector<int> getNeighbors(int n);
unsigned long getSize(){return n;};
};
#endif //P2_GRAPH_H
graph.cpp:
//
// Created by salvo on 11/08/21.
//
#include <iostream>
#include <openssl/ossl_typ.h>
#include "graph.h"
graph::graph() {
// verteces call default constructor
n = 0;
}
graph::graph(unsigned long int n) {
verteces = std::vector<std::forward_list<int>>{n};
for(auto &el : verteces) el = std::forward_list<int>{};
this->n = n;
}
void graph::addEdge(int a, int b) {
if(a == b){
std::cout << " No self loop!\nexiting ";
exit(-2);
}
int m = a > b ? a : b + 1;
if(m > n){
std::cout << "The graph only contains " << n << " verteces.\n exiting.";
exit(-1);
}
// Check if the edge exist already
for(auto &el : verteces[a]){
if(el == b) return;
}
verteces[a].emplace_front(b);
verteces[b].emplace_front(a);
std::cout << verteces.size() << std::endl;
}
std::vector<int> graph::getNeighbors(int n){
std::vector<int> res{};
for(auto el : verteces[n])
res.push_back(el);
return res;
}
Output if executed:
malloc(): corrupted top size
Process finished with exit code 134 (interrupted by signal 6: SIGABRT)
I am using C++14.
Without even looking at the code, I added -D_GLIBCXX_DEBUG1 to compiler flags (to enable container bounds checks) and got this:
Error: attempt to subscript container with out-of-bounds index 1, but
container only holds 1 elements.
Then I used GDB to understand where exactly that happens:
void greedyAlgorithm(graph &G){
std::vector<int> colors{static_cast<int>(G.getSize())};
for(int i=0; i<G.getSize(); i++)
colors[i] = -1; <-- HERE
This means that the syntax you used created a vector with a single element (with value G.getSize()).
This is why you should never EVER use direct-list-initialization (i.e. with curly braces, without =) with containers. If the vector had some other element type (not a number), this would've worked, and this is exactly why you shouldn't do it.
The fix is to use parentheses:
std::vector<int> colors(static_cast<int>(G.getSize()));
1 This is libstdc++-specific flag (it only works with the GCC's standard library). Other standard library implementations have similar checks. There are also address sanitizers that could also work here.
std::vector<int> colors{static_cast<int>(G.getSize())}
Constructs a vector with one element equal to static_cast<int>(G.getSize()). You want std::vector colors(here_the_size) not with { }. std::vector colors(G.getSize()); will construct a vector with G.getSize() elements.
Because subsequent colors[i] = -1; overwrites memory without any checks, you get errors.
Use .at() instead of []. Using colors.at(i) = -1; will allow you to detect errors early on.
I have a class "beaker" that represents a beaker with n-dices that have n-faces. It has a method "roll" which returns a vector with n-elements where each element represents a dice. Then I have another class "board" that for now, it only prints the values generated by beaker.roll using cout;
So I call the beaker.roll function to pass the result to print them, but it does nothing. I have no compile errors/IntelliSense warnings. What am I doing wrong?
#include <iostream>
#include <random>
#include <chrono>
#include <thread>
#include <vector>
using std::cout;
using std::vector;
class beaker {
public:
int diceCount, diceFaces;
beaker() {
diceCount = 2;
diceFaces = 6;
};
beaker(int count, int faces) {
diceCount = count;
diceFaces = faces;
};
//Dice values
vector<uint8_t> dice;
//METHODS
//RETURN DICE i VALUE
int diceValue(int d) {
return dice.at(d-1);
}
//ROLL DICE + RETURN RESULT
vector<uint8_t> roll() {
std::mt19937 mt(std::chrono::high_resolution_clock::now().time_since_epoch().count());
std::uniform_int_distribution<int> dist(1, diceFaces);
for (int i=0; i<diceCount; i++) {
dice.push_back(dist(mt));
}
return dice;
}
//RETURN LAST DICE NUMBERS
vector<uint8_t> result() {
return dice;
}
};
class board {
public:
void Print(vector<uint8_t> dice) {
for (int i=0; i<dice.size(); i++) {
cout << dice.at(i);
}
}
};
int main() {
beaker beaker;
board board;
board.Print(beaker.roll());
}
The problem is that the values in dice are of type uint8_t, which the cout::<< operator is interpreting as unsigned char, so it is printing out the values as ASCII characters. However, the values are between 1 and 6, and ASCII characters less than 32 are mostly non-printing characters, so they aren't visible in the output.
To convince the cout::<< operator to print the values as integers instead, update the code to this:
void Print(vector<uint8_t> dice) {
for (int i=0; i<dice.size(); i++) {
cout << static_cast<int>(dice.at(i));
}
cout << std::endl; // just to make sure the buffer gets flushed ASAP
}
Im trying to create a adjacency representation of a graph.
I wrote a small program using vectors of vectors , however I keep getting "segmentation fault" but the compiler(clang++ version 5.0.1 on Windows) it seems wereever I try to access the vector vertex_matrix its giving a segmentation fault, why is it not being instantiated?
Here is the header:
#ifndef GRAPH_MATRIX
#define GRAPH_MATRIX
#include <vector>
//header for graph represented via adjacency matrix with minimal functionality
class graph
{
public:
graph(int);
~graph();
void add_edge(int v1, int v2, int weight);
void print_graph();
private:
std::vector<std::vector<int>> vertex_matrix;
int num_of_vertices;
int num_of_edges;
};
#endif
Here is the cpp implementation:
#include <iostream>
#include "graph_matrix.h"
#include <climits>
using namespace std;
//header for graph represented via adjacency matrix with minimal functionality
graph::graph(int _num_of_vertices) : num_of_vertices(_num_of_vertices)
{
if (_num_of_vertices==0)
{
_num_of_vertices=10;
}
for (int i = 0; i < _num_of_vertices; i++)
{
vertex_matrix[i]=(vector<int> (_num_of_vertices,INT_MAX));
}
}
graph::~graph()
{
vertex_matrix.clear();
}
void graph::add_edge(int v1, int v2, int weight)
{
//vertex_matrix[v1-1][v2-1] == INT_MAX
vector<int> columnVector = vertex_matrix[v1-1];
if (columnVector[v2-1] == INT_MAX)
{
columnVector[v2-1] = weight;
}
}
void graph::print_graph()
{
cout << "vertex_matrix size:" << vertex_matrix.size() << endl;
for (int i=0; i< num_of_vertices; i++)
{
for (int j = 0; j < num_of_vertices; j++)
{
//vertex_matrix[i][j]
std::vector<int> columnVector = vertex_matrix[i];
if (columnVector[j] != INT_MAX)
{
std::cout << columnVector[j] ;
}
else
{
std::cout << "0";
}
}
std::cout << endl;
}//end for printing
}
Here is the main entry:
#include <iostream>
#include "graph_matrix.h"
using namespace std;
int main ()
{
std::cout << " Matrix representation of graph" << std::endl;
graph _graph(4);
_graph.add_edge(1,2,1);
_graph.add_edge(2,3,1);
_graph.add_edge(3,1,1);
_graph.add_edge(3,3,1);
_graph.add_edge(3,4,1);
_graph.add_edge(4,0,0);
_graph.print_graph();
}
I edited the above code to use pass by reference, however the matrix still prints as 0's.
Please help with pass by reference, updates below:
Header:
#ifndef GRAPH_MATRIX
#define GRAPH_MATRIX
#include <vector>
//header for graph represented via adjacency matrix with minimal functionality
class graph
{
public:
graph(int);
~graph();
void add_edge(int v1, int v2, int weight,std::vector<std::vector<int>> & matrix);
void print_graph();
std::vector<std::vector<int>> vertex_matrix;
private:
int num_of_vertices;
int num_of_edges;
};
#endif
Cpp file:
#include <iostream>
#include "graph_matrix.h"
#include <climits>
using namespace std;
//header for graph represented via adjacency matrix with minimal functionality
graph::graph(int _num_of_vertices) : num_of_vertices(_num_of_vertices) {
if (num_of_vertices == 0) {
num_of_vertices = 10;
}
for (int i = 0; i < num_of_vertices; i++) {
std::vector<std::vector<int>>& matrix = vertex_matrix;
matrix.push_back(vector<int> (num_of_vertices, INT_MAX));
}
}
graph::~graph() {
std::vector<std::vector<int>>& matrix = vertex_matrix;
matrix.clear();
}
void graph::add_edge(int v1, int v2, int weight,std::vector<std::vector<int>> & _matrix) {
//vertex_matrix[v1-1][v2-1] == INT_MAX
vector<int> columnVector = _matrix[v1 - 1];
if (columnVector[v2 - 1] == INT_MAX) {
columnVector[v2 - 1] = weight;
}
}
void graph::print_graph() {
std::vector<std::vector<int>>& matrix = vertex_matrix;
for (int i = 0; i < matrix.size(); i++) {
for (int j = 0; j < matrix.size(); j++) {
//vertex_matrix[i][j]
std::vector<int> columnVector = matrix[i];
if (columnVector[j] != INT_MAX) {
std::cout << columnVector[j];
} else {
std::cout << "0";
}
}
std::cout << endl;
}//end for printing
}
main:
#include <iostream>
#include "graph_matrix.h"
using namespace std;
int main ()
{
std::cout << " Matrix representation of graph" << std::endl;
graph _graph(4);
std::vector<std::vector<int>>& m = _graph.vertex_matrix;
_graph.add_edge(1,2,1,m);
_graph.add_edge(2,3,1,m);
_graph.add_edge(3,1,1,m);
_graph.add_edge(3,3,1,m);
_graph.add_edge(3,4,1,m);
_graph.add_edge(4,0,0,m);
_graph.print_graph();
}
Any help will be appreciated.
Thanks
You create an empty vector and then try to access elements in it. Change your constructor to
graph::graph(size_t _num_of_vertices) :
vertex_matrix(
std::vector<std::vector<int>>(
_num_of_vertices,std::vector<int>(_num_of_vertices)
)
)
{}
to create a correctly sized vector.
Also in case _num_vertices == 0 you set it to 10 but thats after you initialized the member num_vertices so you leave the object in an inconsistent state. There are different ways to fix that, I would probably just throw an exception when the number of vertices passed is zero, or just ignore it. User wants a zero sized matrix? Why not?
Moreover the size should be unsigned not signed, there is size_t for container sizes. Even better you shouldnt have that member at all, because a vector already knows its size, the only reason to repeat that information is to introduce mistakes ;)
I want to be able to compare the "overall" values of a person with another person. I'm unsure if I'm storing them correctly and I don't know how to compare them correctly. I don't know how to access the "overall" values of any single person, which is what I think is bugging me the most.
Header file
#ifndef Population_h
#define Population_h
class population
{
friend class person;
private:
int size;
int generation;
public:
void setsize(int x);
void tournament_selection(population x, int z);
};
class person
{
friend class population;
private:
float fit1;
float fit2;
float overall;
public:
void generatefit();
void setfit();
void langerman();
void printinfo();
};
#endif
Population.cpp
#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <random>
#include <string>
#include <CMATH>
#include <vector>
#include "Population.h"
using namespace std;
void person ::generatefit()
{
float randomnumb1;
float randomnumb2;
//float((rand() % 10)*0.1);
randomnumb1 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
randomnumb2 = static_cast <float> (rand()) / static_cast <float> (RAND_MAX);
fit1 = randomnumb1;
fit2 = randomnumb2;
}
void person::setfit()
{
float x = fit1;
float y = fit2;
}
void person::langerman()
{
overall = 3 * pow(fit1, 2) + 2 * fit2 + 0.0252;
for (overall; overall > 1; overall--);
}
void person::printinfo()
{
cout << overall << " " << endl;
}
void population::setsize(int x)
{
size = x;
}
void population::tournament_selection(population x, int total)
{
float best = 0;
for (int i = 0; i <= total; i++)
{
}
}
main.cpp
#include "Population.h"
#include <iostream>
#include <string>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <chrono>
#include <random>
#include <vector>
#include <stdlib.h>
using namespace std;
int main()
{
cout << "Program is starting " << endl;
srand(static_cast <unsigned> (time(0)));
population pop;
vector<person> popvector;
vector<person> survivor;
person *p1;
int popsize = 500;
pop.setsize(popsize);
for (int i = 0; i <= popsize; i++)
{
p1 = new person;
p1 ->generatefit();
p1->setfit();
p1->langerman();
popvector.push_back(*p1);
delete p1;
}
cout << "The fit values of the person are listed here: " << endl;
vector<person> ::iterator it; //iterator to print everything in the vector
for (it = popvector.begin(); it != popvector.end(); ++it)
{
it->printinfo();
}
unsigned seed = std::chrono::system_clock::now().time_since_epoch().count(); // generate a seed for the shuffle process of the vector.
cout << "Beggining selection process" << endl;
shuffle(popvector.begin(), popvector.end(), std::default_random_engine(seed));
//want to pick consecutive parents
int j = 0;
}
I want to be able to compare people, store the "winners" into the "survivors" vector and then proceed to use the "survivor" vector to create a new population with the use of crossover and mutation for X generations.
You could use operator overloading to set a customized "Rule" of comparing the fitness level of two human beings. std::string is a perfect example": equal operations can be carried out directly by if(str1 == str2) instead of if(!strcmp(str1, str2)), demonstrating the virtue of operator overloading technique.
The following code should suit your needs:
class person {
friend class population;
private:
float fit1;
float fit2;
float overall;
public:
void generatefit();
void setfit();
void langerman();
void printinfo();
//Overloading '<' operator
bool operator(const person&);
};
//The following function defines
//rule of fitness in the jungle
bool person::operator < (const person& p2){
//This is just an example, you can define your own rules
return overall < p2.overall;
}
Once the comparing rule has been established, you can sort your population by that very rule:
//The "less fit" rule is defined so the population will be sorted
//in ascending order, if you want to sort them by descending order,
//just change the definition of your fitness rules accordingly.
sort(popvector, popvector + popsize);
Or you can use an ordered container to store population in the first place. Such choice can be set, map or priority_queue. The elements in ordered container will always follow the exact order you designated when you declared such container objects.
In your case I would suggest priority_queue because you can easily pop out the most unfitful human being from the top of the pile, like this:
#include<priority_queue>
//Still, the definition of "priority" is required beforehand
priority_queue<person> pqPerson;
person tmp;
for(int i = 0; i < popsize; ++i){
tmp.setfit(fit1, fit2, overall);
pqPerson.push(tmp);
}
for(int generation = 0; generation < X; +=generation){
//The weakest group will perish
for(int j = 0; j < tollSize; ++j){
pqPerson.pop();
}
//Crossover and Mutation process
}
i am working on a worksheet i have for university and the question asks me to "Allow a user to enter 10 numbers from the keyboard into an array" however we have been told that we need to use classes and vectors for this task. When i run my code i get an error stating: "Expression: Vector subscript out of range"
can anyone help?
Array.h
#include <iostream>
#include <vector>
using namespace std;
class Array
{
private:
vector<int> lists;
public:
void fillArray();
void printForwards();
void halfandHalf();
void shiftArrayRight();
Array();
Array(vector<int>);
};
Array.cpp
#include "Array.h"
Array::Array()
{
lists[10];
}
Array::Array(vector<int> lists)
{
this->lists = lists;
}
void Array::fillArray()
{
for (int i = 0; i < 10; i++)
{
cin >> lists[i];
}
}
void Array::printForwards()
{
for (int i = 0; i < 10; i++)
{
cout << lists[i];
}
}
Source.cpp
#include <iostream>
#include "Array.h"
using namespace std;
int main()
{
Array list1,list2;
//fill array 1
list1.fillArray();
//fill array 2
list2.fillArray();
// print array 1
list1.printForwards();
//print array 2
list2.printForwards();
system("pause");
return 0;
}
Thanks in advance
lists[10]; is not going to create a vector of size 10. It is going to try and access the 11th element of an empty vector. If you wanted to create a vector of size 10 then you can use
Array::Array() : lists(std::vector<int>(10, 0)) {}
I would also suggest you change
Array::Array(vector<int> lists)
{
this->lists = lists;
}
To
Array::Array(vector<int> lists) lists(lists) {}
You should also change your for loops to use the vector size() instead of a hard coded value
void Array::fillArray()
{
for (int i = 0; i < lists.size(); i++) // uses size()
{
cin >> lists[i];
}
}
void Array::printForwards()
{
for (int i = 0; i < lists.size(); i++) // uses size()
{
cout << lists[i];
}
}
Or if you have C++11 or higher you can use a ranged based for loop like
void Array::fillArray()
{
for (auto& e : lists)
{
cin >> e;
}
}
void Array::printForwards()
{
for (const auto& e : lists)
{
cout << e;
}
}