This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 9 years ago.
I am writing a simple data structure library, while I met some problems.
I wrote three files. collections.h is the header file, collections.cpp is to implement the methods declared in header file, main.cpp is for test. But compile error occurs:
Undefined reference to List::GetCount() const;
Undefined reference to List::IsEmpty() const;
Undefined reference to List::Add(int);
...// And so on.
I provide my code below, where is the problem?
collections.h:
#ifndef COLLECTIONS_H
#define COLLECTIONS_H
#include <windows.h>
#include <stdexcept>
template<typename T>
class ISequenceList
{
protected:
ISequenceList() { }
public:
virtual int GetCount() const = 0;
virtual bool IsEmpty() const = 0;
virtual void Add(T item) = 0;
virtual void AddRange(const T *items, int length) = 0;
virtual T &ElementAt(int index);
virtual bool InsertAt(T item, int index);
virtual bool Remove(T item) = 0;
virtual bool RemoveAt(int index) = 0;
virtual bool Contains(T item) = 0;
};
template<typename T>
class List : public ISequenceList<T>
{
private:
int _count;
int _capacity;
T *_array;
void ExpandCapacity();
public:
List(int capacity = 100)
{
if (capacity <= 0)
std::__throw_invalid_argument("The capcity can't be 0 or below.");
this->_count = 0;
this->_capacity = capacity;
this->_array = (T*)malloc(_capacity* sizeof(T));
}
List(const List &other)
{
if (this == other)
return;
this->_count = other->_count;
this->_capacity = other->_capacity;
free(_array);
this->_array = other->_array;
}
List &operator=(const List &other)
{
this = other;
}
~List()
{
if (_array)
free(_array);
}
int GetCount() const;
bool IsEmpty() const;
T &ElementAt(int index);
void Add(T item);
void AddRange(const T *items, int length);
bool InsertAt(T item, int index);
bool Remove(T item);
bool RemoveAt(int index);
bool Contains(T item);
};
#endif
collections.cpp:
#include "collections.h"
template<typename T>
void List<T>::ExpandCapacity()
{
T *temp = this->_array;
this->_array = (T*)malloc((this->_capacity << 1) * sizeof(T));
memcpy(this->_array, temp, this->_capacity * sizeof(T));
this->_capacity = this->_capacity << 1;
free(temp);
}
template<typename T>
int List<T>::GetCount() const
{
return this->_count;
}
template<typename T>
bool List<T>::IsEmpty() const
{
return this->_count == 0;
}
template<typename T>
void List<T>::Add(T item)
{
this->_array[_count] = item;
_count++;
if (_count == _capacity)
this->ExpandCapacity();
}
template<typename T>
void List<T>::AddRange(const T *items, int length)
{
if (length <= 0)
std::__throw_invalid_argument("The length can't be 0 or below.");
if (!items)
std::__throw_invalid_argument("The items can't be null");
int totalLength = this->_count + length;
if (totalLength >= this->_capacity)
{
T *temp = this->_array;
this->_array = (T*)malloc((totalLength << 1) * sizeof(T));
memcpy(_array, temp, this->_capacity);
free(temp);
}
this->_array += this->_capacity;
memcpy(_array, items, length * sizeof(T));
this->_capacity = totalLength << 1;
this->_count += length;
}
template<typename T>
T &List<T>::ElementAt(int index)
{
if (index < 0 || index >= _count )
std::__throw_invalid_argument("The index is out of bound.");
return _array[index];
}
template<typename T>
bool List<T>::InsertAt(T item, int index)
{
if (index < 0 || index > _count)
return false;
if (index == _count)
{
this->Add(item);
return true;
}
for (int i = _count; i > index; i--)
{
_array[i] = _array[i - 1];
}
_array[index] = item;
_count++;
if (_count == _capacity)
this->ExpandCapacity();
return true;
}
template<typename T>
bool List<T>::Remove(T item)
{
for (int i = 0; i < _count; i++)
{
if (_array[i] == item)
{
for (int j = i; j < _count; j++)
{
_array[j] = _array[j + 1];
}
_count--;
return true;
}
}
return false;
}
template<typename T>
bool List<T>::RemoveAt(int index)
{
if (index < 0 || index >= _count)
return false;
for (int j = index; j < _count; j++)
{
_array[j] = _array[j + 1];
}
_count--;
return true;
}
template<typename T>
bool List<T>::Contains(T item)
{
for (int i = 0; i < _count; i++)
{
if (_array[i] == item)
return true;
}
return false;
}
main.cpp:
#include "collections.h"
#include <iostream>
int main()
{
List<int> *seqList = new List<int>();
seqList->Add(5);
int arr[100] = {0};
seqList->AddRange(arr, 50);
seqList->ElementAt(5) = 111;
seqList->InsertAt(100, 15);
seqList->Remove(50);
seqList->ElementAt(44) = 44;
seqList->RemoveAt(44);
if (seqList->Contains(111))
std::cout << "Yes" << std::endl;
for (int i = 0; i < seqList->GetCount(); i++)
{
std::cout << seqList->ElementAt(i) << "\t";
}
return 0;
}
I have defined all the methods in List, but why can't the complier recognize? Where is the problem? Thanks for anyone who help me..
Note: my ide is Code::Blocks
Implementation of the template functions must be in a header; it can't be in a separate source file. The compiler needs to see it at the point where the template is used and its arguments become known.
Related
I am trying to merge two dynamic arrays but I am getting an error in my merge function that
"data': is not a member of 'List<T>"
I know that the error is ocuring because the given parameter in the merge(const List& other) is list but I am confused how to access my ArrayList2 which has been passed in merge function in the main
my code is:
#include <iostream>
using namespace std;
template<class T>
class List {
public:
// return the capacity of the list
virtual size_t capacity() const = 0;
// return the number of elements in the list
virtual size_t size() const = 0;
// inserts an element to the beginning
virtual void push_front(const T& value) = 0;
// adds an element to the end
virtual void push_back(const T& value) = 0;
// removes the last element
virtual void pop_back() = 0;
// removes the first element
virtual void pop_front() = 0;
// remove the first occurrence of an element with the given value
virtual void remove(const T& val) = 0;
// merges two sorted lists
virtual void merge(const List<T>& other) = 0;
virtual ~List() {}
};
template<class T>
class ArrayList : public List<T>
{
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
ArrayList() = delete; // disable default constructor
// constructor
ArrayList(size_t capacity) : max_capacity(capacity), num_of_element(0) {
data = new T[capacity];
}
// copy constructor
ArrayList(const ArrayList<T>& other_list) : max_capacity(other_list.max_capacity),
num_of_element(other_list.num_of_element) {
data = new T[max_capacity];
for (size_t i = 0; i < other_list.num_of_element; i++) {
data[i] = other_list.data[i];
}
}
// destructor
virtual ~ArrayList() {
delete[]data;
}
size_t capacity() const override {
return max_capacity;
}
size_t size() const override {
return num_of_element;
}
T& operator[](int index) {
return data[index];
}
bool operator==(const ArrayList<T>& other_list) {
// not comparing capacity as eventually array list can be made capacity irrelevant using dynamic allocation
if (num_of_element != other_list.num_of_element) {
return false;
}
for (int i = 0; i < num_of_element; i++) {
if (data[i] != other_list.data[i]) {
return false;
}
}
return true;
}
void push_front(const T& value)
{
}
void push_back(const T& value)
{
if (max_capacity > num_of_element)
{
num_of_element++;
data[num_of_element - 1] = value;
}
}
void pop_back()
{
}
void pop_front()
{
}
void remove(const T& val)
{
int i = 0, j;
while (i < max_capacity)
{
if (data[i] == val)
{
for (int j = i; j < num_of_element-1; j++)
data[j] = data[j + 1];
if (data[i] == val && (i + 1) > num_of_element - 1)
{
data[i] = {};
num_of_element--;
break;
}
num_of_element--;
}
else
i++;
}
}
void merge(const List<T>& other)
{
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++)
temp[i] = data[i];
for (int j = 0; j < other.size(); j++)
{
temp[i] = other.data[j]; //I am getting error on this line
i++;
}
}
private:
void shift_left_to(size_t start) {
for (size_t i = start; i < num_of_element - 1; i++) {
data[i] = data[i + 1];
}
}
};
int main() {
ArrayList<int> list1(3);
list1.push_back(3);
list1.push_back(1);
list1.push_back(1);
ArrayList<int> list2(2);
list2.push_back(1);
list2.push_back(8);
list1.merge(list2);
/* for (size_t i = 0; i < list1.size(); i++)
cout<<list1[i]<<" ";
cout<<"Size:"<<list1.size()<<" Capacity:"<<list1.capacity();*/
system("pause");
return 0;
}
Presumably, all of your concrete List<T> classes (e.g. ArrayList<T>) will have some kind of accessors to the elements. You can make those accessors part of the List<T> interface and call them in the implementation of void merge(List<T> const&). As an example:
template <class T>
class List {
public:
// ...
virtual T& operator[](int index) = 0;
virtual T const& operator[](int index) const = 0;
};
template <class T>
class ArrayList : public List<T> {
private:
T* data;
size_t max_capacity;
size_t num_of_element;
public:
// ...
T& operator[](int index) override { return data[index]; }
T const& operator[](int index) const override { return data[index]; }
// ...
void merge(const List<T>& other) {
int i;
int newsize = size() + other.size();
T* temp = new T[newsize];
for (i = 0; i < num_of_element; i++) temp[i] = data[i];
for (int j = 0; j < other.size(); j++) {
temp[i] = other[j]; // < Use your List<T>::operator[] here
i++;
}
}
// ...
};
I'd say the message is quite descriptive: List does not have a member called data. You should use the [] operator instead to access the list elements in the merge function. [] operator is implemented by descendants of List.
temp[i] = other[j]
this is the header of a class that I have been designing for an assignment. I have included constructors, a destructors, as well as overloaded operators. Could you give me a hint how to properly define the constructors in a class using c++ 20 most recent features in an efficient way.
#ifndef VECTOR_DOUBLE_H
#define VECTOR_DOUBLE_H
#include <memory>
#include <vector>
class vector_double {
public:
vector_double(int size);
vector_double(std::initializer_list<double> lst);
vector_double(const double* array, int size);
vector_double(const vector_doubler& other);
vector_doubleoperator=(const vector_double& other);
// because I use a managed pointer I don't need a destructor
~vector_double() noexcept = default;
void set(int index, double val);
double& get(int index);
const double& get(int index) const;
int size() const;
void reset(double val);
void fill_from(std::initializer_list<double> lst);
void fill_from(const double* array, int size);
int copy_to(std::vector<double>& vec) const;
double& operator[](int index);
const double& operator[](int index) const;
operator double() const;
vector_double add(const vector_double& other) const;
vector_doubleadd(double number) const;
vector_doublemul_by(double number) const;
void resize(int size);
friend std::ostream& operator<<(std::ostream& out, const vector_double& vec);
private:
std::unique_ptr<double[]> m_array;
int m_size;
};
inline std::ostream& operator<<(std::ostream& out, const vector_double& vec){
if (vec.m_size == 0){
out << "{ }";
}
else{
auto first = true;
out << '{';
for (int i=0; i < vec.m_size; ++i){
if (!first)
out << ", ";
else
first = !first;
out << vec.m_array[i];
}
out << '}';
}
return out;
}
#endif //VECTOR_DOUBLE_H
This example definition may help, I tried sticking to C++20 features:
#include <cmath>
#include "vector_double.h"
vector_double::vector_double(int size):
m_array{ new double[size] },
m_size{size}
{}
vector_double::vector_double(std::initializer_list<double> lst): //Constructor that takes an init list
vector_double(lst.size())
{
std::copy(lst.begin(), lst.end(), m_array.get());
}
vector_double::vector_double(const double* array, int size): //Constructor that takes array and size
vector_double(size)
{
// std::copy(array, array + size, m_array.get());
std::copy(&array[0], &array[size], m_array.get());
}
vector_double::vector_double(const vector_double& other): //Copy Constructor
vector_double(other.m_size)
{
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
vector_double& vector_double::operator=(const vector_double& other) {
if (this != &other) {
if (m_size != other.m_size) {
auto* array = new double[other.m_size];
m_array.reset(array);
m_size = other.m_size;
}
std::copy(&other.m_array[0], &other.m_array[m_size], &m_array[0]);
}
return *this;
}
void vector_double::set(int index, double val) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
m_array[index] = val;
}
double& vector_double::get(int index) {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
const double& vector_double::get(int index) const {
if (index < 0 || index > m_size)
throw std::out_of_range("oooh my!");
return m_array[index];
}
int vector_double::size() const {
return m_size;
}
void vector_double::reset(double val) {
for (int i=0; i<m_size; ++i){
m_array[i] = val;
}
}
void vector_double::fill_from(std::initializer_list<double> lst) {
int size = std::min((int)lst.size(), m_size);
std::copy(lst.begin(), lst.begin() + size, &m_array[0]);
}
void vector_double::fill_from(const double* array, int size) {
size = std::min(size, m_size);
for (int i = 0; i < size; ++i) {
m_array[i] = array[i];
}
}
int vector_double::copy_to(std::vector<double>& vec) const {
for (int i = 0; i < m_size; ++i) {
vec.push_back(m_array[i]);
}
return m_size;
}
double& vector_double::operator[](int index) {
return m_array[index];
}
const double& vector_double::operator[](int index) const { //Overloading "[]" operator
return m_array[index];
}
vector_double::operator double() const {
double sum = 0.0;
for (int i = 0; i < m_size; ++i) {
sum += m_array[i] * m_array[i];
}
return std::sqrt(sum);
}
vector_double vector_double::add(const vector_double& other) const {
if (m_size != other.m_size)
throw std::logic_error("size mismatch");
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += other[i];
}
return copy;
}
vector_double vector_double::add(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] += number;
}
return copy;
}
vector_double vector_double::mul_by(double number) const {
auto copy = *this;
for (int i = 0; i < m_size; ++i) {
copy[i] *= number;
}
return copy;
}
void vector_double::resize(int size) {
if (size != m_size){
auto array = new double[size] {0,};
auto common = std::min(size,m_size);
for (int i = 0; i < common; ++i) {
array[i] = m_array[i];
}
m_array.reset(array);
m_size = size;
}
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
In an assigment, I was asked to create my own Vector<T>, Mathvector<T> (which inherits from vector) and a Polynomial class type.
I'm getting the following error and couldn't figure out why.
MathVector.h:37:32: error: invalid operands to binary expression ('mathVector<double>' and 'mathVector<double>')
if (this[j]>this[j+1])
Ihe sort function is in "mathVector.h" and its goal is to sort the vector in ascending or descending order.
This is the error part of the "MathVector.h":
void sort(int index) {
int i,j;
int n=this->get_size();
if (index==1) {
for (i=0; i<n-1; i++)
for (j=0; j<n-i-1; j++) {
if (this[j]>this[j+1]) {
T temp;
temp=this[j+1];
this[j+1]=this[j];
this[j]=temp;
}
}
}
else {
for (i=0; i<n-1; i++)
for (j=0; j<n-i-1; j++) {
if (this[j]<this[j+1]) {
T temp;
temp=this[j+1];
this[j+1]=this[j];
this[j]=temp;
}
}
}
return;
}
This is the "vector.h":
template<class T>
class Vector {
private:
int _size;
int _capacity;
T *_data;
static T *allocate(int size) {
return static_cast<T *>(malloc(sizeof(T) * size));
}
static void copyRange(T *begin, T *end, T *dest) {
while (begin != end) {
new((void *) dest) T(*begin);
++begin;
++dest;
}
}
static void deleteRange(T *begin, T *end) {
while (begin != end) {
begin->~T();
++begin;
}
}
public:
Vector() {
_size = 0;
_capacity = 0;
_data = 0;
}
~Vector() {
deleteRange(_data, _data + _size);
free(_data);
}
Vector(const Vector &obj) {
this->_size = obj.get_size();
this->_data = obj.get_data();
this->_capacity = obj.get_capacity();
}
void insert(const T &value) {
if (_size != _capacity) {
new((void *) (_data + _size)) T(value);
++_size;
return;
}
int newCapacity;
if (_capacity == 0) { newCapacity = 1; }
else (newCapacity = _capacity * 2);
T *newData = allocate(newCapacity);
copyRange(_data, _data + _size, newData);
new((void *) (newData + _size)) T(value);
deleteRange(_data, _data + _size);
free(_data);
_data = newData;
_capacity = newCapacity;
++_size;
}
void resize(int index) {
if (index == _capacity) { return; }
else if (index > _capacity) { _capacity = index; }
else {
_capacity = index;
if (index < _size) {
deleteRange(_data + index, _data + _size);
_size = index;
}
}
}
T &operator[](int index) {
T empty;
if ((index < 0) || (index >= _size)) {
cout<<"Wrong Index";
return empty;
}
return _data[index];
}
const T &
operator[](int index) const {
T empty;
if ((index < 0) || (index >= _size)) {
cout<<"Wrong Index";
return empty;
} else return _data[index];
}
Vector &operator=(const Vector &other) {
this->_size = other.get_size();
this->_data = other.get_data();
this->_capacity = other.get_capacity();
return *this;
}
friend ostream &operator<<(ostream &os, const Vector &other) {
os << "Size: " << other._size << " | Capacity: " << other._capacity << " | ";
int i;
for (i = 0; i < other._size; i++) {
os << other[i] << ",";
}
return os;
}
T *begin() const {
return _data;
}
T *end() const {
return _data + _size;
}
int get_size() const {
return _size;
}
T* get_data() const {
return _data;
}
int get_capacity() const {
return _capacity;
}
};
this[j] is hardly ever the right thing to do. It can only be correct, if *this happens to be a subobject within an array, and have at least j siblings after it. this[j] is equivalent to *(this + j). As you can see, it dereferences a pointer to jth sibling after *this.
I suspect, that you instead intended to access the elements of the buffer by calling Vector::operator[]. You'd do that by dereferencing the pointer first: (*this)[j].
This main program should ask the user to put in some numbers and store them into a dynamic array. The array should then be outputted its contents in a straight line, no end line commands, with a comma in between. I can't figure out how to start the program.
If you guys can help me find a way to do this, I would be eternally thankful!
Here is ListType.h:
#ifndef LISTTYPE_H_INCLUDED
#define LISTTYPE_H_INCLUDED
#include <iostream>
class ListType {
public:
ListType(size_t=10);
virtual ~ListType();
virtual bool insert(int)=0;
virtual bool erase();
virtual bool erase(int)=0;
virtual bool find(int) const=0;
size_t size() const;
bool empty() const;
bool full() const;
void output(std::ostream& out) const;
friend std::ostream& operator << (std::ostream&, const ListType&);
protected:
int *items;
size_t capacity;
size_t count;
};
#endif // LISTTYPE_H_INCLUDED
here is UListType.h:
#ifndef ULISTTYPE_H_INCLUDED
#define ULISTTYPE_H_INCLUDED
#include <iostream>
class UListType: public ListType {
public:
UListType(size_t=10);
bool insert(int);
bool erase(int);
bool find(int) const;
};
#endif // ULISTTYPE_H_INCLUDED
here is OListType.h:
#ifndef OLISTTYPE_H_INCLUDED
#define OLISTTYPE_H_INCLUDED
#include <iostream>
class OListType: public ListType {
public:
OListType(size_t=10);
bool insert(int);
bool erase(int);
bool find(int) const;
};
#endif // OLISTTYPE_H_INCLUDED
here is ListType.cpp:
#include "ListType.h"
ListType::ListType (size_t a) {
capacity = a;
count = 0;
items = new int [capacity];
}
ListType::~ListType() {
delete [] items;
}
bool ListType::erase() {
count = 0;
return 0;
}
size_t ListType::size() const {
return (count);
}
bool ListType::empty() const {
return (count == 0);
}
bool ListType::full() const {
return (count == capacity);
}
void ListType::output(std::ostream& out) const {
for (int i = 0; i < count; i++) {
if (i > 0) {
out << ", ";
}
out << items[i];
}
}
std::ostream& operator << (std::ostream& out, const ListType& my_list) {
my_list.output(out);
return out;
}
here is UListType.cpp
#include "ListType.h"
#include "UListType.h"
UListType::UListType (size_t c): ListType(c) {}
bool UListType::insert(int item) {
if (full()) {
int *newitems;
capacity *=2;
newitems = new int[capacity];
for (size_t i =0; i < count; ++i){
newitems[i] = items[i];
}
delete [] items;
items = newitems;
}
items[count++] = item;
return true;
}
bool UListType::erase(int item) {
bool result = false;
size_t i=0;
while ( i < count && items [i] != item) {
++i;
}
if (i < count) {
items[i] = items[-- count];
result = true;
}
return result;
}
bool UListType::find(int item) const {
size_t i = 0;
while (i < count && items [i] != item) {
++i;
}
return i;
}
here is OListType.cpp
#include "ListType.h"
#include "OListType.h"
OListType::OListType(size_t c): ListType(c) {}
bool OListType::insert(int item) {
size_t i = count;
if (full()) {
int *newitems;
capacity *=2;
newitems = new int[capacity];
while (i > 0 && items[i-1] > item){
newitems[i] = items[i];
}
delete [] items;
items = newitems;
}
items[count++] = item;
return true;
}
bool OListType::erase(int item) {
bool found=false;
size_t i=0, j= count-1, mid;
while (i <= j && !(found)){
mid = (i + j)/2;
if (item < items [mid])
j = mid - 1;
else if (item > items [mid])
i = mid + 1;
found = items [mid] == item;
}
if (found) {
for (i = mid; i < count - 1; ++i) {
items [i] = items [i +1];
}
--count;
}
return found;
}
bool OListType::find (int item) const {
bool found=false;
size_t i=0, j= count-1, mid;
while (i <= j && !(found)){
mid = (i + j)/2;
if (item < items [mid])
j = mid - 1;
else if (item > items [mid])
i = mid + 1;
found = items [mid] == item;
}
return found;
}
#include "ListType.h"
#include "UListType.h"
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
int main()
{
UListType UL;
cout << "How many numbers do you want to put it?" << endl;
int n;
cin >> n;
cout << "All right, enter " << n << " numbers:" << endl;
int x;
for(int k=0; k<n; ++k)
{
cin >> x;
// do something with x
}
return(0);
}
You already have everything you need. Try the following
#include <iostream>
#include "OListType.h"
using namespace std;
int main()
{
OListType list;
int n;
do
{
cout << "Add a number [Y/n]?";
char a;
cin >> a;
if (a != 'n')
{
cin >> n;
list.insert(n);
}
else
{
list.output(cout);
break;
}
}while (1);
return 0;
}
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();
}