【问题标题】:Is there a way to speed up a recursion with many loops?有没有办法通过许多循环来加速递归?
【发布时间】:2012-04-18 11:20:17
【问题描述】:

我基本上是在尝试使用递归,并创建了一个小程序,可以找到 10 个项目中 0-10 的所有组合({1 apple, 0 grapes}, {2 apple, 0 grapes}, {0 apple, 1 颗葡萄} 等)。

import java.util.Arrays;
import java.util.List;

public class main {

    public static void main(String[] args) {
        System.out.println("Starting..");
        long startTime = System.currentTimeMillis();
        List<Integer> list_to_start = Arrays.asList(new Integer[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); 
        String[] name_of_list_to_start = new String[] {"Grapes", "Strawberries", "Raspberries", "Blackberries", "Pineapples", "Oranges", "Prunes", "Pears", "cherries", "Peaches", "Apples"};       
        System.out.println(list_to_start.size());
        counter(list_to_start.size(), list_to_start, name_of_list_to_start);
        long endTime = System.currentTimeMillis(); 
        System.out.println("Total execution time: " + (endTime-startTime));
    }

    private static void counter(int length, List<Integer> list_to_start, String[] name_of_list_to_start) {
        // If we've gone through everything then return the results
        if (length == 0) {
            for (int i = 0; i<list_to_start.size(); i++) {
                //System.out.println(name_of_list_to_start[i] + " = " + list_to_start.get(i));
            }
            //System.out.println("****");
            return;
        }   
        //This part basically increments list_to_start and then the above part displays it.
        for (int i = 0; i<=10; i++) {
            if (length != 0 ) {
                list_to_start.set((length-1), i);
                counter((length-1), list_to_start, name_of_list_to_start);
                list_to_start.set((length-1), 0);
            }
        }
    }
}

现在它有 10,000,000,000 个循环(10^10),所以我理解为什么需要很长时间,但我想知道是否有任何 Java 或算法技巧可以用来减少循环数以加快速度?

我曾考虑过使用线程/多处理,但仍需要执行相同数量的循环,这仍需要很长时间。我不确定这里是否可以使用任何数据结构、排序算法或缓存算法。或者我可以将结果并行添加到数组中,然后将它们组合在一起以获得最终结果?我不熟悉任何其他现有方法,因此非常欢迎任何有关语言特定技巧或算法解决方案的建议。

更新:为了阐明我在做什么和性能,我将发布一些示例。要增加处理时间,只需向 list_to_start 添加/删除零(以下结果以毫秒为单位):

1 zero = 0 
2 zero = 1
3 zero = 1
4 zero = 29
5 zero = 37
6 zero = 115
7 zero = 345
8 zero = 1517
9 zero = 23738 (23 seconds)
10 zero = over 30 min. I gave up.

输出(我禁用它以使其运行得更快)是 2 个变量的输出(上面的代码运行 10):

Grapes = 0
Strawberries = 0
****
Grapes = 1
Strawberries = 0
****
Grapes = 2
Strawberries = 0
****
Grapes = 3
Strawberries = 0
****
Grapes = 4
Strawberries = 0
****
Grapes = 5
Strawberries = 0
****
Grapes = 6
Strawberries = 0
****
Grapes = 7
Strawberries = 0
****
Grapes = 8
Strawberries = 0
****
Grapes = 9
Strawberries = 0
****
Grapes = 10
Strawberries = 0
****
Grapes = 0
Strawberries = 1
****
Grapes = 1
Strawberries = 1
****
Grapes = 2
Strawberries = 1
****
Grapes = 3
Strawberries = 1
****
Grapes = 4
Strawberries = 1
****
Grapes = 5
Strawberries = 1
****
Grapes = 6
Strawberries = 1
****
Grapes = 7
Strawberries = 1
****
Grapes = 8
Strawberries = 1
****
Grapes = 9
Strawberries = 1
****
Grapes = 10
Strawberries = 1
****
Grapes = 0
Strawberries = 2
****
Grapes = 1
Strawberries = 2
****
Grapes = 2
Strawberries = 2
****
Grapes = 3
Strawberries = 2
****
Grapes = 4
Strawberries = 2
****
Grapes = 5
Strawberries = 2
****
Grapes = 6
Strawberries = 2
****
Grapes = 7
Strawberries = 2
****
Grapes = 8
Strawberries = 2
****
Grapes = 9
Strawberries = 2
****
Grapes = 10
Strawberries = 2
****
Grapes = 0
Strawberries = 3
****
Grapes = 1
Strawberries = 3
****
Grapes = 2
Strawberries = 3
****
Grapes = 3
Strawberries = 3
****
Grapes = 4
Strawberries = 3
****
Grapes = 5
Strawberries = 3
****
Grapes = 6
Strawberries = 3
****
Grapes = 7
Strawberries = 3
****
Grapes = 8
Strawberries = 3
****
Grapes = 9
Strawberries = 3
****
Grapes = 10
Strawberries = 3
****
Grapes = 0
Strawberries = 4
****
Grapes = 1
Strawberries = 4
****
Grapes = 2
Strawberries = 4
****
Grapes = 3
Strawberries = 4
****
Grapes = 4
Strawberries = 4
****
Grapes = 5
Strawberries = 4
****
Grapes = 6
Strawberries = 4
****
Grapes = 7
Strawberries = 4
****
Grapes = 8
Strawberries = 4
****
Grapes = 9
Strawberries = 4
****
Grapes = 10
Strawberries = 4
****
Grapes = 0
Strawberries = 5
****
Grapes = 1
Strawberries = 5
****
Grapes = 2
Strawberries = 5
****
Grapes = 3
Strawberries = 5
****
Grapes = 4
Strawberries = 5
****
Grapes = 5
Strawberries = 5
****
Grapes = 6
Strawberries = 5
****
Grapes = 7
Strawberries = 5
****
Grapes = 8
Strawberries = 5
****
Grapes = 9
Strawberries = 5
****
Grapes = 10
Strawberries = 5
****
Grapes = 0
Strawberries = 6
****
Grapes = 1
Strawberries = 6
****
Grapes = 2
Strawberries = 6
****
Grapes = 3
Strawberries = 6
****
Grapes = 4
Strawberries = 6
****
Grapes = 5
Strawberries = 6
****
Grapes = 6
Strawberries = 6
****
Grapes = 7
Strawberries = 6
****
Grapes = 8
Strawberries = 6
****
Grapes = 9
Strawberries = 6
****
Grapes = 10
Strawberries = 6
****
Grapes = 0
Strawberries = 7
****
Grapes = 1
Strawberries = 7
****
Grapes = 2
Strawberries = 7
****
Grapes = 3
Strawberries = 7
****
Grapes = 4
Strawberries = 7
****
Grapes = 5
Strawberries = 7
****
Grapes = 6
Strawberries = 7
****
Grapes = 7
Strawberries = 7
****
Grapes = 8
Strawberries = 7
****
Grapes = 9
Strawberries = 7
****
Grapes = 10
Strawberries = 7
****
Grapes = 0
Strawberries = 8
****
Grapes = 1
Strawberries = 8
****
Grapes = 2
Strawberries = 8
****
Grapes = 3
Strawberries = 8
****
Grapes = 4
Strawberries = 8
****
Grapes = 5
Strawberries = 8
****
Grapes = 6
Strawberries = 8
****
Grapes = 7
Strawberries = 8
****
Grapes = 8
Strawberries = 8
****
Grapes = 9
Strawberries = 8
****
Grapes = 10
Strawberries = 8
****
Grapes = 0
Strawberries = 9
****
Grapes = 1
Strawberries = 9
****
Grapes = 2
Strawberries = 9
****
Grapes = 3
Strawberries = 9
****
Grapes = 4
Strawberries = 9
****
Grapes = 5
Strawberries = 9
****
Grapes = 6
Strawberries = 9
****
Grapes = 7
Strawberries = 9
****
Grapes = 8
Strawberries = 9
****
Grapes = 9
Strawberries = 9
****
Grapes = 10
Strawberries = 9
****
Grapes = 0
Strawberries = 10
****
Grapes = 1
Strawberries = 10
****
Grapes = 2
Strawberries = 10
****
Grapes = 3
Strawberries = 10
****
Grapes = 4
Strawberries = 10
****
Grapes = 5
Strawberries = 10
****
Grapes = 6
Strawberries = 10
****
Grapes = 7
Strawberries = 10
****
Grapes = 8
Strawberries = 10
****
Grapes = 9
Strawberries = 10
****
Grapes = 10
Strawberries = 10

【问题讨论】:

    标签: java algorithm data-structures recursion


    【解决方案1】:

    您可以使用单个循环。

    有 11^10 种可能的组合。你可以遍历它们所有

    // String[] names = "Grapes,Strawberries,Raspberries,Blackberries,Pineapples,Oranges,Prunes,Pears,Cherries,Peaches,Apples".split(",");
    String[] names = "Pineapples,Oranges,Prunes,Pears,Cherries,Peaches,Apples".split(",");
    int maxQuantity = 10;
    long combinations = 1;
    int quantities = maxQuantity + 1;
    for (String _ : names)
        combinations *= quantities;
    
    long start = System.currentTimeMillis();
    PrintStream out = new PrintStream(new BufferedOutputStream(new FileOutputStream("combinations.tsv")));
    // heading
    for (String name : names)
        out.print(name + "\t");
    out.println();
    
    for (long comb = 0; comb < combinations; comb++) {
        // comb is a base N number of digits 0 to maxQuantity.
        long c = comb;
        for (int i = 0; i < names.length; i++) {
            long n = c % quantities;
            c /= quantities;
            out.print(n);
            out.print('\t');
        }
        out.println();
    }
    out.close();
    System.out.println("Took " + (System.currentTimeMillis() - start) / 1e3 + " seconds" +
            " to write " + combinations + " combinations");
    

    打印

    Took 51.585 seconds to write 19487171 combinations
    

    如果您注释掉这些行,它会将值打印到您获得的文件中

    Took 0.065 seconds to write 19487171 combinations
    

    注意:此程序将大部分时间用于打印。如果您移除打印部分,它将很快完成。 ;)

    【讨论】:

    • 谢谢彼得。有帮助,但在示例代码中我将其设置为 2,因此如果有人错误地运行它,它不会永远运行(我现在编辑它)。假设我将它设置为 10 而不是 2(0 到 10 而不是 0 到 2).. 有没有什么技术可以用来加速它?即使减少打印仍然需要很长时间(只是打印以证明我在寻找什么)
    • @learningJava:你有两个选择。您可以 (a) 更改算法以使算法本身更快,就像 Peter 所做的那样,或者您可以 (b) 优化。当您的算法效率极低时(如在原始代码中),小事情的优化将无济于事。我强烈建议参加算法课程,他们会在其中讨论计算复杂性以充分理解问题。
    • 运行后,我不确定这是不是我上面的程序正在做的事情。我的程序提供了从 0 到 10 显示每种水果的所有组合,但有一些组合似乎不在此样本的输出中(也未显示该值)。
    • 我已对其进行了更改,以便计算唯一解决方案的数量。您期望有多少解决方案?
    • 我不太确定,因为它需要永远运行到第 10 号,但是如果你运行上面的代码并删除一些零,那么只有 3 个零(10^3)然后我得到1331 个结果。如果我运行 4 个变量,那么我得到 14641..
    【解决方案2】:

    假设您只关心同一项目的第一个实例,您可以在匹配时打破循环以避免额外的循环。您能否更好地分解此处的“问题”(您的程序应该做什么)?

    【讨论】:

    • 我正在努力学习。我有一个不同的爱好程序,它非常复杂,但遵循类似的逻辑。我试图弄清楚是否有任何技术可以加快速度并学习一种新的做事方式(如果存在的话)。
    • 我的意思是对于您的搜索,您是否只对是/否解决方案感兴趣,如果不是,您是否需要对项目进行计数?会有两个以上相同的项目/有关系吗?像这样的东西,在学习时,我建议分解问题并尽可能具体,这基本上是创建算法的基础。有很多方法可以加速这个过程,例如使用高级搜索/排序算法或数据结构。我建议研究这些一般性主题。祝你好运
    • 在阅读了您的其他 cmets 之后,我意识到我有点偏离目标,尽管我的建议仍然有些合理。为了加快输出速度,请尝试将您的组合存储在一个数组中,并在程序结束时将其转储。打开和关闭 IO 流会显着减慢您的程序。
    • 感谢瑞恩的评论。即使没有 IO 流,如果您运行上述代码,它也需要 30 多分钟(甚至更多,它仍在为我运行)。我正在寻找像你提到的东西,高级搜索/排序算法或数据结构......你知道哪些会适用吗?还是在任何基本的算法书中?
    猜你喜欢
    • 2010-09-06
    • 1970-01-01
    • 2019-08-22
    • 2020-03-30
    • 1970-01-01
    • 2023-03-04
    • 2020-06-19
    • 2021-12-08
    相关资源
    最近更新 更多