递归解决方案无法正常工作/遇到错误

时间:2012-02-08 15:39:26

标签: c++ recursion segmentation-fault stack-overflow

我正在寻找一些关于我之前模糊询问的问题的帮助,这是递归地解决了15-peg solitaire。当我编译并运行它时,我一直遇到奇怪的错误,大多数人说“堆栈溢出”或者我遇到了一个seg错误。这就是我到目前为止,“board [15]”代表15 peg board,“move [36]”代表所有可能的移动。当只剩下一个挂钩时,应该发现递归。

#include <iostream>

using namespace std;                               

void solveGame(int a[15], int b[36][3], int c[15][4]);

void chooseMove (int a[15], int b[36][3], int openSpace, int c[15][4]);

int findEmpty (int a[15]);

int pegCount (int a[15]);

bool isPeg (int peg, int a[15]);

int usedVals[15] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};

int d = 0;

int index = 0;

int main ()
{
    int openSpace = 5;

    int board[15]= {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};

    board[openSpace] = 0;

    int alreadyMoved[15][4];                                                                                                        

    int moves[36][3] = {{0, 1, 3},
                        {0, 2, 5},
                        {1, 3, 6},
                        {1, 4, 8},
                        {2, 4, 7},
                        {2, 5, 9},
                        {3, 6, 10},
                        {3, 7, 12},
                        {3, 1, 0},
                        {3, 4, 5},
                        {4, 7, 11},
                        {4, 8, 13},
                        {5, 9, 14},
                        {5, 8, 12},
                        {5, 2, 0},
                        {5, 4, 3},
                        {6, 3, 1},
                        {6, 7, 8},
                        {7, 4, 2},
                        {7, 8, 9},
                        {8, 4, 1},
                        {8, 7, 6},
                        {9, 5, 2},
                        {9, 8, 7},
                        {10, 6, 3},
                        {10, 11, 12},
                        {11, 7, 4},
                        {11, 12, 13},
                        {12, 7, 3},
                        {12, 8, 5},
                        {12, 11, 10},
                        {12, 13, 14},
                        {13, 8, 4},
                        {13, 12, 11},
                        {14, 9, 5},
                        {14, 13, 12}};


    solveGame(board, moves, alreadyMoved);

    for (int i = 0; i < 13; i++)
        cout << alreadyMoved[i][0] << " " << alreadyMoved[i][1] << " " < <alreadyMoved[i][2] << endl;

    return 0;
}

// main recursive function
void solveGame (int a[15], int b[36][3], int c[15][4]
{
int empSpace;
int moveIndex;

    if (pegCount(a) < 2) {
        cout<<"game over"<<endl;
    } else {
        empSpace = findEmpty(a);
        chooseMove(a, b, empSpace, c);
        solveGame(a, b, c);
    }
}

// supposed to pick a move that is applicable to the board otherwise it find a new move
void chooseMove (int a[15], int b[36][3], int openSpace, int c[15][4])
{
int i = 0;

    while (1) {
        if (i < 36 && b[i][2] == openSpace && isPeg(b[i][0],a) && isPeg(b[i][1],a)) {
            a[b[i][0]] = 0;
            a[b[i][1]] = 0;
            a[b[i][2]] = 1;

            c[d][0] = b[i][0];
            c[d][1] = b[i][1];
            c[d][2] = b[i][2];
            c[d][3] = i;

            d++;

            index = 0;

            for (int v = 0; v < 15; v++)
                usedVals[v] = -1;

            break;
        } else if (i > 35) {
            a[b[c[d-1][3]][0]] = 1;
            a[b[c[d-1][3]][1]] = 1;
            a[b[c[d-1][3]][2]] = 0;

            c[d-1][0] = 0;
            c[d-1][1] = 0;
            c[d-1][2] = 0;
            c[d-1][3] = 0;

            usedVals[index] = openSpace;

            index++;

            int newOpen = findEmpty(a);

            chooseMove(a, b, newOpen, c);
        }

        i++;
    }
}

// counts the pegs on the board in order to cancel recursion
int pegCount (int a[15])
{
    int count = 0;
    for (int i = 0; i < 15; i++)
        if (a[i] == 1)
            count++;
    return count;
}

// finds an empty space that hasn't already been found faulty 
int findEmpty (int a[15])
{
    for (int i = 0; i < 15; i++) {
        for(int j = 0; j < 15; j++) {
            if(a[i] == 0 && i != usedVals[j] && usedVals[j] > -1)
                return i;
        }
    }
}


// tests if current index is a peg 
bool isPeg (int peg, int a[15])
{
    return a[peg] == 1;
}

3 个答案:

答案 0 :(得分:2)

快速浏览显示了许多潜在问题,但我认为这可能归结为您传递数组的方式。数组是通过引用传递的,而不是通过值传递的,因此递归函数使用数组的单个副本,我认为这不是你想要的。因此,您永远不会找到结束移动,这将从无限递归中获得堆栈溢出。

尝试在每个递归级别分配数组的新副本。有些人会希望你使用newmalloc这样做,因为他们觉得C ++的介绍应该是一个火灾的试验,你必须掌握内存管理来做任何有用的事情。相反,我会建议你不要使用数组;使用一个在按值传递时能正常工作的集合类(我认为POD的std :: vector会这样做),集合类将按照你的代码所期望的方式创建数组的副本。

当您真正想要广度优先搜索时,您可能还会遇到在chooseMove中进行深度优先搜索的问题。

答案 1 :(得分:0)

使用递归时堆栈溢出非常常见。这是因为函数调用的返回值存储在堆栈中,只要函数没有返回,堆栈就会保持填充状态。如果递归性太深,你最终会填满整个堆栈并溢出它,这也会导致SEGV。

答案 2 :(得分:0)

通常在退出条件不起作用时会出现堆栈溢出,但是在这里您还要按值传递参数,即使在正常操作中也可能会溢出堆栈。

我建议您在std::vector中通过引用或更好的方式传递数组。 std::vector是一个小对象,它将实际数据保存在堆分配的空间中。你甚至可以归还那些。

我还建议您在调试器中启动程序,这是找出确切错误的最简单,最有效的方法。