简体   繁体   English

Java并行数独求解器

[英]Parallel Sudoku Solver in Java

I have a homework that requires to implement a sequential and a parallel version of a sudoku solver in Java ( using the ForkJoin Framework for the parallel one ). 我有一个家庭作业,需要在Java 中实现数独数独求解器的顺序和并行版本( 使用ForkJoin Framework作为并行版本 )。

I wrote the sequential one and it works fine. 我写了顺序的,它工作正常。 The algorithmic idea is a simple backtracking exercise: for each cell (starting from the top-left corner of the table) not already filled, fill it (sequentially, and one at a time) with all the legal candidates (integer from 1 to 9) until you reach the end (row 9 col 9) of the matrix. 算法思想是一个简单的回溯练习:对于尚未填充的每个单元格(从表格的左上角开始),用所有合法候选者(从1到9的整数)填充(依次一次,一次填充一次) ),直到到达矩阵的末尾(第9行第9行)。 If you've reached the end, then increments the solutions number. 如果您已结束,请增加解决方案编号。

I thought to implement the parallel version just spawning a new thread for each valid candidate found for a particular cell, and then waiting for them.. It seems not to work and I wasn't able to find the reason. 我以为要实现并行版本,只需为在特定单元格中找到的每个有效候选者生成一个新线程,然后等待它们即可。似乎无法正常工作,我也找不到原因。

I post the class that should do the entire work with the hope to find a good advice: 我发布了应该完成所有工作的课程,希望能找到一个好的建议:

class SolveSudoku extends RecursiveAction{
    private int i, j;
    private int[][] cells;

    SolveSudoku(int i, int j, int[][] cells){
        this.i = i;
        this.j = j;
        this.cells = cells;
    }

    @Override
    protected  void compute(){
        if (j == 9) {
            j = 0;
            if (++i == 9){
                solutions++;
                System.out.println(solutions);
                return;
            }
        }

        if (cells[i][j] != 0 ){                             // skip filled cells
            SolveSudoku s =  new SolveSudoku(i, j+1, cells);
            s.compute();
            return;
        }


        ArrayList<Integer> vals = new ArrayList<Integer>();
        for (int val = 1; val <= 9; val++)                 // try all the legal candidates for i, j
            if (legal(i,j,val,cells))
                vals.add(val);


        if(vals.size() == 1){                            // only one, no new threads
            cells[i][j] = vals.get(0);
            new SolveSudoku(i, j+1, cells).compute();
        }
        else{
            SolveSudoku threads[] = new SolveSudoku[vals.size()];
            int n = 0;
            int first;
            for(int k=0; k<vals.size(); k++){
                if(k == vals.size()-1){
                    cells[i][j] = vals.get(k);
                    threads[n] = new SolveSudoku(i, j+1, cells);
                    threads[n].compute();
                }
                else{
                    cells[i][j] = vals.get(k);
                    threads[n] = new SolveSudoku(i, j+1, cells);
                    threads[n].fork();
                }
                n++;
            }


            for(int k=0; k<threads.length-1; k++)
                if(k != vals.size()-1)
                    threads[k].join();

        }

        cells[i][j] = 0;
        return;
    }}

new ForkJoinPool().invoke(new SolveSudoku(0, 0, M)); // where *M* is a sudoku instance to solve where all the unfilled cells contain '0'

First, you should consider what happens if one thread finishes it's job. 首先,您应该考虑如果一个线程完成工作会发生什么情况。 You should note that it tries to reset the cell to 0, but what if there's another sub-thread working with the Cell? 您应该注意,它会尝试将单元重置为0,但是如果该单元还有另一个子线程该怎么办?

Obviously, if another thread accessing the same Cell tries to check if it's legal, it may have to put a wrong value because another thread put a zero back in it! 显然,如果另一个访问同一Cell的线程试图检查它是否合法,则可能必须输入错误的值,因为另一个线程将零归还!

I think you should pass the copy of the array to the new threads. 我认为您应该将数组的副本传递给新线程。 In your code, you pass the same array to all the threads and they try to insert the correct value at the same time. 在您的代码中,您将相同的数组传递给所有线程,并且它们尝试同时插入正确的值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM