0

This is my implementation of Disjoint Sets according with Cormen (Introduction to Algorithms - 2nd Ed. chapter 21).
I'm having problem when deleting objects (the "~DisjointSet" destructor).
This occurs because the registers of "std::vector sets;" may points to the same "MetaSet*".

#include <vector>
#include <string>
#include <iostream>
#include <sstream>

#define WEIGHTED_UNION_HEURISTIC

class DisjointSetLinkedList
{
    class LinkedListSet
    {
        int pos;
        LinkedListSet * parent;
        LinkedListSet * next;

    public:
        LinkedListSet(int pos) :
            pos(pos),
            parent(this),
            next(NULL)
        {
        }

        LinkedListSet * getParent()
        {
            return parent;
        }

        void setParent(LinkedListSet *  node)
        {
            this->parent = (LinkedListSet *)node;
        }

        LinkedListSet * getNext()
        {
            return next;
        }

        void setNext(LinkedListSet *  node)
        {
            this->next = (LinkedListSet *)node;
        }

        int getPos()
        {
            return pos;
        }
    };

    class MetaSet
    {
    #ifdef WEIGHTED_UNION_HEURISTIC
        int size;
    #endif
        LinkedListSet * head;
        LinkedListSet * tail;

    public:
        MetaSet(LinkedListSet * head_, LinkedListSet * tail_) :
        #ifdef WEIGHTED_UNION_HEURISTIC
            size(1),
        #endif
            head(head_),
            tail(tail_)
        {
        }

    #ifdef WEIGHTED_UNION_HEURISTIC
        int getSize()
        {
            return size;
        }

        void setSize(int size_)
        {
            this->size = size_;
        }
    #endif

        LinkedListSet * getHead()
        {
            return head;
        }

        LinkedListSet * getTail()
        {
            return tail;
        }

        void setHead(LinkedListSet * head)
        {
            this->head = head;
        }

        void setTail(LinkedListSet * tail)
        {
            this->tail = tail;
        }
    };

    std::vector<MetaSet*> sets;

public:

    DisjointSetLinkedList(int size)
    {
        make_set(size);
    }

    virtual ~DisjointSet()
    {
        for(unsigned int i = 0 ; i < sets.size() ; i++)
        {
            MetaSet * meta = sets[i];
            Set * node = meta->getHead();
            while(node!=NULL)
            {
                Set * temp  = node;
                node = node->getNext();
                delete temp;
            }
            meta->setHead(NULL);
            meta->setTail(NULL);
        }

        // The error occurs here
    //  for(unsigned int i = 0 ; i < sets.size() ; i++)
    //      delete sets[i];

        sets.clear();
    }

    void union_sets(unsigned int idx_left, unsigned int idx_right)
    {
        if(idx_left >= sets.size() ||
                idx_right >= sets.size())
            return;

        MetaSet * set_left = find_set(idx_left);
        MetaSet * set_right = find_set(idx_right);

        if(set_left == set_right)
            return;

    #ifdef WEIGHTED_UNION_HEURISTIC
        if(set_left->getSize() <
            set_right->getSize())
        {
            MetaSet * temp = set_left;
            set_left = set_right;
            set_right = temp;
        }

        set_left->setSize(
                set_left->getSize() +
                set_right->getSize()
        );
    #endif

        set_left->getTail()->setNext(
                set_right->getHead());

        set_left->setTail(
                set_right->getTail());

        LinkedListSet * node = set_right->getHead();

        while(node != NULL)
        {
            sets[node->getPos()] = set_left;
            node->setParent(set_left->getHead());
            node = node->getNext();
        }
        delete set_right;
    }

    void print_list()
    {
        std::cout << "| ";
        for(unsigned int i = 0 ; i < sets.size() ; i++)
            std::cout << sets[i]->getHead()->getPos() << " | ";
        std::cout << std::endl;
    }

private:
    void make_set(int size)
    {
        for(int i = 0 ; i < size ; i++)
        {
            LinkedListSet * node = new LinkedListSet(i);
            sets.push_back(new MetaSet(node, node));
        }
    }

    MetaSet * find_set(int i)
    {
        return sets[i];
    }
};

int main()
{
    {
    DisjointSet disjoint_set(8);
    disjoint_set.print_list();

    disjoint_set.union_sets(0, 7);
    disjoint_set.print_list();
    disjoint_set.union_sets(3, 4);
    disjoint_set.print_list();
    disjoint_set.union_sets(0, 3);
    disjoint_set.print_list();
    disjoint_set.union_sets(0, 5);
    disjoint_set.print_list();
    }

    std::cout << "Objects deleted!";
}
lopes
  • 549
  • 5
  • 13
  • Have you debugged the code? – PaulMcKenzie Apr 20 '14 at 22:33
  • I was able to run the code you posted on my machine without any errors. – R Sahu Apr 20 '14 at 22:34
  • @lopes - Your design is flawed. You have the differing containers storing the same address. When you call `delete`, you must make sure that all of those containers are adjusted to remove the pointer that was just deleted. Time to learn about smart pointers (shared_ptr, for example), or redesign so that you're not storing the same pointer in different containers. – PaulMcKenzie Apr 20 '14 at 23:01
  • @RSahu - The issue is the lines in the comments. But even so, even with those commented lines, there seems to be a memory leak. So basically the code is flawed with or without those lines commented out. – PaulMcKenzie Apr 20 '14 at 23:04
  • @lopes - You can start by using `std::list` instead of making up a class called `LinkedListSet` and having to reinvent the wheel of creating a linked list. – PaulMcKenzie Apr 20 '14 at 23:09
  • Smart-pointers and std::list are a good idea, but this is a exercise for representing the content of chapter 21 of Cormen coded for master's degree course with minimum of resources. Thank you. – lopes Apr 21 '14 at 12:44
  • I will not call it cheating to get your code working with the help from STL (or whatever existing libraries) first. You can remove dependency to existing libraries by replacing them with your own implementation one by one. With this approach, you will also learn what is modular design. Also note that not many people here have a copy of *Introduction to Algorithms* on their desk. You need to explain what you want to achieve with your code. – nodakai Apr 21 '14 at 18:05
  • @lopes - Your code goes beyond just a linked list. You would be using a std::list to implement a higher-level data structure. There is nothing wrong with that. No different than coding an n-ary tree (which doesn't exist in standard C++), and use vectors or lists to represent the nodes and the child nodes. – PaulMcKenzie Apr 21 '14 at 19:21

0 Answers0