【问题标题】:Improving Intersection Algorithm改进交叉算法
【发布时间】:2013-03-26 09:53:59
【问题描述】:

我有一个算法来构建两个排序列表的交集。如果我在性能测试中将它与 java.util.BitSet 进行比较,我的算法很慢。

    public static List<Integer> intersection(List<Integer> list1, List<Integer> list2) {
            int size1 = list1.size(), size2 = list2.size();
            int capacity = size1 < size2 ? size1 : size2;
            List<Integer> intersection = new ArrayList<Integer>(capacity);
            int i1 = 0, i2 = 0;
            while (i1 < size1 && i2 < size2) {
                if (list1.get(i1) < list2.get(i2))
                    i1++;
                else if (list2.get(i2) < list1.get(i1))
                    i2++;
                else {
                    intersection.add(list2.get(i2++));
                    i1++;
                }
            }
            return intersection;
        }

有人看到任何改进吗?

谢谢

【问题讨论】:

  • 使用BitSet,甚至int[]。为ArrayList 指定容量可能是一个错误。可能不需要那么大。此外,每个循环只需要两个 gets。如果您只在关联的增量上使用get,即使这样也可以减少。您可能需要考虑使用Iterators,尤其是当您获得LinkedList 作为参数时。

标签: java intersection sortedlist


【解决方案1】:

函数的输入是否总是ArrayList 类型?

  • 如果是,从算法上讲,您的方法没有问题。我会做两个改变:
    1. 我会将参数类型更改为ArrayList&lt;Integer&gt; list1, ArrayList&lt;Integer&gt; list2
    2. 我只会给list1.get(i1)list2.get(i2) 打一次电话。这可能会或可能不会对性能产生任何影响,但在风格上我更愿意考虑这一点。
  • 如果您需要支持任何列表,那么我会根据两个迭代器重写该函数,因为调用 get(index) 可能会非常昂贵。

最后,在测试性能时,请务必遵循How do I write a correct micro-benchmark in Java?中给出的建议

【讨论】:

    【解决方案2】:

    你应该知道:

    List<Integer> intersection = new ArrayList<Integer>(capacity);
    

    分配一个大小为capacity的内部数组。

    假设list1.size() == 5000list2.size() == 5000intersection(list1, list2).size() == 3,该方法将分配4997个无用整数。

    尝试使用合理的容量(取决于方法的使用)或将其保留为默认值(即 10)。

    (请记住,分配大小为n(或容量 nArrayList)的数组的复杂性是O(n)。 )

    【讨论】:

    • 在 ArrayList 中分配更多空间不是很昂贵吗?
    • 分配更多空间代价高昂,让ArrayList调整其内部数组的时间太多也代价高昂,你应该选择一个合理的capacity
    猜你喜欢
    • 2017-08-19
    • 2011-04-20
    • 2014-08-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多