Copy constructor of N-ary tree in C++ - c++

I have the following header class:
class Tree
{
private:
string label;
vector<Tree*> children;
void free(Tree* tree);
Tree* copyFrom(const Tree* other);
public:
Tree(string _label, vector<Tree*> _children= vector<Tree*>());
Tree(const Tree& other);
void addChild(Tree* child);
Tree& operator=(const Tree& other);
Tree* addChild(Tree* parent, string label);
void removeChild(vector<Tree*>::iterator position);
void insertTree(Tree* tree, vector<Tree*>::iterator position);
~Tree();
};
and following implementation
#include "Tree.h"
string Tree::getLabel() const
{
return label;
}
Tree* Tree::copyFrom(const Tree* other)
{
if (other == nullptr)
{
return nullptr;
}
Tree* result = new Tree(other->label);
vector<Tree*> _children;
for (int i = 0; i < other->children.size(); i++)
{
_children.push_back(copyFrom(other->children[i]));
}
result->children= _children;
return result;
}
void Tree::free(Tree* tree)
{
if (this == nullptr)
{
return;
}
for (int i = 0; i < tree->children.size(); i++)
{
delete tree->_children[i];
}
tree->children.clear();
}
Tree::Tree(string _label, vector<Tree*> _children)
:label(_label), children(_children)
{
}
Tree::Tree(const Tree& other)
{
const Tree* pointer = &other;
copyFrom(pointer);
this->label = pointer->label;
this->children= pointer->children;
pointer = nullptr;
}
Tree& Tree::operator=(const Tree& other)
{
if (this != &other)
{
free(this);
const Tree* pointer = &other;
copyFrom(pointer);
this->label = pointer->label;
this->children= pointer->children;
pointer = nullptr;
}
return *this;
}
Tree::~Tree()
{
free(this);
}
void Tree::addChild(Tree* child)
{
children.push_back(child);
}
Tree* Tree::addChild(Tree* parent, string label)
{
if (parent == nullptr)
{
throw "No parent";
}
Tree* result = new Tree(label);
parent->children.push_back(result);
return result;
}
void Tree::removeChild(vector<Tree*>::iterator position)
{
if (children.size() == 0)
{
throw "No children to delete from!";
}
int index = position - children.begin();
Tree* toDelete = children.at(index);
children.erase(position);
delete toDelete;
}
void Tree::insertChild(Tree* tree, vector<Tree*>::iterator position)
{
if (tree== nullptr)
{
throw "Tree cannot be null!";
}
children.insert(position, tree);
}
I have some struggles with my destructor, copy constructor and consequently, operator=. I believe my destructor works correctly, but my copy constructor is giving me a hard time, because it is supposed to create a deep copy, but when I copied an object, let's call the copy copyTree and the original firstTree, and then removed a child from firstTree, the change affected copyTree as well. What am I doing wrong?

The replies provided me with great workarounds for this hassle, but to answer my question, the concrete problem was that I forgot to assign the result from copyFrom, that is:
Box::Box(const Box& other)
{
const Box* pointer = &other;
Box* result = copyFrom(pointer);
this->label = result->label;
this->boxes = result->boxes;
this->souvenirs = result->souvenirs;
pointer = nullptr;
}
and same for operator =

Related

Implementation of a Doubly Linked List

I am trying to implement a linked list, and I am completely lost. I'm getting break points all over the place, specifically with the erase method. Whenever I alter the erase method, some error will inevitably spring up. I've got pointer errors, problems with the destructor that only occur when the erase method is called, and so on.
Here's what I have so far:
Header file:
#pragma once
class IntList {
private:
class IntNode {
public:
IntNode(int v, IntNode *pr, IntNode *nx);
~IntNode();
IntNode* previous;
IntNode* next;
class iterator {
public:
iterator(IntNode* t);
int& operator*();
iterator& operator++();
iterator& operator--();
bool operator!=(iterator other)const;
private:
IntNode* target;
};
private:
int value;
};
IntNode* head;
IntNode* tail;
int count;
public:
IntList();
~IntList();
void push_back(int v);
void pop_back();
int size() const { return count; }
typedef IntNode::iterator iterator;
iterator begin();
iterator end();
//unsigned int size() const;
void push_front(int value);
bool empty() const;
int& front();
int& back();
void clear();
iterator erase(iterator position);
};
Implementation:
#include "IntList.h"
#include <stdexcept>
IntList::IntList() : head{ nullptr }, tail{ nullptr }, count{ 0 }
{}
IntList::~IntList() {
while (head) {
head = head->next;
delete head;
}
}
void IntList::push_back(int v) {
tail = new IntNode{ v, tail, nullptr };
if (!head) { head = tail; }
count += 1;
}
void IntList::pop_back() {
tail = tail->previous;
delete tail->next;
count -= 1;
}
IntList::iterator IntList::begin()
{
return iterator{ head };
}
IntList::iterator IntList::end() {
return iterator{ nullptr };
}
void IntList::push_front(int value) {
head = new IntNode{ value, nullptr, head };
if (!tail) { tail = head; }
count += 1;
}
bool IntList::empty() const{
return (count==0);
}
int& IntList::front() {
return *begin();
}
int& IntList::back() {
return *begin();
}
void IntList::clear() {
head = nullptr;
tail = nullptr;
count = 0;
}
IntList::iterator IntList::erase(iterator position) {
int midpointL = 0;
for (iterator index = begin(); index != position; ++index) {
midpointL++;
}
if (midpointL == 0) {
head = head->next;
}
else if (midpointL == count) {
tail = tail->previous;
}
else {
// Move head to get a reference to the component that needs to be deleted
for (int i = 0; i < midpointL; i++) {
head = head->next;
}
// Change the previous and next pointers to point to each other
(head->previous)->next = (head->next);
(head->next)->previous = (head->previous);
for (int i = midpointL-1; i > 0; i++) {
head = head->previous;
}
}
count-=1;
return position;
}
IntList::IntNode::IntNode(int v, IntNode * pr, IntNode * nx)
: previous{ pr }, next{ nx }, value{ v }
{
if (previous) { previous->next = this; }
if (next) { next->previous = this; }
}
IntList::IntNode::~IntNode() {
if (previous) previous->next = next;
if (next) next->previous = previous;
}
IntList::IntNode::iterator::iterator(IntNode* t)
: target{ t }
{}
int& IntList::IntNode::iterator::operator*() {
if (!target) { throw std::runtime_error{ "Deferenced sentinel iterator." }; }
return target->value;
}
IntList::IntNode::iterator& IntList::IntNode::iterator::operator++()
{
if (target) { target = target->next; }
return *this;
}
IntList::IntNode::iterator& IntList::IntNode::iterator::operator--()
{
if (target) { target = target->previous; }
return *this;
}
bool IntList::IntNode::iterator::operator!=(iterator other)const
{
return (!(target == other.target));
}
Could anyone help point me in the right direction?
Thanks!
Let's make a kind of quick review here:
IntList::~IntList() {
while (head) {
head = head->next;
delete head;
}
}
you should do instead:
IntList::~IntList() {
while (head) {
IntNode* newHead = head->next;
delete head;
head = newHead;
}
}
as you are deleting the "next" object and then you are trying to get access to it in the next iteration.
void IntList::pop_back() {
tail = tail->previous;
delete tail->next;
count -= 1;
}
Here you are not checking if tail is null or if it is pointing to head..(what's the empty condition?), maybe count!=0? in case you may delete a not existing next-node
IntList::iterator IntList::end() {
return iterator{ nullptr };
}
..end is null? ebd should be your tail...
int& IntList::back() {
return *begin();
}
that's begin..not back.
void IntList::clear() {
head = nullptr;
tail = nullptr;
count = 0;
}
a clear should release all the objects in the list. You are generating garbage here (leaks).
I stopped here, sorry for that, it's just a coffee break. But you should look carefully at:
* null pointer usage
* delete your node list item when not needed
* pay attention to do not use invalid pointers (like head->previous->next I saw somewhere)
You have to review your code, bottom up. Hope that those first hints help you through your learning process.
Have fun,
Ste

Error EXC_BAD_ACCESS in list with SmartPointer

I'm facing this problem when I remove an element from my list.
Here my list.h:
class AwesomeList {
friend class Iteratore;
private:
class Nodo;
class SmartPointer {
public:
Nodo* punt;
SmartPointer(Nodo* n = 0): punt(n) {}
SmartPointer(const SmartPointer& ptr): punt(ptr.punt) {}
~SmartPointer() {
delete punt;
}
SmartPointer& operator=(const SmartPointer& ptr) {
if (this != &ptr) {
delete punt;
punt = ptr.punt;
}
return *this;
}
bool operator==(const SmartPointer& ptr) const {
return ptr.punt == punt;
}
bool operator!=(const SmartPointer& ptr) const {
return ptr.punt != punt;
}
Nodo* operator->() const {
return punt;
}
Nodo& operator*() const {
return *punt;
}
};
class Nodo {
public:
T* value;
SmartPointer next;
Nodo(T* t = T(), const SmartPointer& ptr = SmartPointer()): value(t), next(ptr) {}
};
SmartPointer head;
SmartPointer tail;
public:
class Iteratore{
friend class AwesomeList;
private:
AwesomeList::SmartPointer punt;
public:
bool operator==(const Iteratore& it) const {
return it.punt == punt;
}
bool operator!=(const Iteratore& it) const {
return it.punt != punt;
}
Iteratore& operator++() {
if(punt != 0) punt = punt->next;
return *this;
}
Iteratore& operator++(int) {
if(punt != 0) punt = punt->next;
return *this;
}
T* operator*() const {
if (punt != 0) return punt->value;
}
};
AwesomeList(const SmartPointer& ptr = 0): head(ptr), tail(0) {
if (head != 0) {
SmartPointer p = head;
while (p != 0)
p = p->next;
tail = p;
}
}
AwesomeList(const AwesomeList& list): head(list.head), tail(list.tail) {}
AwesomeList& operator=(const AwesomeList& list) {
head = list.head;
tail = list.tail;
}
int getSize() const {
int count = 0;
SmartPointer p = head;
while (p != 0) {
p = p->next;
count++;
}
return count;
}
bool isEmpty() const {
return getSize() == 0;
}
T* at(int pos) const {
if (pos > -1 && pos < getSize()) {
SmartPointer p = head;
while (pos--) {
p = p->next;
}
return p->value;
} else return 0;
}
void add(const T& t) {
if (head == 0) {
head = SmartPointer(new Nodo(&(const_cast<T&>(t))));
tail = head;
} else {
tail->next = SmartPointer(new Nodo(&(const_cast<T&>(t))));
tail = tail->next;
}
}
void remove(int pos) {
if (pos > -1 && pos < getSize()) {
SmartPointer newHead = head;
SmartPointer p = newHead;
head = 0;
while (pos--) {
add(*p->value);
p = p->next;
}
p = p->next;
while (p != 0) {
add(*p->value);
p = p->next;
}
}
}
void replace(int pos, T* t) {
if (pos > -1 && pos < getSize()) {
SmartPointer p = head;
while (pos--)
p = p->next;
p->value = t;
}
}
void replace(int pos, const T& t) {
if (pos > -1 && pos < getSize()) {
SmartPointer p = head;
while (pos--)
p = p->next;
T& t_obj = const_cast<T&>(t);
p->value = &t_obj;
}
}
Iteratore begin() const {
Iteratore it;
it.punt = head;
return it;
}
Iteratore end() const {
Iteratore it;
it.punt = 0;
return it;
}
T* operator[](const Iteratore& it) const {
return it.punt->value;
}
};
This are the tests I made:
AwesomeList<int> list = AwesomeList<int>();
list.add(1);
list.add(2);
list.add(3);
for (int i = 0; i < list.getSize(); i++)
qDebug() <<*(list.at(i)) <<" ";
list.remove(-1);
for (int i = 0; i < list.getSize(); i++)
qDebug() <<*(list.at(i)) <<" ";
list.remove(2);
for (int i = 0; i < list.getSize(); i++)
qDebug() <<*(list.at(i)) <<" ";
list.replace(0, 5);
qDebug() <<"Replace in posizione 0";
auto cit = list.begin();
for (; cit != list.end(); cit++)
qDebug() <<*(*cit) <<" ";
qDebug() <<"Size";
qDebug() <<list.getSize() <<endl;
This is the lines where errors appears:
AwesomeList::Nodo::~Nodo() + 16 (awesomelist.h:8)
AwesomeList::SmartPointer::~SmartPointer() + 42 (awesomelist.h:21)
AwesomeList::SmartPointer::~SmartPointer() + 21 (awesomelist.h:22)
Any help is appreciate. Thanks!
UPDATE
I solved my problem changing SmartPointer and Nodo classes like this:
SmartPointer(Nodo* n = 0): punt(n) {
if (punt) punt->references++;
}
SmartPointer(const SmartPointer& ptr): punt(ptr.punt) {
if (punt) punt->references++;
}
~SmartPointer() {
if (punt) {
punt->references--;
if (punt->references == 0) delete punt;
}
}
SmartPointer& operator=(const SmartPointer& ptr) {
if (this != &ptr) {
Nodo* n = punt;
punt = ptr.punt;
if (punt) punt->references++;
if (n) {
n->references--;
if (n->references == 0) delete n;
}
}
return *this;
}
bool operator==(const SmartPointer& ptr) const {
return ptr.punt == punt;
}
bool operator!=(const SmartPointer& ptr) const {
return ptr.punt != punt;
}
Nodo* operator->() const {
return punt;
}
Nodo& operator*() const {
return *punt;
}
};
class Nodo {
public:
T* value;
SmartPointer next;
int references;
Nodo(T* t = T(), const SmartPointer& ptr = SmartPointer()): value(t), next(ptr), references(0) {}
};
Sorry but I don't understand the ratio beneath your SmartPointer class.
It carry a pointer to a Nodo and delete it with the constructor. Good.
But, if I'm not wrong
(1) when you create a SmartPointer with copy constructor, you copy the pointer from the SmartPointer copied so you have two object with a punt with the same value; when you destroy the two objects, you call delete two times over the same pointer; this can crash the program
(2) when you call operator=, you have the same problem with the copy constructor but, moreover, you don't delete the old pointed value
By example, look at add()
head = SmartPointer(new Nodo(&(const_cast<T&>(t))));
tail = head;
You create a temporary SmartPointer object initializing it with new Nodo(&(const_cast<T&>(t))). Next you copy this temporary object in head, so both head and the temporary object are carrying the same not-NULL pointer. Now the temporary object is destroyed, so the memory pointed by punt is deleted but head (his punt) continue to point to a memory area that is deleted. Now you copy head in tail, and you have both head and tail that are pointing to the same deleted area.
Look at the else case
tail->next = SmartPointer(new Nodo(&(const_cast<T&>(t))));
tail = tail->next;
In this case, tail->next (and take in count that take point to a deleted area) receive a pointer from a temporary object that delete it. So you write in a deleted area a pointer that is immediately deleted.
I hope it is clear how much all this is dangerous.
Suggestion: redesign SmartPointer class.
p.s.: sorry for my bad English.

C++ List is not copying via copy ctor or assignment operator

I have a program that has a list manually put into it, its just a bunch of names tossed in like this: list.PushBack("Frank"); or list.PushFront("George");
My current problem is that when I attempt to run the already made list through my copy constructor and assignment operator, the list comes out "" (as defined in an isEmpty function)
Ignore all of the "TODO" commented spots, those are mental notes for myself.
There are also a couple of random cout statements that I used for debugging purposes, and would like to keep there until everything is working properly.
Here is the relevant code:
List.h
class Node;
class List
{
public:
List();
List(const char* p);
//Copy constructor
List(const List& str);
//Deep Copy
List& operator=(const List& str);
~List();
void Clear();
//Adds to the front
void PushFront(std::string data);
//adds to the back
void PushBack(std::string data);
//removes from the front
void PopFront();
//removes from the back
void PopBack();
//gets the back value
std::string& Back() const;
//gets the from value
std::string& Front() const;
bool Empty() const {return m_pFront == 0;}
ostream& OutPut(ostream& os);
private:
Node* m_pFront;
Node* m_pBack;
char* m_pData;
};
List.cpp
List::List() : m_pFront(0), m_pBack(0), m_pData(0)
{}
List::~List()
{
Clear();
}
void List::Clear()
{
//delete
if(!m_pFront)
{
return;
}
delete m_pFront;
delete m_pData;
m_pFront = 0;
m_pBack = 0;
}
void List::PushFront(std::string data)
{
//create a new node
Node* p = new Node(data);
//Empty list
if(!m_pFront)
{
m_pFront = p;
m_pBack = p;
}
else //Not empty list
{
p -> m_pNext = m_pFront;
m_pFront -> m_pPrev = p;
m_pFront = p;
}
}
void List::PushBack(std::string data)
{
Node* p = new Node(data);
if(!m_pBack)
{
m_pFront = p;
m_pBack = p;
}
else
{
p -> m_pPrev = m_pBack;
m_pBack -> m_pNext = p;
m_pBack = p;
}
}
void List::PopFront()
{
if(m_pFront == 0)
{
//TODO: we need to handle this problem
return;
}
if(m_pBack == m_pFront)
{
Clear();
return;
}
Node* p = m_pFront;
m_pFront = m_pFront -> m_pNext;
p -> m_pNext = 0;
m_pFront -> m_pPrev = 0;
delete p;
}
void List::PopBack()
{
if(m_pBack == 0)
{
//TODO: we need to handle this problem
return;
}
if(m_pBack == m_pFront)
{
Clear();
return;
}
Node* p = m_pBack;
m_pBack = m_pBack -> m_pPrev;
p -> m_pPrev = 0;
m_pBack -> m_pNext = 0;
delete p;
}
ostream& List::OutPut(ostream& os)
{
if(Empty() == true)
{
os << "<empty>";
}
else
{
m_pFront -> OutputNode(os);
}
return os;
}
std::string& List::Back() const
{
if(m_pBack == 0)
{
//TODO: we need to handle this problem
}
return m_pBack -> GetData();
}
std::string& List::Front() const
{
if(m_pFront == 0)
{
//TODO: we need to handle this problem
}
return m_pFront -> GetData();
}
//Copy Constructor
List::List(const List& str)
{
if(str.m_pData)
{
m_pData = new char[strlen(str.m_pData) + 1];
strcpy(m_pData, str.m_pData);
}
else
{
m_pData = 0;
}
}
//Deep copy
List& List::operator=(const List& str)
{
//Check for self assignment
if(this == &str)
{
return *this;
}
//Deallocate any value the string is holding
delete [] m_pData;
//Now we need to deep copy m_pData
if(str.m_pData)
{
//Allocate memory for the copy
m_pData = new char[strlen(str.m_pData) + 1];
//Copy the parameter to the newly allocated memory
strcpy(m_pData, str.m_pData);
}
else
{
m_pData = 0;
}
return *this;
}
You can change char* m_pData; to std::string m_sData, Otherwise, you need to allocate memory for m_pData manually.
and m_pData = str.m_pData; will cause problem, because you let m_pData point to str.m_pData, if str.m_pData got delete it. m_pData point to unknown place.
In your copy constructor
//Copy Constructor
List::List(const List& str)
{
if(Empty() == true)
{
m_pData = 0;
return;
}
m_pData = str.m_pData;
strcpy(m_pData, str.m_pData);
}
You are using Empty() which is bool Empty() const {return m_pFront == 0;} and m_pFront is not initialized so far.
And m_pData = str.m_pData there is no need for strcpy.
Rather make copy of this string (first allocated and then copy) or use std::string instead.

C++ custom template LinkedList crashes adding std::string

For academic purposes, I'm trying to develop a little "textual adventure game". I have to implement all data structures by my own. Now, I have some problems with the implementation of a generic (template) LinkedList.
In the specific, this data structure works with everything (primitive data types and custom objects) BUT strings! (standard library strings).
When I try to add strings to a list, the application crashes with the following error (in console):
"terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_constructor null not valid"
The list is implemented as a "double linked list" using the head-node as first-last node
Here the code ("Abstract" List interface):
#ifndef LIST_H_
#define LIST_H_
template <class T>
class List
{
public:
virtual ~List() {}
virtual T get(int position) = 0;
virtual List* add(T item) = 0;
virtual List* insert(T item, int position) = 0;
virtual List* remove(int position) = 0;
virtual int size() const = 0;
virtual bool isEmpty() const = 0;
protected:
private:
};
#endif /* LIST_H_ */
This is the LinkedList implementation (the "node" class):
#include "List.h"
#include <stdlib.h>
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
template <class T>
class ListNode
{
public:
ListNode(T item)
{
mItem = item;
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item;
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem;
}
T getItem()
{
return mItem;
}
ListNode<T>* getNext()
{
return mNext;
}
ListNode<T>* getPrev()
{
return mPrev;
}
void setItem(T item)
{
mItem = item;
}
void setNext(ListNode<T>* next)
{
mNext = next;
}
void setPrev(ListNode<T>* prev)
{
mPrev = prev;
}
protected:
private:
T mItem;
ListNode<T> *mNext, *mPrev;
};
The LinkedList class:
template <class K>
class LinkedList : public List<K>
{
public:
LinkedList()
{
mSize = 0;
mFirstNode = NULL;
}
~LinkedList()
{
// implementazione distruttore tramite ciclo sui nodi
}
K get(int position)
{
K item = NULL;
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL) item = targetNode->getItem();
return item;
}
List<K>* add(K item)
{
if (mFirstNode == NULL)
{
mFirstNode = new ListNode<K>(item);
mFirstNode->setNext(mFirstNode);
mFirstNode->setPrev(mFirstNode);
}
else
{
ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev());
mFirstNode->getPrev()->setNext(newNode);
mFirstNode->setPrev(newNode);
}
mSize++;
return this;
}
List<K>* insert(K item, int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode);
targetNode->setItem(item);
targetNode->setNext(newNode);
mSize++;
}
return this;
}
List<K>* remove(int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
targetNode->setItem(targetNode->getNext()->getItem());
targetNode->setNext(targetNode->getNext()->getNext());
//delete targetNode->getNext();
mSize--;
}
return this;
}
int size() const
{
return mSize;
}
bool isEmpty() const
{
return (mFirstNode == NULL) ? true : false;
}
protected:
ListNode<K>* getNodeAtPosition(int position)
{
ListNode<K>* current = NULL;
if (mFirstNode != NULL && position < mSize)
{
current = mFirstNode;
for (int i = 0; i < position; i++)
{
current = current->getNext();
}
}
return current;
}
private:
int mSize;
ListNode<K>* mFirstNode;
};
#endif /* LINKEDLIST_H_ */
Suggestions?
Part of your problem is here:
ListNode(T item)
{
mItem = item; // for a std::string, this will be a class member, non-pointer
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item; // same here
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem; // you are attempting to delete an item you never created
}
You should either change your constructors to create a T* object on the heap (which will then be deleted in your destructor), or remove the delete line from your destructor.
This problem will be evident with far more than just std::string, by the way.
Somewhere in your program you are doing this:
std::string s(nullptr);
Calling std::string's constructor with a null pointer is causing it to throw a std::logic_error exception.
From the standard:
ยง 21.4.2
basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
Requires: s shall not be a null pointer and n < npos.
It seems it's not possible to pass std::string as template argument...
Strings as Template Arguments
Now I use an "old" - char const* - to achieve the expected result, even if I have to implement my personal "utils" methods to work with those pointers now...

How can I manage memory deallocation in disjoint sets in C++?

I have a set of classes to handle Disjoint sets in my C++ app. I have a hard time implementing the destructors for these classes. Can anyone help me on that?
What these basically do is: put nodes' pointers into NodeAddress[], every node is distinguished by its val. Every node has a pointer to the Item which is a placeholder for hd head and tl tail of the disjoint set.
I want to mention that I realize that there are some issues with e.g. : variable visibility ( public access ), constant size NodeAddress buffer but I want to focus here on memory deallocation.
And yes I want (need) to do it on pointer (no STL). If you have sny suggestions or questions feel free to comment.
This is the code :
header
class ListSet {
public:
unsigned int size;
node* NodeAddress[MAX_NUMBER_OF_LABELS];
struct Item;
class node {
public:
unsigned int val;
node *next;
Item *itemPtr;
node () : val(0), next(0), itemPtr(0) {}
node (const int& a) : val(a), next(0), itemPtr(0) {}
};
struct Item {
public:
node *hd, *tl;
Item(node *shd) : hd(shd), tl(shd) {}
void ListSet::Item::append (const Item* other);
//removal
ListSet::node* remove(node* old);
};
ListSet()
{
this->size = 0;
memset(NodeAddress, 0, sizeof(NodeAddress));
}
void setNodeAddress(const int& a, node* shd)
{
NodeAddress[a] = shd;
}
node* getNodeAddress(const int& a)
{
return NodeAddress[a];
}
ListSet::Item* ListSet::makeSet (const int& a) ;
ListSet::Item* ListSet::find (const int& a);
ListSet::Item* ListSet::unionSets (Item* s1, Item* s2);
void ListSet::unionSets (const int& a1, const int& a2);
};
source
void ListSet::Item::append (const Item* other) {
//join the tail of the set to head of the other set
tl->next = other->hd;
tl = other->tl;
for (node* cur = other->hd; cur; cur = cur->next) {
cur->itemPtr = this;
}
}
ListSet::Item* ListSet::makeSet (const int& a) {
if( a > this->size) {this->size = a;}
assert(!getNodeAddress(a));
node *shd = new node(a);
Item *newSet = new Item(shd);
setNodeAddress(a, shd);
shd->itemPtr = newSet;
return newSet;
}
ListSet::Item* ListSet::find (const int& a) {
node* ptr = getNodeAddress(a);
if (ptr)
return ptr->itemPtr;
return 0;
}
ListSet::Item* ListSet::unionSets (Item* s1, Item* s2) {
Item *set1 = s1;
Item *set2 = s2;
set2->append(set1);
delete set1;
return set2;
}
void ListSet::unionSets (const int& a1, const int& a2) {
Item* s1 = find(a1);
Item* s2 = find(a2);
if (s1 && s2) {
(void) unionSets(s1, s2);
}
}
*EDIT: *
there is something that I have but is not working
ListSet::node* ListSet::Item::remove(node* old) {
if (old == hd) {
if (old == tl) {
assert(! old->next);
return 0;
}
assert(old->next);
hd = old->next;
} else {
node* prev;
for (prev = hd; prev->next != old; prev = prev->next) {
assert(prev->next);
;
}
if (old == tl) {
assert(! old->next);
//
tl = prev;
prev->next = 0;
} else {
assert(old->next);
prev->next = old->next;
}
}
return hd;
}
ListSet::node::~node() {
if (itemPtr) {
if (! itemPtr->remove(this)) {
// Don't leak an empty set.
delete itemPtr;
}
}
}
void ListSet::remove(const int& a) {
node* ptr = getNodeAddress(a);
if (ptr) {
setNodeAddress(a, 0);
delete ptr;
}
// else error?
}
Your code is overly complicated. Here's my take on a disjoint set forest; all memory management can be handled from the outside by putting the sets in a vector. Note that no pointer manipulation is needed, because a set can be uniquely identified by a size_t-typed index into the forest.