不使用goto语句重写程序

时间:2010-10-06 23:54:28

标签: c++ algorithm

我不得不使用goto语句编写类似的问题。现在我们被要求在不使用goto语句的情况下重写代码。我不知道如何开始这个程序。我使用goto粘贴以前的程序代码。

// Eight Queens problem using one dimesional array and goto statement

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


int main()
{
    int q[8];
    q[0] = 0;
    int c = 0;
    int count = 0;

NC: //cout  << "Next column\n" << "Column = " << c << endl;
    c++;
    if (c == 8) goto print;
    q[c] = -1;

NR: //cout << "Next row\n" << "Row = " << q[c] << "\nColumn = " << c << endl;
    q[c]++;
    if (q[c] == 8) goto backtrack; 
    for(int i = 0; i < c; i++){
        if(q[i] == q[c] || abs(q[c] - q[i]) == (c - i))
            goto NR;
    }
    goto NC;

backtrack:
    //cout << "Backtrack" << endl;
    //cout <<"Column = " << c << endl;
    c--;
    if(c == -1) return 0;
    goto NR;

print:
    //cout << "print" << endl;
    ++count;
    cout << count << endl;
    for(int i = 0; i <= 7; i++){
            cout << q[i];
    }
    cout << endl;
    goto backtrack;


    return 0;
}

这个程序是教授为课程发布的一个提示。

 #include <iostream>
    #include<cstdlib>
    #include <cmath>
    using namespace std;

    bool ok(int q[], int col){
    if the configuration is “bad” return false;
    else
    return true;
    }

    void backtrack(int &col){
    col--;
    if(col==-1) exit(1);
    }

    void print(int q[]){
    static int count =0;
    print the array q
    }

    int main(){
    int q[8]; q[0]=0;
    int c=1;
    // from_backtrack keeps track if we need to reset the row to the
    // top of the current colum or not.

    bool from_backtrack=false;
    // The outer loop keeps looking for solutions
    // The program terminates from function backtrack
    // when we are forced to backtack into column -1
    while(1){
    while(c<8){ //this loop goes across columns
    // if we just returned from backtrack, use current value of row
    // otherwise get ready to start at the top of this column
    if(!from_backtrack) // we did not just return from backtrack
    Code goes here
    from_backtrack=false;
    while(q[c]<8){ // place queen in this column
    q[c]++;
    // if row=8, there is no valid square in this column
    // so backtrack and continue the loop in the previous column
    Code goes here
    //if this position is ok, place the queen
    // and move on (break) to the next column,
    // otherwise keep looking in this column
    Code goes here
    }
    c++; // placed ok, move to the next column
    }
    // one complete solution found, print it.
    print(q); // board completed, print it out
    backtrack(c);
    from_backtrack=true;
    }
    }

这是我为完成该计划所做的尝试

// NoGoto.cpp.cpp : Defines the entry point for the console application.
//

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



bool attack(int q[], int col){
    if(q[i] == q[c] || abs(q[c] - q[i]) == (c - i)) return false;
    else
        return true;
} // Attack

void backtrack(int & col){
    col--;
    if(col == -1) exit(1);
} // Backtrack

void print(int q[]){
    static int count = 0;
    ++count;
    cout << count << endl;
    for(int i = 0; i < 8; i++)
        cout << q[i];
    cout << endl;
}
int main()
{
    int q[8];
    q[0] = 0;
    int c = 1;

    bool from_backtrack = false;

    while(1){
        while(c < 8){ // this loops across columns

            if(!from_backtrack)
                attack(q[c],c)

            from_backtrack = false;

            while(q[c] < 8){ // place queen in this column
                q[c]++;

    return 0;
}

“我在编写代码时遇到问题。如何[我可以]调用每个函数以使其正确找到解决方案?”

1 个答案:

答案 0 :(得分:6)

首先,只需通过剥离其他所有内容并添加显式goto来执行,通过直线执行到达标签来查看控制流。

NC: if (…) goto print;
    goto NR;

NR: if (…) goto backtrack;
    if (…) goto NR;
    goto NC;

backtrack:
    if (…) return;
    goto NR;

print:
    goto backtrack;

现在,采取无条件的getos并尝试移动块,使它们代表直线执行。

NR: if (…) goto backtrack;
    if (…) goto NR;
    goto NC;

NC: if (…) goto print;
    goto NR;

print:
    goto backtrack;

backtrack:
    if (…) return;
    goto NR;

现在消除直线的结果

NR: if (…) goto backtrack;
    if (…) goto NR;

NC: if (…) goto print;
    goto NR;

print:

backtrack:
    if (…) return;
    goto NR;

请注意,包含所有后向gotos的标签是一个循环:

for (;;) {
NR: if (…) goto backtrack;
    if (…) continue;

NC: if (…) goto print;
    continue;

print:

backtrack:
    if (…) return;
}

嗯,我们可以扭转NC: if()的感觉并消除goto print。并且goto backtrack只会跳过某些语句,这相当于另一个语句if

for (;;) {
NR: if (! …) {
        if (…) continue;
NC:     if (! …) continue;
print:
    }
backtrack:
    if (…) return;
}

循环没有条件,但是backtrack: … if(…) return;只是退出它,所以将该块和条件移动到循环中。

for (;…; /* backtrack */ …) {
NR: if (! …) {
        if (…) continue;
NC:     if (! …) continue;
print:
    }
}

看起来很不错,没有更多的东西,也没有“可疑”的结构!但是,NC应该是切入点。

这是盲目,机械,编译器转换失败的地方。我看到三种选择:

  1. 引入变量以强制执行第一次循环迭代。在我看来,这比goto更加丑陋。
  2. goto NC;伪装成switch(0)并将标签NC:称为case 0:。老师可能不会接受这种妥协。
  3. 将块从NC复制到循环的末尾,并粘贴到循环开头的上方。然后,您可以将它们分解为函数。实际上,这是一种盲目的机械转型。万岁。我还代表NRbacktrack作为统一的函数。
  4. NC();
    if (…) {
        print();
    }
    
    while ( backtrack(), … ) { // <- note comma operator
        NR();
        if (! …) {
            if (…) continue;
            NC();
            if (! …) continue;
            print();
        }
    }
    

    可能有一个更优雅的解决方案,包括查看代码的内容,但这需要较少的思考。