我尝试写一个循环而不是递归函数

时间:2019-04-25 11:37:57

标签: c++ algorithm

我尝试在阵列中找到簇。例如,我有这样的数组:

0 0 0 0 0
0 2 3 0 1
0 8 5 0 7
7 0 0 0 4

启动程序后,它将打印以下结果:

Cluster 1: <2,3,8,5,7>

Cluster 2: <1,7,4>

我已经创建了递归函数来解决此问题:

void DFS(int x, int y)
{
  printf("%d ", g[x][y]);
  g[x][y] = 0;
  // iterate over neighbours
  for(dx=-1; dx<=1; dx++)
    for(dy=-1; dy<=1; dy++)
      if (g[x+dx][y+dy]) DFS(x+dx, y+dy);
}

for(i=0; i<n; i++)
  for(j=0; j<n; j++)
    if (g[i][j])
    {
      DFS(i, j);
      printf("\n");
    }

但是有一个问题:我需要处理特大数组,因此当递归函数调用其自身约1000次以上时,该程序将出现错误“堆栈溢出”。

因此,我需要在不使用递归函数的情况下重新制作此代码。 我尝试使用列表,cicle等,但无法正常工作。

你能告诉我,我该怎么做?

再次尝试解释:

// random_number_gererator.cpp: определяет точку входа для консольного приложения.
//

#include "stdafx.h"
#include <ctime>
#include <iostream>
#include <fstream>

//Задаем максимально возможный размер стека
#pragma comment(linker, "/STACK:100000000000")

using namespace std;

const int k = 2;                                        //размерность массива
const int N = k * k * k;                                //количество элементов, которые необходимо сгенерировать
int number0 = 0, number1 = 0;

int generation(float probability);                      //прототип функции генерации псевдослучайных чисел
int create_array();                                     //прототип функции создания трехмерного массива

int ***ptrarray = new int **[k];                        //указатель на трехмерный массив

ofstream fout("clusters.txt");

int find_and_write_clusters(int X, int Y, int Z);       //прототип функции поиска кластеров

int main()
{

    setlocale(LC_ALL, "rus");                           //установка русской кодировки
    int err = create_array();                           //вызов функции создания трехмерного массива
                                                        //cout << err<<endl;
    generation(0.3);                                    //функция генерации и заполнения массива
                                                        //После генерации данные заполнились в массив ptrarray[][][]

    for (int X = 0; X < k; X++) {
        for (int Y = 0; Y < k; Y++) {
            for (int Z = 0; Z < k; Z++) {
                if (ptrarray[X][Y][Z] == 1) {
                    find_and_write_clusters(X, Y, Z);   //вызываем рекурсивную функцию поиска и записи кластеров
                    fout << endl;
                    fout << endl;
                }
            }
        }
    }
    fout.close();
    system("pause");
    return 0;
}

int generation(float probability) {
    int prob_persent = ceil(probability * 10000);       //введенная пользователем вероятность, в процентах до 10 000 (для большей точности)
    int T;
    if (probability > 1 || probability < 0) return 1;

    for (int X = 0; X < k; X++) {
        for (int Y = 0; Y < k; Y++) {
            for (int Z = 0; Z < k; Z++) {
                T = 0 + rand() % 10001;
                if (T <= prob_persent) {
                    ptrarray[X][Y][Z] = 1;
                }
                else {
                    ptrarray[X][Y][Z] = 0;
                }
            }
        }
    }
    for (int X = 0; X < k; X++) {
        for (int Y = 0; Y < k; Y++) {
            for (int Z = 0; Z < k; Z++) {
                cout << ptrarray[X][Y][Z];
            }
            cout << endl;
        }
        cout << endl;
    }

    return 0;
}
int create_array() {
    for (int X = 0; X < k; X++) {
        ptrarray[X] = new int *[k];
        for (int Y = 0; Y < k; Y++) {
            ptrarray[X][Y] = new int[k];
        }
    }
    return 0;
}


int find_and_write_clusters(int X, int Y, int Z) {
    if (ptrarray[X][Y][Z] == 1) {
        //Здесь проверить, есть ли такой элемент в файле
        fout << X << ";" << Y << ";" << Z << " ";
        //Заменяем текущий элемент на 0, чтобы он больше не обрабатывался
        ptrarray[X][Y][Z] = 0;
        if (X + 1 < k) find_and_write_clusters(X + 1, Y, Z);
        if (Y + 1 < k) find_and_write_clusters(X, Y + 1, Z);
        if (Z + 1 < k) find_and_write_clusters(X, Y, Z + 1);

        if (X - 1 >= 0) find_and_write_clusters(X - 1, Y, Z);
        if (Y - 1 >= 0) find_and_write_clusters(X, Y - 1, Z);
        if (Z - 1 >= 0) find_and_write_clusters(X, Y, Z - 1);
    }
    return 0;
}

这是完整代码。在此程序中,我们的程序生成3D数组,并在其中填充“ 0”和“ 1”数字。 之后,程序使用这种算法找到簇(例如,我们制作了2 * 2 * 2数组:

10
01

11
00

这里我们有2层,总共8个元素(2 * 2 * 2)。

如何查找群集: 我们扫描数组并调用函数find_and_write_clusters。如果元素等于“ 1”,则在相邻元素中调用此函数。等等。

现在,如果您要编译并运行此代码,您将获得包含两行的文件“ clusters.txt”。我会尽力为您绘画

enter image description here

2 个答案:

答案 0 :(得分:1)

您的描述So I need to remake this code without usage of recursive functions. I tried to use lists, cicles and so on, but it doesn't work properly.非常模糊。

如果您通过递归代码的简化示例(例如,固定数组,随机生成确实与问题无关)来开始问题,那就更好了,然后还包含{ 1}}试试。这样我们可以更轻松地帮助您学习。

无论如何,这里是函数的一个版本,它是将递归版本直接转换为将数据存储在堆上的形式。如果doesn't work properly不适合您的用例,那么您可以使用其他数据结构,但是我认为它可能直到真正大时才可用。

vector

但是您的方法开始时效率很低。您可以使用Two-pass approach来节省很多复杂性(尽管我猜想对于3D,您需要跨层合并连接的2d标签,但仍比您现在正在做的所有分支和缓存丢失便宜)像您现在所做的那样,不规则地遍历每个标签的数据。

编辑:如果lambda令人困惑,则该代码等效于不带lambda的该版本

int find_and_write_clusters(int X, int Y, int Z) {
    struct IState {
        int X, Y, Z, step;
    };
    std::vector<IState> remaining;
    auto insertIfOne = [&remaining](int X, int Y, int Z) {
        if (ptrarray[X][Y][Z] == 1) {
            fout << X << ";" << Y << ";" << Z << " ";
            ptrarray[X][Y][Z] = 0;
            remaining.emplace_back(IState{ X, Y, Z, 0 });
        }
    };
    insertIfOne(X, Y, Z);
    while (!remaining.empty())
    {
        auto& c = remaining.back();//current
        switch (c.step++)
        {
        case 0:
            if (c.X + 1 < k) insertIfOne(c.X + 1, c.Y, c.Z);
            break;
        case 1:
            if (c.Y + 1 < k) insertIfOne(c.X, c.Y + 1, c.Z);
            break;
        case 2:
            if (c.Z + 1 < k) insertIfOne(c.X, c.Y, c.Z + 1);
            break;
        case 3:
            if (c.X - 1 >= 0) insertIfOne(c.X - 1, c.Y, c.Z);
            break;
        case 4:
            if (c.Y - 1 >= 0) insertIfOne(c.X, c.Y - 1, c.Z);
            break;
        case 5:
            if (c.Z - 1 >= 0) insertIfOne(c.X, c.Y, c.Z - 1);
            break;
        default:
            remaining.pop_back();
        }
    }
    return 0;
}

答案 1 :(得分:-7)

每个递归构造都可以用堆栈构造代替,反之亦然。尝试用堆栈数据类型替换递归逻辑。

这是C#,但是此概念适用于所有语言:https://haacked.com/archive/2007/03/04/Replacing_Recursion_With_a_Stack.aspx/