【问题标题】:Problem with recursive objective-c void-method递归objective-c void-method的问题
【发布时间】:2011-07-14 12:55:36
【问题描述】:

这是我在这里的第一个问题,我希望有人可以帮助我。 我是 iPhone 编程的新手,想尝试一个简单的应用程序...... 这是一个使用递归方法的数独求解器。在 JAVA 中,这段代码没有问题,但在 Objective-C 中,当数独被解决时,代码并没有停止。它仍在尝试解决数独问题并稍后停止。

谁有想法?!

这是代码。

- (SudokuSolver *) initWithField: (int[9][9]) field {
self = [super init];
if(self) {
    for (int i=0; i<9; i++) {
        for (int j=0; j<9; j++) {
            sudokuField[i][j] = field[i][j];
            if (field[i][j]) {
                sudokuFieldStatic[i][j] = 1;
            } else {
                sudokuFieldStatic[i][j] = 0;
            }
        }
    }
}
return self;
}

- (void) solve {
   [self solveFieldAtRow:0 andCol:0];
}

- (void) solveFieldAtRow: (int) row andCol: (int) col {
  if (row > 8) {
    return;
  } else {
    while (sudokuField[row][col] != 0) {
        if (++col > 8) {
            col = 0;
            row++;
            if (row > 8) {
                return;
            }
        }
    }
    for (int num=1; num<10; num++) {
        if ([self checkRow:row forNumber:num] && [self checkCol:col forNumber:num] && [self checkFieldAtRow:row andCol:col forNumber:num]) {
            sudokuField[row][col] = num;
            [self showFieldInConsole:0];
            if (col < 8) {
                [self solveFieldAtRow:row andCol:col+1];
            } else {
                [self solveFieldAtRow:row+1 andCol:0];
            }
        }
    }
    sudokuField[row][col] = 0;
  }
}

【问题讨论】:

  • 能否也分享一下sudokuField的声明和初始化?
  • 有些代码不在这里,所以快速检查一下:您是否收到任何编译器警告?如果您在checkRow 等方面遇到问题,例如总是返回非零,那么可能需要一些时间来完成求解。
  • 递归模式不是很清楚。我建议重写它以在 solveFieldAtRow 方法的开头放置一个 row &gt;= 9 || col &gt;= 8 检查。
  • 当我插入一个 NSLOG();在“返回”上,它在正确的时间向我展示了,但是接下来会有更多的递归。我用 JAVA 编写了异常代码。
  • 并且没有警告。我用调试测试了检查方法。一切正常

标签: objective-c recursion return void


【解决方案1】:

解决难题时代码不会停止,因为您没有在递归调用后检查难题是否已解决。因此,即使递归调用找到了解决方案,代码也会在找到解决方案后继续运行,直到尝试了所有可能性。

既然您说您的 Java 代码可以工作,我建议您将 Java 程序的逻辑与此代码进行比较。您可能会发现 Java 代码确实包含这样的测试。


编辑从您上面的评论中,我看到您不会在 Java 代码中找到这样的测试,因为当找到解决方案时,您正在滥用异常从递归中“返回” .正确的方法是让每个递归调用在找到解决方案时返回真值,如果没有找到解决方案则返回假值。然后每个步骤都应该检查它的子调用是否成功,如果成功则返回成功。像这样的:

- (BOOL) solveFieldAtRow: (int) row andCol: (int) col {
    if (row > 8) {
        // reached the end, so it must have succeeded
        return YES;
    } else {
        while (sudokuField[row][col] != 0) {
            if (++col > 8) {
                col = 0;
                row++;
                if (row > 8) {
                    // reached the end, so it must have succeeded
                    return YES;
                }
            }
        }
        for (int num=1; num<10; num++) {
            if ([self checkRow:row forNumber:num] && [self checkCol:col forNumber:num] && [self checkFieldAtRow:row andCol:col forNumber:num]) {
                sudokuField[row][col] = num;
                [self showFieldInConsole:0];
                BOOL result;
                if (col < 8) {
                    result = [self solveFieldAtRow:row andCol:col+1];
                } else {
                    result = [self solveFieldAtRow:row+1 andCol:0];
                }
                if (result) {
                    // Our child call succeeded, so we pass that back up
                    // the stack.
                    return YES;
                }
            }
        }
        sudokuField[row][col] = 0;
        // If we get here, we could not find a solution. Return failure
        // back up the stack.
        return NO;
    }
}

【讨论】:

  • 我认为“if(row > 8) return”可以完成这项工作。
  • 当它发现它到达结束时从最后的递归调用返回。但是倒数第二个递归调用不检查最后的递归调用是成功还是失败找到解决方案,因此它有效地假定它失败并继续尝试下一个数字。
  • 我根据您上面的评论编辑了我的答案,即您“使用异常”编写了 Java 版本。
  • 哦,非常感谢。现在我明白了。所以我不能在这里使用我的 JAVA 迁移代码。
  • 可以,如果你真的想要的话。查看@try@catchNSException。但是异常之所以称为“异常”,是因为它们应该是异常情况,而不是计算的预期结果。
猜你喜欢
  • 2012-03-07
  • 2017-11-19
  • 1970-01-01
  • 2020-05-30
  • 2011-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多