Java简单递归算法,使其并行

问题描述 投票:0回答:1

我有一个简单的递归算法,该算法生成字符串的所有排列并计算通过一些条件的排列数。我想通过并行编程使其更高效,但是我不能将其与“ forkJoinPool”一起使用(我不确定,但是不可能用分而治之的方式来实现它)。因此,我不得不在分离的线程上运行所有计算(检查条件和递增计数器),但这并不比顺序算法更好。

Thread thread = new Thread(() -> {
    compute(elements);
});
thread.start();

上面的代码似乎不能更好地工作。

package com.company;

public class Main {
    public static void main(String[] args) {
        long start = System.nanoTime();
        call();
        long end = System.nanoTime();
        System.out.println((end - start) / 1000000);
    }

    private static void call() {
        char[] elements = "1234567890+/".toCharArray();
        Permutation p = new Permutation();
        p.printAllRecursive(elements.length, elements);
        System.out.println(p.counter);
    }
}


class Permutation {
    Integer counter = 0;

    public void printAllRecursive(int n, char[] elements) {
        if (n == 1) {
            // running compute() in parallel
            Thread thread = new Thread(() -> {
                compute(elements);
            });
            thread.start();
        } else {
            for (int i = 0; i < n - 1; i++) {
                printAllRecursive(n - 1, elements);
                if (n % 2 == 0) {
                    swap(elements, i, n - 1);
                } else {
                    swap(elements, 0, n - 1);
                }
            }
            printAllRecursive(n - 1, elements);
        }
    }

    private void swap(char[] elements, int a, int b) {
        char tmp = elements[a];
        elements[a] = elements[b];
        elements[b] = tmp;
    }

    private void compute(char[] elements) {
        String string = new String(elements);
        int index1 = string.indexOf('/');
        int index2 = string.indexOf('+');
        if (index1 > 0 && index2 > 0 && index1 < 11 && index2 < 11) {
            if (index1 > index2) {
                if (index1 - index2 != 1) {
                    counter++;
                }
            }
        }
    }
}

方法compute(elements)非常耗时,如何在多线程中使其更高效?在此先感谢

java multithreading algorithm executorservice forkjoinpool
1个回答
0
投票

[当您调用printAllRecursive()时,您会创建一个附加线程来调用compute(),然后再调用printAllRecursive()并再次创建一个新线程。附加线程对您没有帮助。 似乎您的算法是错误的

查看正确的代码以计算排列:

public class Main {
    public static void main(String[] args) {
        long start = System.nanoTime();
        call();
        long end = System.nanoTime();
        System.out.println("time: " + (end - start) / 1000000);
    }

    private static void call() {
        char[] elements = "ABCD".toCharArray();
        int n = elements.length;
        Permutation p = new Permutation();
        p.printAllRecursive(elements, 0 , n-1);
        System.out.println("number of permutations: " + p.counter);
    }

}

class Permutation {
    Integer counter = 0;

    public void printAllRecursive(char[] elements, int l, int r) {
        if (l == r) {
            counter++;
            //System.out.println(String.valueOf(elements));
        } else {
            for (int i = l; i <= r; i++) {
                swap(elements, l, i);
                printAllRecursive(elements, l+1, r);
                swap(elements, l, i);
            }
        }
    }

    private void swap(char[] elements, int a, int b) {
        char tmp = elements[a];
        elements[a] = elements[b];
        elements[b] = tmp;
    }
}

您可以看到此算法的插图以更好地理解它,例如here

P.S。如前所述,您的问题不是多线程,但无论如何,我描述了为什么您不能简单地添加以下代码:

Thread thread = new Thread(() -> {
    compute(elements);
});
thread.start();

您应该意识到的第一件事是,您不能通过不同的线程来修改一个内存区域。在您的代码示例中,您从不同的线程修改了字段counter和数组elements。为什么不能从不同线程修改一个变量?例如,线程1想要将序列'777777777'写入您的数组。在此写入过程中,thread2希望从数组中读取值。因此,线程2可以读取值'777456789',因为线程1仍将数据写入数组并且尚未完成。因此,我们可以通过线程安全的Integer更改AtomicInteger并将synchronized添加到swap方法的签名。

© www.soinside.com 2019 - 2024. All rights reserved.