首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于利用递归给二维数组赋值的一个有关问题

2013-06-26 
关于利用递归给二维数组赋值的一个问题本帖最后由 u011209118 于 2013-06-26 09:53:05 编辑用递归方法编写

关于利用递归给二维数组赋值的一个问题
本帖最后由 u011209118 于 2013-06-26 09:53:05 编辑 用递归方法编写了一个给二维数组赋值的程序,但是运行时或提示发生堆栈溢出的错误,程序如下:
如果程序中row和col设置的很小,比如20,程序是可以运行的。请各位高手帮忙看看问题出在那里。

#include "stdafx.h"
#include <iostream>
#include <fstream>
using namespace std;

//如果row和col较小,程序可以运行
int row = 80;
int col = 80;
void regionGrow(int **imgFlag, int x, int y);
int _tmain(int argc, _TCHAR* argv[])
{
int **imgFlag = new int*[row];
for (int i=0; i<row; i++) {
imgFlag[i] = new int[col];
}
for (int i=0; i<row; i++) {
for (int j=0; j<col; j++) {
imgFlag[i][j] = 0;
}
}
regionGrow(imgFlag, col/2, row/2);
return 0;
}

void regionGrow(int **imgFlag, int x, int y)
{
if (imgFlag[y][x]==0)
imgFlag[y][x] = 1;
else
return;

if (x>0 && imgFlag[y][x-1]!=1) regionGrow(imgFlag, x-1, y);
if (y>0 && imgFlag[y-1][x]!=1) regionGrow(imgFlag, x, y-1);
if (x<col-1 && imgFlag[y][x+1]!=1) regionGrow(imgFlag, x+1, y);
if (y<row-1 && imgFlag[y+1][x]!=1) regionGrow(imgFlag, x, y+1);
} 递归 二维数组 C++
[解决办法]
递归次数过多导致堆栈溢出
要么限制递归次数,要么自己保存递归状态
[解决办法]
“给定一个小点的输入,完整单步跟踪(同时按Alt+7键查看Call Stack里面从上到下列出的对应从里层到外层的函数调用历史)一遍。”是理解递归函数工作原理的不二法门!
递归函数关注以下几个因素
·退出条件
·参数有哪些
·返回值是什么
·局部变量有哪些
·全局变量有哪些
·何时输出
·会不会导致堆栈溢出

[解决办法]
把你的代码如下修改后运行:


[code=c]
#include <iostream>
#include <fstream>
#include <cassert>

using namespace std;

int row = 1000;
int col = 1000;
void regionGrow(int **imgFlag, int x, int y, unsigned int level);
int main(int argc, char* argv[])
{
    int **imgFlag = new int*[row];
    for (int i=0; i<row; i++)
    {
        imgFlag[i] = new int[col];
    }
    for (int i=0; i<row; i++)
    {
        for (int j=0; j<col; j++)
        {
            imgFlag[i][j] = 0;
        }
    }
    regionGrow(imgFlag, col/2, row/2, 1);


    return 0;
}

void regionGrow(int **imgFlag, int x, int y, unsigned int level)
{
    assert( x >= 0 && x < col );
    assert( y >= 0 && y < row );
    std::cerr << ++level << '\n';
    
    if (imgFlag[y][x]==0)
        imgFlag[y][x] = 1;
    else
        return;

    if (x>0 && imgFlag[y][x-1]!=1) regionGrow(imgFlag, x-1, y, level);
    if (y>0 && imgFlag[y-1][x]!=1) regionGrow(imgFlag, x, y-1, level);
    if (x<col-1 && imgFlag[y][x+1]!=1) regionGrow(imgFlag, x+1, y, level);
    if (y<row-1 && imgFlag[y+1][x]!=1) regionGrow(imgFlag, x, y+1, level);
}


最后出错时递归了65080层。
改用栈实现吧。选择递归算法时一定要预估一下可能的递归深度,如果太深的话就改用栈结构来模拟。

[解决办法]
改用栈结构实现的代码:

#include <iostream>
#include <fstream>
#include <cassert>
#include <stack>
#include <utility>
#include <algorithm>

using namespace std;

int row = 300;
int col = 300;
void regionGrow(int **imgFlag, int x, int y);
int main(int argc, char* argv[])
{
    int **imgFlag = new int*[row];
    for (int i=0; i<row; i++)
    {
        imgFlag[i] = new int[col];
    }
    for (int i=0; i<row; i++)
    {
        for (int j=0; j<col; j++)
        {
            imgFlag[i][j] = 0;
        }
    }
    regionGrow(imgFlag, col/2, row/2);
    return 0;
}

void regionGrow(int **imgFlag, int x, int y)
{
    std::stack<std::pair<int, int> > point_stack;
    if( imgFlag[y][x] == 0)
    {
        point_stack.push( pair<int, int>( x, y ));
    }
    
    unsigned int level = 0; //这行代码将来要删掉
    while( !point_stack.empty())
    {
        level = std::max( level, point_stack.size());//这行代码将来要删掉
        std::cerr << '\r' << level << "                ";//这行代码将来要删掉
        


        int x = point_stack.top().first;
        int y = point_stack.top().second;
        point_stack.pop();
        
        assert( x >= 0 && x < col );
        assert( y >= 0 && y < row );
        
        imgFlag[y][x] = 1;
        
        //为了让数据处理数据和原来的代码相同,我这里把判断顺序倒过来了
        //因为处理时后入栈的先处理。
        if (y<row-1 && imgFlag[y+1][x]!=1) point_stack.push( std::pair<int,int>(x, y+1));
        if (x<col-1 && imgFlag[y][x+1]!=1) point_stack.push(std::pair<int,int>( x+1, y));
        if (y>0 && imgFlag[y-1][x]!=1) point_stack.push(std::pair<int,int>( x, y-1));
        if (x>0 && imgFlag[y][x-1]!=1) point_stack.push(std::pair<int,int>( x-1, y));
    }
    
}



point_stack.size的最大值是89402,也就是需要递归89402层。

你这个递归设计得严重不平衡,如果把代码中递归的过程组织成一棵树,你会发现棵树几乎始化成了一个链表,所有节点最聚集在最左边的那个链上。

因此,如果用递归实现“全矩阵置1”,最好给每一层递归设置上方向限制:


#include <iostream>
#include <fstream>
#include <cassert>
#include <algorithm>
using namespace std;
int row = 1000;
int col = 1000;
const int dir_left = 1;
const int dir_right = 2;
const int dir_up = 3;
const int dir_down = 4;
const int dir_all = dir_left 
[解决办法]
 dir_right 
[解决办法]
 dir_up 
[解决办法]
 dir_down;
unsigned int max_level = 0;
void regionGrow(int **imgFlag, int x, int y, int dir, unsigned int level);

bool check_result(int **imgFlag)
{
   bool ok = true;
   int x = 0;
   while( ok && x < col )
   {
        int y = 0;
        while( ok && y < row )
        {
            ok = ( imgFlag[y][x] == 1);
            ++ y;
        }
        ++ x;
   }
   return ok;
}

int main(int argc, char* argv[])
{
    int **imgFlag = new int*[row];


    for (int i=0; i<row; i++)
    {
        imgFlag[i] = new int[col];
    }
    for (int i=0; i<row; i++)
    {
        for (int j=0; j<col; j++)
        {
            imgFlag[i][j] = 0;
        }
    }
    regionGrow(imgFlag, col/2, row/2, dir_all, 1);
    assert(check_result(imgFlag));
    std::cout << "Max level:" << max_level << '\n';
    
    return 0;
}


void regionGrow(int **imgFlag, int x, int y, int dir, unsigned int level)
{
    assert( x >= 0 && x < col );
    assert( y >= 0 && y < row );
    max_level = std::max(level ++, max_level);
    if (imgFlag[y][x]==0)
        imgFlag[y][x] = 1;
    else
        return;
    if ( (dir & dir_left) && (x>0) && (imgFlag[y][x-1]!=1) )
        //允许向左,并且未到左边界,并且左边需要处理
    {
        regionGrow(imgFlag, x-1, y, dir & ~dir_right, level );//下一步不允许向右
    }
    if ( (dir & dir_up) && (y>0) && (imgFlag[y-1][x]!=1) )
        //允许向上,并且未到上边界,并且上边需要处理
    {
        regionGrow(imgFlag, x, y-1, dir & ~dir_down, level);//下一步不允许向下
    }
    if ( (dir & dir_right) && (x<col-1) && (imgFlag[y][x+1]!=1) )
        //允许向右,并且未到右边界,并且右边需要处理
    {
        regionGrow(imgFlag, x+1, y, dir & ~dir_left, level);//下一步不允许向左
    }
    if ( (dir & dir_down) && (y<row-1) && (imgFlag[y+1][x]!=1) ) 
        //允许向规划,并且未到下边界,并且下边需要处理
    {
        regionGrow(imgFlag, x, y+1, dir & ~dir_up, level);//下一步不允许向上
    }
}


这样最大递归深度为1001。
[解决办法]
没注意到上面的代码中行列数不一样。

用MinGW4.7.1编译,在递归65080层时栈溢出,改为300*300行后用栈结构模拟判断最大递归深度为89402。

设置方向限制之后,1000*1000最大递归层数是1001,300*300最大递归导数是301,1000*100时最大递归层数是551

热点排行