karger最小切割算法因大输入而崩溃

时间:2012-07-20 11:35:49

标签: c multidimensional-array

我尝试实施karger Minimum Cut算法(Karger wiki page

到目前为止,我已经在小例子(大小为10的输入)上尝试了我的算法,它似乎有效。但是当我尝试获得更大的输入时,让我们说200.它只是崩溃。

为了存储最小切割数据,我创建了一个2D数组:GraphCut [SIZE_ARRAY] [SIZE_ARRAY_2] 在这种情况下,SIZE_ARRAY = 200,但我找不到SIZE_ARRAY_2的长度。

问题是,SIZE_ARRAY_2必须很大,因为我修改了初始数组以合并不同的顶点。

如果我声明SIZE_ARRAY_2 = 200,则大小不够,但如果我把SIZE_ARRAY_2 = 1000,程序就会崩溃。

问题是,我必须执行算法100000次。

以下是代码的一部分:

#define ARRAY_SIZE 200
#define ARRAY_SIZE_2 200

int main()
{
    int minCut,minMinCut;

    for (int k = 0; k < ARRAY_SIZE * ARRAY_SIZE * 4;k++) {
        minCut = kargerMinCut(k);
        if (k == 0)
            minMinCut = minCut;
        else if (minMinCut > minCut)
            minMinCut = minCut;
    }
    printf("\n minMinCut = %d\n", minMinCut);

    return 0;
}

int kargerMinCut(int k) {
// 1st dimension: each different node
// 2nd dimension: vertices
    long graphCut[ARRAY_SIZE + 1][ARRAY_SIZE_2] = {0};
    populateIntegerArray(graphCut); // import data from a file

    int nodeToMain[ARRAY_SIZE + 1];
    int sizeOfMainNode, indexToMerge,initialRand,i,j,m,nodeToMerge,nodeRemaining = ARRAY_SIZE;
    for (m = 0;m<ARRAY_SIZE + 1;m++) // initialization of nodeToMain
        nodeToMain[m] = m;

    while (nodeRemaining > 2) {
i = 0;
        j = 0;
        srand(time(NULL) + nodeRemaining);// initialise rand
        initialRand = nodeToMain[rand()%(ARRAY_SIZE) + 1]; // pick a random initial node, but not a merged one
        sizeOfMainNode = sizeOfArray(graphCut[initialRand]); // size of the initial node

        srand(time(NULL) + k); // initialise rand
        indexToMerge = rand()%sizeOfMainNode;// pick another random node in the linked nodes (its index to be precise)
        nodeToMerge = nodeToMain[graphCut[initialRand][indexToMerge]];

        for (m = 0;m<ARRAY_SIZE + 1;m++)  // update the nodeToMain array, initialRand is now the main node for nodeToMerge
            if (nodeToMain[m] == nodeToMerge)
                nodeToMain[m] = initialRand;

        // remove the nodeToMerge numbers from the graphCut[initialRand] (as they are going to be merged)
        while(graphCut[initialRand][j] > 0 && j < sizeOfMainNode) {
            if (initialRand == nodeToMain[graphCut[initialRand][j]]) {
                // if this is the last element, do nothing
                while(nodeToMain[graphCut[initialRand][sizeOfMainNode - 1]] == initialRand && j < sizeOfMainNode - 1) {
                    graphCut[initialRand][sizeOfMainNode - 1] = 0;
                    sizeOfMainNode--;
                }
                graphCut[initialRand][j] = nodeToMain[graphCut[initialRand][sizeOfMainNode - 1]];
                graphCut[initialRand][sizeOfMainNode - 1] = 0;
                sizeOfMainNode--;
            }
            j++;
        }

        i = 0;
        while (graphCut[nodeToMerge][i] > 0 && sizeOfMainNode < ARRAY_SIZE_2 && i < ARRAY_SIZE_2) { // add each vextex of the nodeTomerge to the merged nodes
            if (nodeToMain[graphCut[nodeToMerge][i]] != initialRand) {
                graphCut[initialRand][sizeOfMainNode] = nodeToMain[graphCut[nodeToMerge][i]];
                sizeOfMainNode++;
            }
            i++;
        }

        nodeRemaining--;
    }

    return sizeOfArray(graphCut[nodeToMain[1]]);
}

我确信代码不是很干净,甚至可能非常糟糕(C语言中的初学者)。所以我欢迎任何其他建议。

我用调试器得到的错误似乎是随机的。 错误是:

  

无法除以0

它在time64.c第62行停止

tim = (__time64_t)((nt_time.ft_scalar - EPOCH_BIAS) / 10000000i64);

3 个答案:

答案 0 :(得分:2)

数组大小的变化可能导致堆栈溢出。堆栈的常见默认大小为1MB(1048576字节)。如果你有:

long graphCut[200][1000];

4 == sizeof(long) graphCut数组占用200 * 1000 * 4 = 800000个字节,这会留下248576个字节,这对于populateIntegerArray()函数中的堆栈变量可能不够(我没看到那个功能)。如果8 == sizeof(long)则数组将需要1600000个字节,大于1MB。

如果需要该大小的数组,则在堆上而不是堆栈上分配(全部或部分)。例如:

long* graphCut[ARRAY_SIZE_1];
int i;
for (i = 0; i < sizeof(graphCut)/sizeof(graphCut[0]); i++)
{
    graphCut[i] = malloc(ARRAY_SIZE_2 * sizeof(graphCut[0][0]));
    memset(graphCut[i], 0, ARRAY_SIZE_2 * sizeof(graphCut[0][0]));
}

for (i = 0; i < sizeof(graphCut)/sizeof(graphCut[0]); i++)
{
    free(graphCut[i]);
}

答案 1 :(得分:1)

一些可能的问题是整数或堆栈溢出(所以你在正确的站点上)和内存初始化。

这个实现应该在堆上分配graphCut,并在每次调用kargerMin时将其归零,从而解决这些问题。

int minCut, minMinCut;
    // There is a small possibility that ARRAY_SIZE*ARRAY_SIZE*4 exceeds int boundary if 16-bit
    long k;
    long **buffer;
// Allocate graphCut on the heap
buffer = malloc((ARRAY_SIZE + 1)*sizeof(long *));
for (k = 0; k < ARRAY_SIZE + 1; k++)
    buffer[k] = malloc(ARRAY_SIZE_2*sizeof(long));

for (k = 0; k < ARRAY_SIZE * ARRAY_SIZE * 4;k++) {
    minCut = kargerMinCut(k, buffer);
    if (k == 0)
        minMinCut = minCut;
    else if (minMinCut > minCut)
        minMinCut = minCut;
}
printf("\n minMinCut = %d\n", minMinCut);

// Here we free the buffer. We could do it in any order, but
// as it costs nothing here to do so, we free it in reverse-
// allocation-order to avoid any possible memory fragmentation
// - which is moot anyway, if this is a main() and we're exiting
// the program. In other instances it could be relevant.
for (k = 0; k < ARRAY_SIZE + 1; k++)
{
    free(buffer[ARRAY_SIZE-k]); buffer[ARRAY_SIZE-k] = NULL;
}
free(buffer); buffer = NULL;
// The NULLing of the just-freed variables has no purpose except
// to GUARANTEE that any illegal use of them, dangling pointers,
// leftover copies etc. will immediately trigger a core dump and
// be discovered, instead of lurking undetected.

return 0;
}

int kargerMinCut(long k, long **graphCut) {
    // 1st dimension: each different node
    // 2nd dimension: vertices

    // Zero graphCut. If populateIntegerArray rewrites
    // the whole of graphCut, these four lines are redundant.
    int     i, j;
    for (i = 0; i < ARRAY_SIZE + 1; i++)
            for (j = 0; j < ARRAY_SIZE_2; j++)
                    graphCut[i][j] = 0;
    // otherwise, they make sure that no old value of graphCut
    // or uninitialised value is going to linger and potentially
    // corrupt calculations later on.
    populateIntegerArray(graphCut); // import data from a file

答案 2 :(得分:0)

我在C ++中实现了Karger算法。我的下面的代码适用于大文件,但我还没有足够的优化...它仍然可以快速运行..但可以更快..试试这个解决方案。

#include "stdafx.h"
#include <iostream>
#include <stdio.h>
#include <string>
#include <map>
#include <list>
#include <fstream>
#include <sstream>
#include <set>
#include <stdlib.h>
#include <time.h>

int pick_edge(std::map <int, std::list<int>> g2, set<int> myset, int &u, int &v)
{
    std::map <int, std::list<int>>::iterator it;
    std::list<int> eachRow;

    int rand_vertex;
    int rand_edge;

    srand (time(NULL));

    rand_vertex = (rand() + 1) % myset.size() ;
    if (rand_vertex == 0)
        rand_vertex = 1;
    u = get_value_at_i(myset, rand_vertex);

    for (it = g2.begin(); it != g2.end(); ++it) {
        if (it->first == u) {
            eachRow = it->second;
            rand_edge = (rand() + 1) % eachRow.size();
            if (rand_edge == 0)
                rand_edge = 1;
            v = get_edge_at_j(eachRow, rand_edge);
            break;
        }
    }
    return 0;
}




map <int, std::list<int>> merge_uv(map <int, std::list<int>>  g2, int u, int v)
{
    std::map <int, std::list<int>>::iterator it_g;
    std::map <int, std::list<int>>::iterator it_u;
    std::map <int, std::list<int>>::iterator it_v;
    std::list<int>::iterator iter_l;

    std::list<int> eachRow, uRow, vRow;
    std::list<int> newRow;
    int vertex;
    int j = 0;

    map <int, std::list<int>> new_Graph_G;
    vRow.clear();
    uRow.clear();
    eachRow.clear();
    newRow.clear();

    for (it_g = g2.begin(); it_g != g2.end(); ++it_g) {
        vertex = it_g->first;
        eachRow = it_g->second;

        if (vertex == u) {
            uRow = it_g->second;

            it_u = it_g;
            j++;
            continue;
        }
        if (vertex == v) {
            vRow = it_g->second;
            it_v = it_g;
            j++;
            continue;
        }
    }
    if (j == 2) {
        uRow.sort();
        vRow.sort();
        //      uRow.merge(vRow);
        for (std::list<int>::iterator ite = vRow.begin(); ite != vRow.end();  ++ite) {
            if (*ite != u) {
                uRow.push_back(*ite);
            }
        }
        g2.erase(v);
        g2[u] = uRow;
    }

    for (it_g = g2.begin(); it_g != g2.end(); ++it_g) {
        eachRow = it_g->second;
        for (std::list<int>::iterator ite = eachRow.begin(); ite != eachRow.end();  ++ite) {
            if (*ite == v && *ite != it_g->first) {
                newRow.push_back(u);
            } else if (*ite == it_g->first) {
                continue;
            }   else {
                newRow.push_back(*ite);
            }
        }
        new_Graph_G[it_g->first] = newRow;
        newRow.clear();
    }

    for (it_g = g2.begin(); it_g != g2.end(); ++it_g) {
        eachRow = it_g->second;
        if (it_g->first == u) {
            for (std::list<int>::iterator ite = eachRow.begin(); ite != eachRow.end();  ++ite) {
                if (*ite != u && *ite != v) {
                    newRow.push_back(*ite);
                }
            }
            new_Graph_G[it_g->first] = newRow;
            break;
        }
    }

    return new_Graph_G;
}

int get_min_cut(std::map <int, std::list<int>> g1)
{
    int v;
    std::list<int> eachRow;
    std::map <int, std::list<int>>::iterator it_g;
    int min_cut = 0;

    for (it_g = g1.begin(); it_g != g1.end(); ++it_g) {
        eachRow = it_g->second;
        v = it_g->first;
        for (std::list<int>::iterator ite = eachRow.begin(); ite != eachRow.end();  ++ite) {
            if (*ite != v) {
                min_cut++;
            }
        }
        break;
    }

    return min_cut;
}


int EdgeContractionAlgorithm()
{
    std::map <int, std::list<int>>::iterator it;
    int min_cut = 0;
    int vertex = 1;
    std::list<int> eachRow;
    std::set<int> myset;
    std::set<int>::iterator itSet;
    std::map <int, std::list<int>> g2;

    int edge;
    int n_vertices;
    int cnt = 0;
    int u, v;

    n_vertices = Cal_nVertices(myset, Graph_G);
    g2 = Graph_G;

    // Contraction algorithm.
    while (n_vertices > 2) {
        edge = pick_edge(g2, myset, u, v);
        g2 = merge_uv(Graph_G, u, v);

        n_vertices = g2.size();
        myset.erase (myset.find(v));
        Graph_G = g2;
    }

    print_graph(g2);

    min_cut = get_min_cut(g2);
    return (min_cut);
}