首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么迭代置换生成器比递归慢?

为什么迭代置换生成器比递归慢?
EN

Stack Overflow用户
提问于 2013-11-27 10:45:19
回答 1查看 555关注 0票数 0

我正在比较两个用作置换生成器的函数。这个问题是关于很多事情的:字符串intern表,使用迭代和递归解决这个问题的优缺点,等等。

代码语言:javascript
复制
public static List<String> permute1(String input) {
    LinkedList<StringBuilder> permutations = new LinkedList<StringBuilder>();
    permutations.add(new StringBuilder(""+input.charAt(0)));

    for(int i = 1; i < input.length(); i++) {
        char c = input.charAt(i);
        int size = permutations.size();
        for(int k = 0; k < size ; k++) {
            StringBuilder permutation = permutations.removeFirst(),
                    next;
            for(int j = 0; j < permutation.length(); j++) {
                    next = new StringBuilder();
                    for(int b = 0; b < permutation.length(); next.append(permutation.charAt(b++)));
                    next.insert(j, c);
                    permutations.addLast(next);
            }
            permutation.append(c);
            permutations.addLast(permutation);
        }
    }
    List<String> formattedPermutations = new LinkedList<String>();
    for(int i = 0; i < permutations.size(); formattedPermutations.add(permutations.get(i++).toString()));
    return formattedPermutations;
}

public static List<String> permute2(String str) { 
    return permute2("", str); 
}

private static List<String> permute2(String prefix, String str) {
    int n = str.length();
    List<String> permutations = new LinkedList<String>();
    if (n == 0) permutations.add(prefix);
    else 
        for (int i = 0; i < n; i++) 
            permutations.addAll(permute2(prefix + str.charAt(i), str.substring(0, i) + str.substring(i+1, n)));
    return permutations;
}

我认为这两个算法大体上应该是相等的,但是递归实现在n=10上做得很好,而迭代解决方案permute1在n=8上有一个内存错误,其中n是输入字符串长度。我使用StringBuilder然后转换成字符串的事实是不是一个坏主意?如果有,原因何在?我认为无论何时你添加到一个字符串中,它都会创建一个新的字符串,这是不好的,因为java会对它进行实例化,对吧?所以你最终会得到一堆中间字符串,它们不是排列,而是卡在实习生的表中。

编辑:

我用String替换了StringBuilder,这样就不需要使用StringBuilder.insert()了。但是,我必须使用String.substring()来构建置换字符串,这可能不是最好的方法,但从经验上讲它比StringBuilder.insert()更好。我没有像Alex Suo建议的那样使用字符数组,因为我的方法应该返回一个字符串列表,所以我必须将这些字符数组转换为字符串,这将导致在字符数组上进行更多的垃圾回收(这就是OutOfMemoryError的原因)。因此,有了这些,OutOfMemoryError和速度问题都得到了解决。

代码语言:javascript
复制
public static List<String> permute3(String input) {
        LinkedList<String> permutations = new LinkedList<String>();
        permutations.add(""+input.charAt(0));
        for(int i = 1; i < input.length(); i++) {
            char c = input.charAt(i);
            int size = permutations.size();
            for(int k = 0; k < size ; k++) {
                String permutation = permutations.removeFirst(),
                        next;
                for(int j = 0; j < permutation.length(); j++) {
                        next = permutation.substring(0, j + 1) + c + permutation.substring(j + 1, permutation.length());
                        permutations.addLast(next);
                }
                permutations.addLast(permutation + c);
            }
        }
        return permutations;
    }
EN

回答 1

Stack Overflow用户

发布于 2013-11-27 11:20:14

首先,自从你得到了OutOfMemoryError,这暗示着你有很多GC正在进行,正如我们所知道的,GC是一个性能杀手。因为年轻一代的GC是停止世界的,你可能会因为遭受GC的痛苦而获得更糟糕的性能。

查看您的代码,如果您深入研究StringBuilder的实际实现,您会发现insert()是一个非常昂贵的操作,涉及到System.arraycopy()等,还可能涉及到expandCapacity()。因为你没有提到n表示排列,所以我假设你的缓冲区是n<10,所以这里不会有问题--因为StringBuilder的默认缓冲区大小只有16,所以你需要重新分配内存。StringBuilder基本上是一个自动字符数组,但它并不神奇--无论您需要通过从头开始编写代码来做什么,StringBuilder也需要这样做。

话虽如此,如果你真的想获得最大的性能,既然你的字符串数组的长度是预先定义的,为什么不使用长度= String.length()的字符数组呢?就性能而言,这可能是最好的。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20232952

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档