英文:
Java use global variable reset in iteration
问题
这种情况可能发生在单线程环境中是因为在第一个代码示例中,res
在每次递归调用 backTrace
后没有累积,因此它在每个递归层次中都被重置为0。这是因为在每次递归中,backTrace
返回了1或0,但这个返回值没有被添加到 res
中。
在第二个代码示例中,通过引入变量 a
来保存 backTrace
的返回值,并将其添加到 res
中,确保了递归的结果被累积。
在单线程环境中,如果不显式地将递归调用的结果累积到一个变量中,那么递归调用不会影响到外部的 res
变量,因此它会在每个递归层次中被重置。所以,为了正确地累积结果,你需要将递归的返回值添加到 res
中,这就是为什么第二个代码示例中的做法是正确的。
英文:
I have the code work with iteration in a single thread enviorment:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
class Solution {
int res = 0;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
backTrace(n, 0, columns, record1, record2);
return res;
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
res = res + backTrace(n, row + 1, columns, record1, record2);
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return 0;
}
}
the result of the code is below, and it seems the res
reset when res = res + backTrace(n, row + 1, columns, record1, record2);
res start:0
res start:0
res end:0
res start:0
res start:0
res end:0
res end:0
res end:0
res start:0
res start:0
res start:0
res start:0
res end:1
res end:0
res end:0
res end:0
res start:0
res start:0
res start:0
res start:0
and when we change the code, let a new variable to save the result of backTrace, and it works fine.
package com.nbp.cdncp.vpe.api.controller;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
class Solution {
int res = 0;
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
backTrace(n, 0, columns, record1, record2);
return res;
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
var a = backTrace(n, row + 1, columns, record1, record2);
res += a;
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return 0;
}
}
the result:
res start:0
res start:0
res end:0
res start:0
res start:0
res end:0
res end:0
res end:0
res start:0
res start:0
res start:0
res start:0
res end:1
res end:1
res end:1
res end:1
res start:1
res start:1
res start:1
res start:1
res end:2
res end:2
res end:2
res end:2
res start:2
res start:2
res start:2
res end:2
res end:2
res start:2
res end:2
res end:2
2
Why this happens in a single thread environment
答案1
得分: 1
以下是您要翻译的部分:
"The expression res + backTrace(n, row + 1, columns, record1, record2)
is evaluated left to right. This means the value of res
is read before calling backTrace
, and doesn’t reflect the change to the value that happens within that method call.
If you reverse the order of arguments to backTrace(n, row + 1, columns, record1, record2) + res
, this avoids the problem, however this may still make the code hard to understand. Most people expect addition to be commutative. This assumption is violated in code where evaluation of one of the operands affects the value of the other. It would be clearer to rewrite the method to avoid using the non-local variable res
:
class Solution {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
return backTrace(n, 0, columns, record1, record2);
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
int res = 0;
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
res += backTrace(n, row + 1, columns, record1, record2);
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return res;
}
}
英文:
The expression res + backTrace(n, row + 1, columns, record1, record2)
is evaluated left to right. This means the value of res
is read before calling backTrace
, and doesn’t reflect the change to the value that happens within that method call.
If you reverse the order of arguments to backTrace(n, row + 1, columns, record1, record2) + res
, this avoids the problem, however this may still make the code hard to understand. Most people expect addition to be commutative. This assumption is violated in code where evaluation of one of the operands affects the value of the other. It would be clearer to rewrite the method to avoid using the non-local variable res
:
class Solution {
public static void main(String[] args) throws IOException {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String line;
while ((line = in.readLine()) != null) {
int n = Integer.parseInt(line);
int ret = new Solution().totalNQueens(n);
String out = String.valueOf(ret);
System.out.print(out);
}
}
public int totalNQueens(int n) {
Set<Integer> columns = new HashSet<Integer>();
Set<Integer> record1 = new HashSet<Integer>();
Set<Integer> record2 = new HashSet<Integer>();
return backTrace(n, 0, columns, record1, record2);
}
private int backTrace(int n, int row, Set<Integer> columns, Set<Integer> record1, Set<Integer> record2) {
if (n == row) {
return 1;
}
int res = 0;
for (int i = 0; i < n; i++) {
if (columns.contains(i)) {
continue;
}
int check1 = row - i;
if (record1.contains(check1)) {
continue;
}
int check2 = row + i;
if (record2.contains(check2)) {
continue;
}
columns.add(i);
record1.add(check1);
record2.add(check2);
System.out.println("res start:" + res);
res += backTrace(n, row + 1, columns, record1, record2);
System.out.println("res end:" + res);
columns.remove(i);
record1.remove(check1);
record2.remove(check2);
}
return res;
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论