I'm currently making a simulation of an autonomous car for my AI class. The car's constructor receives the board as a parameter so it can set the position of the car and add the first node to the search tree, so it can search an optimum path from the Starting Position to the Finishing Position. The thing is, the board generates without any problem, but when I try to pass it to the car's constructor, it results in a Segmentation fault (core dumped) error.
I used a debugger (gdb), ran the code in it and made a back-trace; and the problem came from here:
void node_c::add_child(node_c* chld)
{ int i;
for (i = 0; i < MAX_CHILDREN; i++)
{ if (children_[i] == NULL) //This line's the problem
break;
}
if (children_[i] != NULL)
{ cout << endl << "You can't add any more children." << endl;
return;
}
else children_[i] = chld;
}
Note: 'children_' contains a maximum of 4 children of a search_tree's node, and is a custom vector_c class I had to make.
This is the operator that fails and the function it calls:
template <typename TDato>
TDato& vector_c<TDato>::operator [](int position) { return get_data(position); }
template <typename TDato>
TDato& vector_c<TDato>::get_data(int a) const { return data_[a]; }
I thought that it might be a type error in the comparison if (children_[i] == NULL) so I made a custom operator that returned an object (TDato), not a reference to an object (TDato&), but it didn't work.
I can't imagine what could be causing this and/or how to solve it.
Thanks in advance.
Edit 1: Here's a google drive link to the project as even a minimal reproducible example would be too large to be easy to read in a Stack Overflow question. It's not very big, I promise (less than 1 MB).
Edit 2: Here's the most I could do to make the reproducible example minimal, as the question got closed for not including it.
main.cpp
#include "../include/board_s.hpp"
#include "../include/car_c.hpp"
using namespace std;
int main(void)
{ board_s<int> board(20, 20);
board.file_depiction();
car_c car(board);
board.write(cout);
return 0;
}
Here, the problem comes when the constructor of car_c is called. It should create an car_c object.
board_c.hpp
#ifndef __BOARD_S__
#define __BOARD_S__
#include <cstdio>
#include <iostream>
#include <cstring>
#include <random>
#include <fstream>
#include <utility>
#include "matrix_c.hpp"
#include "tree_c.hpp"
using namespace std;
template <typename TDato = int>
class board_s: public matrix_c<TDato>
{ private:
pair<int, int> starting_pos;
pair<int, int> finishing_pos;
public:
board_s(int, int);
~board_s(void);
pair<int, int> get_start(void);
void file_depiction(void); //Generates obstacles and starting/finishing points as depicted in board_depiction.txt.
virtual ostream& write(ostream&);
int distance(pair<int, int>&) const; //Returns the distance from a given position to the finishing point
private:
bool object_setter(string, int&, int&);
int object_identifier(string&) const; //Given the name of the object ("NEW OBSTACLE" [1], "STARTING POSITION" [2] or "FINISHING POSITION" [3]) returns it's code
};
template class board_s<int>;
#endif
board_c.cpp
#include "../include/board_s.hpp"
#include "matrix_c.cpp"
using namespace std;
//The constructor fills the board with empty boxes.
template <typename TDato>
board_s<TDato>::board_s(int m, int n):
matrix_c<TDato>::matrix_c(m + 2, n + 2)
{ for(int i = 1; i < m; i++)
for(int j = 1; j < n; j++)
matrix_c<TDato>::at(i, j) = 0;
for(int i = 0; i < n + 2; i++)
{ matrix_c<TDato>::at(0, i) = 1;
matrix_c<TDato>::at(m + 1, i) = 1;
}
for(int i = 0; i < m + 2; i++)
{ matrix_c<TDato>::at(i, 0) = 1;
matrix_c<TDato>::at(i, n + 1) = 1;
}
starting_pos.first = 0;
starting_pos.second = 0;
finishing_pos.first = 0;
finishing_pos.second = 0;
}
template <typename TDato>
board_s<TDato>::~board_s(void){}
template <typename TDato>
pair<int, int> board_s<TDato>::get_start(void) { return starting_pos; }
template <typename TDato>
void board_s<TDato>::file_depiction(void)
{ string line;
int x, y, i;
std::ifstream bd;
bd.open("board_depiction.txt");
if (bd.is_open())
{ getline(bd, line);
getline(bd, line);
i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
matrix_c<TDato>::resize(x + 2, y + 2);
getline(bd, line);
getline(bd, line);
i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
object_setter("STARTING POSITION", x, y);
getline(bd, line);
getline(bd, line);
i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
object_setter("FINISHING POSITION", x, y);
while (getline(bd, line))
if (line[0] != 'O')
{ i = line.size() - 1;
y = matrix_c<TDato>::strtoi(line, i);
i--;
x = matrix_c<TDato>::strtoi(line, i);
object_setter("NEW OBSTACLE", x, y);
}
}
else cout << "ERROR";
}
template <typename TDato>
ostream& board_s<TDato>::write(ostream& os)
{ int temp = matrix_c<TDato>::get_n() - 2 + (4 * (matrix_c<TDato>::get_n() - 2));
os << " ";
for (int i = 1; i < temp; i++)
os << "_";
os << " " << endl << "|";
for (int i = 1; i < matrix_c<TDato>::get_m() - 1; i++)
{ for (int j = 0; j < 2; j++)
{ for (int k = 1; k < matrix_c<TDato>::get_n() - 1; k++)
switch (matrix_c<TDato>::at(i, k))
{ case 1:
os << "████|";
break;
case 2:
if (j == 0)
os << " CC |";
else os << "_CC_|";
break;
case 3:
if (j == 0)
os << " FF |";
else os << "_FF_|";
break;
default:
if (j == 0)
os << " |";
else os << "____|";
}
os << endl;
if (j == 0) os << "|";
}
if (i < matrix_c<TDato>::get_m() - 2) os << "|";
}
os << endl;
return os;
}
template <typename TDato>
int board_s<TDato>::distance(pair<int, int>& pos) const
{ int d = (finishing_pos.first - pos.first) + (finishing_pos.second - pos.second);
if (d < 0) return (d * (-1));
else return d;
}
template <typename TDato>
bool board_s<TDato>::object_setter(string name, int &x, int &y)
{ if((x > 0) && (x < matrix_c<TDato>::get_m() - 1) && (y > 0) && (y < matrix_c<TDato>::get_n() - 1) && (matrix_c<TDato>::at(x, y) == 0))
{ matrix_c<TDato>::at(x, y) = object_identifier(name);
cout << endl << endl << "The " << name << " has been set in (" << x << ", " << y << ")" << endl;
if (name == "STARTING POSITION")
{ starting_pos.first = x;
starting_pos.second = y;
}
else if (name == "FINISHING POSITION")
{ finishing_pos.first = x;
finishing_pos.second = y;
}
return true;
}
else
{ cout << endl << "The coordinates that you intriduced were out of reach or the position wasn't free." << endl;
return false;
}
}
template <typename TDato>
int board_s<TDato>::object_identifier(string &name) const
{ if (name == "NEW OBSTACLE")
return 1;
else if (name == "STARTING POSITION")
return 2;
else if (name == "FINISHING POSITION")
return 3;
else return 0;
}
matrix_c.hpp
#ifndef __MATRIX_C__
#define __MATRIX_C__
#include <cstdio>
#include <iostream>
#include <iomanip>
#include <cstring>
#include "vector_c.hpp"
using namespace std;
template <typename TDato>
class matrix_c //Template matrix class implemented with a vector.
{ private:
int m_;
int n_;
vector_c<TDato> v_;
public:
matrix_c(void); //Empty constructor
matrix_c(int, int); //Constructor with dimensions
~matrix_c(void);
void resize(int, int);
TDato& at (int, int); //Redirects to position (x, y)
virtual TDato& operator()(int, int); //Operator for at(int, int)
int get_m(void) const;
int get_n(void) const;
private:
int pos(int, int);
protected:
int ctoi(char&) const;
int strtoi(string&, int&) const;
};
#endif
matrix_c.cpp
#include "../include/matrix_c.hpp"
using namespace std;
template <typename TDato>
matrix_c<TDato>::matrix_c(void):
m_(0),
n_(0),
v_() {}
template <typename TDato>
matrix_c<TDato>::matrix_c(int m, int n):
m_(m),
n_(n),
v_(m * n) {}
template <typename TDato>
matrix_c<TDato>::~matrix_c(void) {}
template <typename TDato>
void matrix_c<TDato>::resize(int m, int n)
{ v_.resize(m * n);
m_ = m;
n_ = n;
}
template <typename TDato>
TDato& matrix_c<TDato>::at(int i, int j) { return v_[(pos(i,j))]; }
template <typename TDato>
TDato& matrix_c<TDato>::operator()(int i, int j) { return at(i,j); }
template <typename TDato>
int matrix_c<TDato>::get_m(void) const { return m_; }
template <typename TDato>
int matrix_c<TDato>::get_n(void) const { return n_; }
template <typename TDato>
int matrix_c<TDato>::pos(int i, int j) { return ((n_ * i) + j); }
template <typename TDato>
int matrix_c<TDato>::ctoi(char &c) const
{ int n = c;
return n - 48;
}
template <typename TDato>
int matrix_c<TDato>::strtoi(string &s, int& i) const
{ int n = 0;
int mult = 1;
while ((s[i] != ' ') && (i >= 0))
{ n += ctoi(s[i]) * mult;
mult *= 10;
i--;
}
return n;
}
template class matrix_c<int>;
vector_c.hpp
#ifndef __VECTOR_C__
#define __VECTOR_C__
#include <iostream>
#include <cstdio>
#include <cassert>
using namespace std;
template <typename TDato>
class vector_c
{ private:
int sz_;
TDato* data_;
public:
vector_c(void); //Empty constructor
vector_c(int); //Constructor with size
~vector_c(void);
TDato& get_data(int) const;
void set_data(TDato&, int);
ostream& write(ostream&) const;
TDato& operator [](int);
void resize(int);
private:
void new_vector(void);
void del_vector(void);
};
#endif
vector_c.cpp
#include "../include/vector_c.hpp"
#include "../include/node_c.hpp"
using namespace std;
template <typename TDato>
vector_c<TDato>::vector_c(void):
sz_(0),
data_(NULL) {}
template <typename TDato>
vector_c<TDato>::vector_c(int size):
sz_(size),
data_(new TDato[sz_]) {}
template <typename TDato>
vector_c<TDato>::~vector_c(void)
{ delete[] data_;
data_ = NULL;
}
template <typename TDato>
TDato& vector_c<TDato>::get_data(int a) const { return data_[a]; }
template <typename TDato>
void vector_c<TDato>::set_data(TDato& dat, int a) { data_[a] = dat;}
template <typename TDato>
TDato& vector_c<TDato>::operator [](int position) { return get_data(position); }
template <typename TDato>
void vector_c<TDato>::resize(int sz)
{ del_vector();
sz_ = sz;
new_vector();
}
template <typename TDato>
void vector_c<TDato>::new_vector(void){
data_ = new TDato[sz_];
}
template <typename TDato>
void vector_c<TDato>::del_vector(void)
{ if (data_ != NULL){
delete [] data_;
data_ = NULL;
}
}
template class vector_c<int>;
template class vector_c<node_c*>;
node_c.hpp
#define MAX_CHILDREN 4
#ifndef __NODE_C__
#define __NODE_C__
#include <iostream>
#include <cstdio>
#include <cassert>
#include "vector_c.hpp"
using namespace std;
class node_c
{ private:
node_c* parent_;
vector_c< node_c* > children_;
pair<pair<int, int>, int> data_;
public:
node_c(void);
node_c(int &x, int &y, int &cost);
node_c(pair<pair<int, int>, int>&);
~node_c(void);
void add_child(node_c*);
};
#endif
node_c.cpp
#include "../include/node_c.hpp"
using namespace std;
node_c::node_c(void):
parent_(NULL)
{ for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
data_.first.first = 0;
data_.first.second = 0;
data_.second = 0;
}
node_c::node_c(int &x, int &y, int &cost):
parent_(NULL)
{ for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
data_.first.first = x;
data_.first.second = y;
data_.second = cost;
}
node_c::node_c(pair<pair<int, int>, int> &dat):
parent_(NULL),
data_(dat)
{ for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
}
node_c::~node_c(void)
{ parent_ = NULL;
for (int i = 0; i < MAX_CHILDREN; i++)
children_[i] = NULL;
data_.first.first = 0;
data_.first.second = 0;
data_.second = 0;
}
void node_c::add_child(node_c* chld)
{ int i;
for (i = 0; i < MAX_CHILDREN; i++)
{ if (children_[i] == NULL)
break;
}
if (children_[i] != NULL)
{ cout << endl << "You can't add any more children." << endl;
return;
}
else children_[i] = chld;
}
tree_c.hpp
#ifndef __TREE_C__
#define __TREE_C__
#include "node_c.hpp"
using namespace std;
class tree_c
{ private:
node_c* root_;
int depth_;
public:
tree_c(void);
tree_c(node_c*);
node_c* add_node(node_c*, int&, int&, int);
};
#endif
tree_c.cpp
#include "../include/tree_c.hpp"
using namespace std;
tree_c::tree_c(void):
root_(NULL),
depth_(0) {}
tree_c::tree_c(node_c* root):
root_(root),
depth_(1) {}
node_c* tree_c::add_node(node_c* parent, int& x, int& y, int cost)
{ node_c* node = new node_c(x, y, cost);
parent->add_child(node);
}
car_c.hpp
#ifndef __CAR_C__
#define __CAR_C__
#include <iostream>
#include <cstdio>
#include <cassert>
#include "tree_c.hpp"
#include "board_s.hpp"
using namespace std;
class car_c
{ private:
tree_c tree_;
pair<int, int> pos_;
matrix_c<int> visited_;
public:
car_c(void);
car_c(board_s<int>&);
~car_c(void);
};
#endif
car_c.cpp
#include "../include/car_c.hpp"
using namespace std;
car_c::car_c(void):
tree_(NULL)
{ pos_.first = 0;
pos_.second = 0;
}
car_c::car_c(board_s<int>& board):
pos_(board.get_start()),
tree_(tree_.add_node(NULL, pos_.first, pos_.second, 0))
{ visited_(pos_.first, pos_.second) = 1; }
car_c::~car_c(void) {}
Debugging information:
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401cc2 in node_c::node_c (this=0x6187d0, x=#0x7ffffffeddf0: 8, y=#0x7ffffffeddf4: 0,
cost=#0x7ffffffedd2c: 0) at src/node_c.cpp:20
20 children_[i] = NULL;
(gdb) bt
#0 0x0000000000401cc2 in node_c::node_c (this=0x6187d0, x=#0x7ffffffeddf0: 8, y=#0x7ffffffeddf4: 0,
cost=#0x7ffffffedd2c: 0) at src/node_c.cpp:20
#1 0x0000000000402007 in tree_c::add_node (this=0x7ffffffedde0, parent=0x0, x=#0x7ffffffeddf0: 8,
y=#0x7ffffffeddf4: 0, cost=0) at src/tree_c.cpp:16
#2 0x0000000000402df6 in car_c::car_c (this=0x7ffffffedde0, board=...) at src/car_c.cpp:15
#3 0x0000000000401403 in main () at src/main.cpp:11
Sorry for the length of my question, but this is the minimal reproducible example I was able to make. If you know another way to recreate my error, let me know so I can improve this.
Yesterday my friend challenged me to write a function in C which would return an array of function pointers where i-th function would return i.
It is easy to get a similar effect in C++, but I am not sure how to do it in C.
Can anyone help me with that?
Edit.
The effect that I am looking for is something equivalent to this.
vector <function<int()>> get_functions(int n) {
vector <function<int()>> functions;
for (int i = 0; i < n; ++i) {
functions.emplace_back([i]() {
return i;
});
}
return functions;
}
int main() {
auto functions = get_functions(10);
for (auto f:functions) {
cout << f() << endl;
}
return 0;
}
Edit.
As asked in the comment section I provide my poor attempt on the challenge.
typedef int (*fun_t)(void);
int fun() { return 0; }
int fun1() { return 1; }
fun_t *get_functions() {
fun_t *functions = malloc(sizeof(fun_t) * 2);
functions[0] = fun;
functions[1] = fun1;
return functions;
}
int main() {
fun_t* funs=get_functions();
for (int i = 0; i < 2; ++i) {
printf("%d\n",funs[i]());
}
free(funs);
}
The C++ code is cheating. function<int()> is not a function pointer; in fact, it's not a pointer at all, it's a class.
Therefore the equivalent C code would look something like this:
#include <stdio.h>
#include <stdlib.h>
// function<int ()>, simplified version just for this task
typedef struct {
int (*code)(int);
int ctx;
} function_int_t;
// function<int()>::operator()()
int call(function_int_t fun) {
return fun.code(fun.ctx);
}
// lambda body
int proto(int ctx) {
return ctx;
}
function_int_t *get_functions(size_t n) {
function_int_t *functions = calloc(n, sizeof *functions);
if (!functions) {
abort(); // hey, that's how C++ does it
}
for (size_t i = 0; i < n; i++) {
functions[i] = (function_int_t){ proto, i }; // capture i
}
return functions;
}
int main(void) {
size_t n = 10;
function_int_t *functions = get_functions(n);
for (size_t i = 0; i < n; i++) {
printf("%d\n", call(functions[i]));
}
free(functions);
return 0;
}
I am working on a sample test in the site: https://www.testdome.com/for-developers/solve-question/9808
I added two destructors for base class and derived class respectively to release the memory allocated by constructors. The first two requirements of this question are solve successfully, but the result give a fail as: Using timed multiple choice test as multiple choice test: Memory limit exceeded
My modified code as given below, I will appreciate if you can help to fix the fail...
#include <iostream>
#include <string>
class MultipleChoiceTest
{
public:
MultipleChoiceTest(int questionsCount)
{
this->questionsCount = questionsCount;
answers = new int[questionsCount];
for (int i = 0; i < questionsCount; i++)
{
answers[i] = -1;
}
}
void setAnswer(int questionIndex, int answer)
{
answers[questionIndex] = answer;
}
int getAnswer(int questionIndex) const
{
return answers[questionIndex];
}
~MultipleChoiceTest()
{
delete answers; // release memory
}
protected:
int questionsCount;
private:
int* answers;
};
class TimedMultipleChoiceTest : public MultipleChoiceTest
{
public:
TimedMultipleChoiceTest(int questionsCount)
: MultipleChoiceTest(questionsCount)
{
times = new int[questionsCount];
for (int i = 0; i < questionsCount; i++)
{
times[i] = 0;
}
}
void setTime(int questionIndex, int time)
{
times[questionIndex] = time;
}
int getTime(int questionIndex) const
{
return times[questionIndex];
}
~TimedMultipleChoiceTest()
{
delete times; // release memory
}
private:
int* times;
};
#ifndef RunTests
void executeTest()
{
MultipleChoiceTest test(5);
for (int i = 0; i < 5; i++)
{
test.setAnswer(i, i);
}
for (int i = 0; i < 5; i++)
{
std::cout << "Question " << i + 1 << ", correct answer: " << test.getAnswer(i) << "\n";
}
}
int main()
{
for (int i = 0; i < 3; i++)
{
std::cout << "Test: " << i + 1 << "\n";
executeTest();
}
}
#endif
you should use delete [] instead of delete to deallocate dynamic arrays.
Also, you don't seem to use the derived class but, nevertheless, the destructor in MultipleChoiceTest should be virtual
The following describe the example I have which works:
header:
const size_t N = 10;
// template<size_t N>
class SymbolicMonomial {
public:
int powers[N];
int constant;
SymbolicMonomial() {
for (int i = 0; i < N; i++) {
this->powers[i] = 0;
}
this->constant = 1;
}
SymbolicMonomial(int variable): SymbolicMonomial(){
this->powers[variable] = 1;
}
static SymbolicMonomial as_monomial(int value){
auto result = SymbolicMonomial();
result.constant = value;
return result;
}
bool is_constant(){
for(int i=0;i<N;i++){
if(this->powers[i] > 0){
return false;
}
}
return true;
}
};
// template<size_t N>
std::ostream &operator<<(std::ostream &out, const SymbolicMonomial value){
out << value.constant << "(";
for(int i=0;i<N-1;i++){
out << value.powers[i] << ", ";
}
out << value.powers[N-1] << ")";
}
// template<size_t N>
SymbolicMonomial operator*(SymbolicMonomial lhs, SymbolicMonomial rhs) {
SymbolicMonomial result = SymbolicMonomial();
for (int i = 0; i < N; i++) {
result.powers[i] = lhs.powers[i] + rhs.powers[i];
}
result.constant = lhs.constant * rhs.constant;
return result;
}
The main.cpp:
int main(int argc, char *argv[])
{
auto t_a = symbolic::SymbolicMonomial(2);
auto t_b = symbolic::SymbolicMonomial(1);
auto t_c = t_b*t_a*t_a;
std::cout << t_c << std::endl;
return 0;
}
And everything is fine. However, I wanted to change the whole thing to have a template argument <N> instead of a constant. Thus this is the templated code:
header.h:
template<const size_t N>
class SymbolicMonomial {
public:
int powers[N];
int constant;
SymbolicMonomial() {
for (int i = 0; i < N; i++) {
this->powers[i] = 0;
}
this->constant = 1;
}
SymbolicMonomial(int variable): SymbolicMonomial(){
this->powers[variable] = 1;
}
static SymbolicMonomial as_monomial(int value){
auto result = SymbolicMonomial<N>();
result.constant = value;
return result;
}
bool is_constant(){
for(int i=0;i<N;i++){
if(this->powers[i] > 0){
return false;
}
}
return true;
}
};
template<const size_t N>
std::ostream &operator<<(std::ostream &out, const SymbolicMonomial<N> value){
out << value.constant << "(";
for(int i=0;i<N-1;i++){
out << value.powers[i] << ", ";
}
out << value.powers[N-1] << ")";
}
template<const size_t N>
SymbolicMonomial<N> operator*(SymbolicMonomial<N> lhs, SymbolicMonomial<N> rhs) {
SymbolicMonomial<N> result = SymbolicMonomial<N>();
for (int i = 0; i < N; i++) {
result.powers[i] = lhs.powers[i] + rhs.powers[i];
}
result.constant = lhs.constant * rhs.constant;
return result;
}
And main.cpp:
int main(int argc, char *argv[])
{
auto t_a = symbolic::SymbolicMonomial<10>(2);
auto t_b = symbolic::SymbolicMonomial<10>(1);
auto t_c = t_b*t_a*t_a;
std::cout << t_c << std::endl;
return 0;
}
Now the non template version works as expected, however the templated one fails with code 139 (SEGFAULT). Firstly, I do not understand why the code fails if someone can explain and secondly how to fix it?
std::ostream &operator<<(std::ostream &out, const SymbolicMonomial<N> value) isn't returning a value. For me, in Visual Studio, that resulted in a compile error. Adding return out; to the end of the function lead to the code working without an ACCESS_VIOLATION (Windows flavor of a SEGFAULT).
All of your bound-checking looks correct, so, if I had to guess, I'd say that your compiler is ignoring the missing return, and you're entering a spooky space known as undefined behavior when you work with a return value that was never actually set.
Assuming you're using GCC, you can set -Werror=return-type to throw compile errors when you make these kinds of mistakes.
I have problem in implementing a disjoint set ADT in C++ due to the fact that our teacher only explained the union and find operations. I fully understand the concepts of union and find but I am still confused about how to implement them.
Could someone please give me an idea of the implementation and also explain what the interface of this data structure should look like?
You have way too many requirements, we're not here to do your homework for you.
Have a look at http://en.wikipedia.org/wiki/Disjoint-set_data_structure
#include <iostream>
template<typename T>
class Disjoint_sets
{
public:
int FIND(int pos);
bool in_same_set(T data_element_1, T data_element_2);
void UNION_IF_EQUIVALENT(T data_element_1, T data_element_2);
void UNION(T data_element_1, T data_element_2);
Disjoint_sets(bool (*is_equivalent)(T, T));
Disjoint_sets();
Disjoint_sets(T* data_arr, bool (*is_equivalent)(T, T),int size);
void insert(T data_element);
bool is_root(int pos_number);
int get_pos(T data_element);
void partition();
void print_partition();
private:
T* data;
int* parent_pos;
int* number_of_children;
int size;
bool (*isequivalent)(T D1, T D2);
};
template<typename T>
Disjoint_sets<T>::Disjoint_sets()
{
data = NULL;
parent_pos = NULL;
number_of_children = NULL;
size = 0;
isequivalent = NULL;
}
template<typename T>
Disjoint_sets<T>::Disjoint_sets(bool (*is_equivalent)(T, T))
{
isequivalent = is_equivalent;
data = NULL;
parent_pos = NULL;
number_of_children = NULL;
size = 0;
}
template<typename T>
Disjoint_sets<T>::Disjoint_sets(T* data_arr, bool (*is_equivalent)(T, T), int size)
{
data = new T[size];
parent_pos = new int[size];
number_of_children = new int[size];
this->size = size;
isequivalent = is_equivalent;
for (int i = 0; i < size; i++)
{
data[i] = data_arr[i];
parent_pos[i] = -1;
number_of_children[i] = 0;
}
}
template<typename T>
bool Disjoint_sets<T>::is_root(int pos)
{
if (pos<0 && pos>size - 1)
{
std::cout << "Error, invalid pos supplied to is_root\n";
return false;
}
if (parent_pos[pos] == -1)
{
return true;
}
else
{
return false;
}
}
template <typename T>
int Disjoint_sets<T>::FIND(int pos)
{
while (!is_root(pos))
{
pos = parent_pos[pos];
}
return pos;
}
template<typename T>
bool Disjoint_sets<T>::in_same_set(T data_element_1, T data_element_2)
{
return FIND(get_pos(data_element_1)) == FIND(get_pos(data_element_2));
}
template<typename T>
int Disjoint_sets<T>::get_pos(T data_element)
{
for (int i = 0; i < size; i++)
{
if (data[i] == data_element)
{
return i;
}
}
std::cout << "Could not find element\n";
return -1;
}
template <typename T>
void Disjoint_sets<T>::UNION(T data_element_1, T data_element_2)
{
int data_parent_1_pos = FIND(get_pos(data_element_1));
int data_parent_2_pos = FIND(get_pos(data_element_2));
if ( data_parent_1_pos==data_parent_2_pos )
{
return;
}
if (number_of_children[data_parent_1_pos] >= number_of_children[data_parent_2_pos])
{
parent_pos[data_parent_2_pos] = data_parent_1_pos;
}
else
{
parent_pos[data_parent_1_pos] = data_parent_2_pos;
}
}
template <typename T>
void Disjoint_sets<T>::UNION_IF_EQUIVALENT(T data_element_1, T data_element_2)
{
if (FIND(get_pos(data_element_1)) == FIND(get_pos(data_element_2)))
{
return;
}
if (isequivalent(data_element_1, data_element_2))
{
UNION(data_element_1, data_element_2);
}
}
template<typename T>
void Disjoint_sets<T>::partition()
{
for (int i = 0; i < size; i++)
{
for (int j = i + 1; j < size; j++)
{
UNION_IF_EQUIVALENT(data[i], data[j]);
}
}
}
template <typename T>
void Disjoint_sets<T>::print_partition()
{
for (int i = 0; i < size; i++)
{
if (is_root(i))
{
for (int j = 0; j < size; j++)
{
if (FIND(j) == i)
{
std::cout << data[j] << " ";
}
}
}
std::cout << "\n";
}
}
template <typename T>
bool lol(int a, int b)
{
return a * a == b * b;
}
int main()
{
int arr[6] = { -1,1,2,3,-3,4 };
Disjoint_sets<int> d(arr,lol<int>, 6);
d.partition();
d.print_partition();
}