1

I wrote a program to for percolation using union find (see here for details)

Union find:

#include<iostream>

class UF {
    protected:
        int N;
        int *connections;
        int *sz;
        int *maxObj;
        int numComponents;

        int _getRoot(int p) {
            while(p != connections[p]) {
                // Path compression
                connections[p] = connections[connections[p]];
                p = connections[p];
            }
            return p;
        }

    public:
        UF() {}

        // Parametrized constructor
        UF(int n) {
            N = numComponents = n;
            connections = new int[n];
            maxObj = new int[n];
            sz = new int[n];
            for(int i = 0; i<n; i++) {
                connections[i] = i;
                sz[i] = 1;
                maxObj[i] = i;
            } 
        }

        // ~UF() {
        //     delete [] connections;
        //     delete [] sz;
        //     delete [] maxObj;
        // }

        int findMax(int i) {
            int root = _getRoot(i);
            return maxObj[root];
        }

        int isConnectedGraph() {
            std::cout << "No of components: " << numComponents << std::endl;
            return numComponents == 1;
        }

        bool isConnected(int p, int q) {
            return connections[p] == connections[q];
        }

        bool find(int p, int q) {
            return _getRoot(p) == _getRoot(q);
        }

        void quickFind(int p, int q) {
            // Eager algorithm
            int label_p = connections[p];
            int label_q = connections[q];
            for(int i=0; i<N; i++) {
                if(connections[i] == label_p || connections [i] == label_q) {
                    connections[i] = label_q;
                }
            }
        }

        void quickUnion(int p, int q) {
            // Lazy approach
            if(!isConnected(p, q)) {
                int p_root = _getRoot(p); 
                int q_root = _getRoot(q);
                int max = p_root > q_root ? p_root : q_root;
                // Weighted quick union
                if(sz[p_root] < sz[q_root]) {
                    connections[p_root] = q_root;
                    sz[q_root] += sz[p_root];
                    maxObj[q_root] = max;
                } else {
                    connections[q_root] = p_root;
                    sz[p_root] += sz[q_root];
                    maxObj[p_root] = max;
                }
                numComponents -= 1;
            }
        }

        void printConnectedComponents() {
            std::cout << "Indices:" << std::endl;
            for (int i = 0; i < N; i++) {
                std::cout << i << " ";
            }
            std::cout << std::endl;
            std::cout << "Connections:" << std::endl;
            for (int i = 0; i < N; i++) {
                std::cout << connections[i] << " ";
            }
            std::cout << std::endl;
            std::cout << "Sizes:" << std::endl;
            for (int i = 0; i < N; i++) {
                std::cout << sz[i] << " ";
            }
            std::cout << std::endl;
        }
};

Percolation:

#include "../union-find.h"

class Percolation {
    private:
        int **grid;
        int N;
        UF uf;
        int totalOpenSites;
        int site(int row, int col) {
            if(row == 0) {
                return 0;
            }
            if(row == N-1) {
                return (N*N)-(2*N)+1;
            }
            return ((row-1)*N)+col+1;
        }
    public:
        Percolation(int n) {
            N = n;
            grid = new int*[n];
            for (int i=0; i < n; i++) {
                grid[i] = new int[n];
                for(int j=0; j<n; j++) {
                    grid[i][j] = 0;               
                }
            }
            uf = UF((n*n)-(2*n)+2);
            totalOpenSites=0;
        }

        ~Percolation() {
            for (int i=0; i<N; i++) {
                delete [] grid[i];
            }
            delete [] grid;
        }

        void open(int row, int col) {
            if(!isOpen(row, col)) {
                int center = site(row, col);
                // std::cout << "Center site: " << center << std::endl;
                grid[row][col]=1;
                if(row-1 >= 0 && grid[row-1][col]) {
                    int north = site(row-1, col);
                    // std::cout << "North site: " << north << std::endl;
                    uf.quickUnion(center, north);
                }
                if(row+1 < N && grid[row+1][col]) {
                    int south = site(row+1, col);
                    // std::cout << "South site: " << south << std::endl;
                    uf.quickUnion(south, center);
                }
                if(col-1 >= 0 && grid[row][col-1]) {
                    int west = site(row, col-1);
                    // std::cout << "West site: " << west << std::endl;
                    uf.quickUnion(center, west);
                }
                if(col+1 < N &&grid[row][col+1]) {
                    int east = site(row, col+1);
                    // std::cout << "East site: " << east << std::endl;
                    uf.quickUnion(east, center);
                }
                totalOpenSites += 1;
            }
        }

        bool isOpen(int row, int col) {
            return grid[row][col] == 1;
        }

        bool isFull(int row, int col) {
            return uf.find(0, site(row, col));
        }

        int numberOfOpenSites() {
            return totalOpenSites;
        }

        bool percolates() {
            return uf.find(0, (N*N)-2*N+1);
        }

        void printGrid() {
            for(int i=0; i<N; i++) {
                for(int j=0; j<N; j++) {
                    std::cout << grid[i][j] << " ";                
                }
                std::cout << std::endl;
            }
        }

        void printUF() {
            uf.printConnectedComponents();
        }
};

percolation.cpp

#include "percolation.h"

int main() {
    Percolation p = Percolation(3);
    std::cout << "Initiate..." << std::endl;
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "Open (0, 1):" << std::endl;
    p.open(0, 1);
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "Open (0, 2):" << std::endl;
    p.open(0, 2);
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "Open (1, 0):" << std::endl;
    p.open(1, 0);
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "Open (1, 1):" << std::endl;
    p.open(1, 1);
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "Open (2, 2):" << std::endl;
    p.open(2, 2);
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "Open (1, 2):" << std::endl;
    p.open(1, 2);
    p.printGrid();
    p.printUF();
    std::cout << std::endl;

    std::cout << "No of open sites: " << p.numberOfOpenSites() << std::endl;

    bool percolates = p.percolates();
    std::cout << "Percolates???" << "";
    if(percolates) {
        std::cout<<"YESSS!! :)";
    } else {
        std::cout<<"NO... :(";
    }
    return 0;
}

When I add destructor to union find class and run percolation.cpp. I'm getting weird results with garbage values in class members connections, sz, maxObj of union find class. When I remove the destructor, it's working fine.

Output without destructor:

Initiate...
0 0 0
0 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
0 1 2 3 4
Sizes:
1 1 1 1 1

Open (0, 1):
0 1 0
0 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
0 1 2 3 4
Sizes:
1 1 1 1 1

Open (0, 2):
0 1 1
0 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
0 1 2 3 4
Sizes:
1 1 1 1 1

Open (1, 0):
0 1 1
1 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
0 1 2 3 4
Sizes:
1 1 1 1 1

Open (1, 1):
0 1 1
1 1 0
0 0 0
Indices:
0 1 2 3 4
Connections:
2 2 2 3 4
Sizes:
1 1 3 1 1

Open (2, 2):
0 1 1
1 1 0
0 0 1
Indices:
0 1 2 3 4
Connections:
2 2 2 3 4
Sizes:
1 1 3 1 1

Open (1, 2):
0 1 1
1 1 1
0 0 1
Indices:
0 1 2 3 4
Connections:
2 2 2 2 2
Sizes:
1 1 5 1 1

No of open sites: 6
Percolates???YESSS!! :)

Output with destructor:

Initiate...
0 0 0
0 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
7502560 7503664 2 3 4
Sizes:
7474272 7503808 1 1 1

Open (0, 1):
0 1 0
0 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
7502560 7503664 2 3 4
Sizes:
7474272 7503808 1 1 1

Open (0, 2):
0 1 1
0 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
7502560 7503664 2 3 4
Sizes:
7474272 7503808 1 1 1

Open (1, 0):
0 1 1
1 0 0
0 0 0
Indices:
0 1 2 3 4
Connections:
7502560 7503664 2 3 4
Sizes:
7474272 7503808 1 1 1

Open (1, 1):

The program doesn't even complete running when I add the destructor to union find class. Why is this happening?

troglodyte07
  • 3,598
  • 10
  • 42
  • 66
  • You can't use `*alloc` with `delete`. You need `new[]`/`delete[]` or `*alloc`/`free`. – NathanOliver Nov 28 '19 at 16:51
  • Not only the bug here is using `delete` with `malloc`, the shown code also violates the rule of three. – Sam Varshavchik Nov 28 '19 at 16:51
  • Used new[] instead of calloc. Pls see the updated code. Still facing the issue. I'll read up about the rule of three. I'm not aware of what that is. – troglodyte07 Nov 28 '19 at 16:54
  • I've added it to the dupe link target. You need a copy constructor for `Percolation p = Percolation(3);` to work correctly. – NathanOliver Nov 28 '19 at 16:55
  • " I'll read up about the rule of three. I'm not aware of what that is." that's why you should use `std::vector` which written by people who is aware. – Slava Nov 28 '19 at 17:12

0 Answers0