为什么我的算法返回stackoverflow异常?

时间:2016-12-20 21:57:29

标签: java algorithm performance

我必须做一个用随机(0到2)数字填充二维数组的算法,唯一的条件是我可以在水平和垂直方向上使用相同的数字3次或更多次。 例如

[0,0,1,2,1
 0,1,2,1,2
 1,2,0,1,0]

没问题

[0,0,0,2,1
 0,1,2,1,2
 1,2,0,1,0]

[0,0,1,2,1
 0,1,1,1,2
 1,2,1,1,0]

错了。

所以这是我的算法:

public class CandyHelper {

    private final int minimumChainLength = 3;
    private final int searchChainSize    = 3;

    public Candy[][] randomInit(int rowCount, int columnCount) {
        Candy[][] map = new Candy[rowCount][columnCount];
        for (int row = 0; row < rowCount; ++row) {
            for (int column = 0; column < columnCount; ++column) {
                // Fill square with random candy.
                Random rand = new Random();
                int value = rand.nextInt(3);
                Candy candy = new Candy();
                candy.setType(value);
                map[row][column] = candy;
            }
        }

        if (findHint(map)) {
            //System.out.println("Winning conditions");
            map = null;
            map = randomInit(rowCount, columnCount);          
        } else {
            System.out.println("no wining");
        }

        return map;
    }

    // Function which searches for match of at least `MinimumChainLength`.
    private boolean findHint(Candy[][] map) {
        int rowCount = map.length;
        int columnCount = map.length;

        List<Candy> hintMove = new ArrayList<Candy>();

        // Search rows.
        for (int row = 0; row < rowCount; ++row) {
            // Search for chain.
            for (int chainStart = 0; chainStart < columnCount - searchChainSize; ++chainStart) {
                // Add initial cell in chain.
                hintMove.clear();
                hintMove.add(map[row][chainStart]);
                for (int nextInChain = chainStart + 1; nextInChain < columnCount; ++nextInChain) {
                    if (map[row][nextInChain].getType() == hintMove.get(0).getType()) {
                        hintMove.add(map[row][nextInChain]);
                    } else {
                        break;
                    }
                }           
                // Was a chain found?
                if (hintMove.size() >= minimumChainLength)
                    return true;
            }
        }

        // Search columns.
        for (int column = 0; column < columnCount; ++column) {
            // Search for chain.
            for (int chainStart = 0; chainStart < rowCount - searchChainSize; ++chainStart) {
                // Add initial cell in chain.
                hintMove.clear();
                hintMove.add(map[chainStart][column]);
                for (int nextInChain = chainStart + 1; nextInChain < rowCount; ++nextInChain) {
                    if (map[nextInChain][column].getType() == hintMove.get(0).getType()) {
                        hintMove.add(map[nextInChain][column]);
                    } else {
                        break;
                    }
                }
                // Was a chain found?
                if (hintMove.size() >= minimumChainLength)
                    return true;
            }
        }

        // No chain was found, so clear hint.
        hintMove.clear();
        return false;     
    }

}

和我的pojo:

public class Candy {
   private int type;

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Candy{" + "type=" + type + '}';
    }

}

当我从10x10的数组开始时,我开始收到堆栈溢出错误。 我该怎么做才能纠正它们?

提前致谢。

2 个答案:

答案 0 :(得分:1)

你的问题就在这一行:

map = randomInit(rowCount, columnCount); 

基本上每次findHint返回true时,你都会以递归方式调用randomInit。这意味着FindHint返回true的概率越大,堆栈溢出的可能性就越大。在你的情况下,你的网格越大,FindHint返回true的概率就越高,我猜大小10几乎肯定会在堆栈溢出中结束。

我很诚实我不知道为什么你在这里再次调用randomInit而不是仅仅返回地图?

答案 1 :(得分:0)

如果randomInit()为真,我会猜测它与findHint()调用自身有关。我发现findHint()的代码没有任何问题(除了一些性能调整 - 例如,你没有必要构建一个匹配列表来计算有多少匹配),但事实上你可能只是在10x10网格上遇到这个问题。任何只有三种类型的10x10对象网格很可能连续三个 - 这可能会导致你的randomInit()自行调用足够的时间来让你的堆栈溢出。

我不是100%确定你想要randomInit()做什么。如果你希望它在没有N组的情况下继续生成随机网格,我建议将网格生成代码放在一个单独的方法中(称之为generate()),然后让randomInit()调用它一个循环:

boolean setFound;
do {
    map = generate(rowCount, columnCount);
    setFound = findHint(map);
} while (setFound);