递归解决方案未按预期工作/遇到错误

发布于 2025-01-03 16:16:52 字数 4361 浏览 2 评论 0原文

我正在寻求一些帮助来解决我之前隐约询问过的问题,即递归解决 15 针纸牌问题。当我编译和运行它时,我不断收到奇怪的错误,其中大多数都说“堆栈溢出”或者我遇到了段错误。这就是我到目前为止所得到的,其中“board[15]”代表 15 个钉板,“moves[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;
}

I'm looking for some help on a problem that I vaguely inquired about before, which is solving 15-peg solitaire recursively. I keep getting strange errors when I compile and run it, most of them say "stack overflow" or that I'm getting a seg fault. This is what I have so far, where "board[15]" represents the 15 peg board, and "moves[36]" represents all of the possible moves that can be made. The recursion is supposed to spot when there is only one peg left.

#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;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

我恋#小黄人 2025-01-10 16:16:52

快速浏览一下会发现很多潜在的问题,但我认为这可能归结为传递数组的方式。数组是按引用传递的,而不是按值传递的,因此递归函数正在处理数组的单个副本,我认为这不是您想要的。因此,你永远找不到结束动作,这将使你因无限递归而导致堆栈溢出。

尝试在每个递归级别分配一个新的数组副本。有些人会希望你为此使用 newmalloc ,因为他们觉得 C++ 入门应该是一场激烈的考验,你必须掌握内存管理才能做任何事情有用。相反,我建议你根本不要使用数组;使用按值传递时可以正常工作的集合类(我认为 POD 的 std::vector 会执行此操作),并且集合类将按照代码预期的方式创建数组的副本。

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

A quick glance shows a lot of potential problems, but I think it probably boils down to the way you are passing arrays. Arrays are passed by reference and not by value, so the recursive function is working with a single copy of the array, which I don't think is what you want. Therefore you are never finding the ending move, which will get you a stackoverflow from unlimited recursion.

Try allocating a new copy of the arrays at each level of recursion. Some people will want you to use new or malloc for this, because they feel an introduction to C++ should be a trial by fire where you have to master memory management to do anything useful. Instead, I would advise you not to use arrays at all; use a collection class that will work properly when passed by value (I think std::vector of POD will do this) and the collection class will create copies of your arrays the way your code seems to expect.

You may also be having a problem of doing a depth-first search in chooseMove, when you really want a breadth-first search.

孤独患者 2025-01-10 16:16:52

使用递归时堆栈溢出很常见。这是因为函数调用的返回值存储在堆栈中,并且只要函数不返回,堆栈就会一直填满。如果递归太深,最终会填满整个堆栈并使其溢出,这也会导致 SEGV。

Stack overfow when using recursivity is pretty common. This is due to the fact that return values for function calls are stored into the stack, and the stack keeps filling as long as function does not return. If the recursivity goes too deep, you end up filling your whole stack and overflowing it, which also causes SEGV.

月寒剑心 2025-01-10 16:16:52

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

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

我还建议您在调试器中启动程序,这是找出到底出了什么问题的最简单、最有效的方法。

Usually you get a stack overflow when your exit condition does not work, but here you are also passing your parameters by value, which might overflow your stack even in normal operation.

I suggest you pass your arrays by reference or better in a std::vector. An std::vector is a small object that holds the real data in a heap allocated space. You can even return those.

I also suggest that you start your program in a debugger, that is the simplest and most effective way to find out what exactly is going wrong.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文