问题 如何更快地减去这些列表?


我想减去两个ArrayLists,这样我就可以让孩子不在另一个列表中。

我是这样做的:

removeIDs=(ArrayList<Integer>) storedIDs.clone();
removeIDs.removeAll(downloadedIDs);

downloadIDs=(ArrayList<Integer>) downloadedIDs.clone();
downloadIDs.removeAll(storedIDs);

问题是两个列表都包含5000个孩子,我的androidphone需要大约4秒钟。

有没有快速的方法来做到这一点? 是否更快地使用集合?(我在列表中没有重复的值)

我开发了一个Android应用程序


7932
2018-03-12 20:32


起源



答案:


除非您需要保留订单,否则请使用HashSet而不是ArrayList。

删除元素需要扫描完整列表以进行列表实现,比较HashSet只是计算哈希码,然后识别目标桶。


7
2018-03-12 20:36





集应该更快。现在,它基本上做了一个n ^ 2循环。它遍历removeIDs中的每个元素,并检查该id是否在downloadedIDs中,这需要搜索整个列表。如果下载的ID存储在更快的搜索内容中,就像HashSet一样,这将更快,并且变为O(n)而不是O(n ^ 2)。 Collections API中可能还有更快的东西,但我不知道。

如果你需要preserver命令,你可以使用LinkedHashSet而不是普通的HashSet,但它会添加一些内存,并且插入/删除元素会有一些性能损失。


1
2018-03-12 20:37





我同意HashSet建议,除非整数ID适合相对较小的范围。在这种情况下,我将使用HashSet和BitSet中的每一个进行基准测试,并实际使用对您环境中的数据更快的数据。


1
2018-03-12 20:39





首先,我为长期答复道歉。如果我在任何时候都错了,欢迎你纠正我。在这里,我将比较解决方案的一些选项

选项1 <ArrayList>:

在您的代码中,您使用了 ArrayList.removeAll 方法让我们查看removeAll的代码

removeAll的源代码

public boolean removeAll(Collection<?> c) {
        return batchRemove(c, false);
    }

所以需要知道里面是什么 batchRemove 方法。这里是 链接。如果你能看到,这里的关键部分

for (; r < size; r++)
         if (c.contains(elementData[r]) == complement)
                 elementData[w++] = elementData[r];

现在让我们来看看 contains 方法只是一个包装 indexOf 方法。 链接。在indexOf方法中有一个O(n)操作。 (注意只是这里的一部分)

 for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                    return i;

总而言之,这是一个

为O(n ^ 2)

在...的运作 removeAll

选项2 <HashSet>: 以前我在这里写了一些东西,但似乎我在某些方面错了所以删除它。最好接受专家关于Hashset的建议。在您的情况下,我不确定hashmap是否是更好的解决方案。所以我提出另一个解决方案

选项3 <我的建议您可以尝试>:

步骤1: 如果您的数据已排序,则不需要此步骤,否则将对要减去的列表进行排序(第二个列表)

第2步: 对于未排序列表的每个元素,在第二个列表中运行二进制搜索

第3步: 如果找不到匹配,则存储在另一个结果列表中但如果找到匹配则不添加

步骤4: 结果列表是你的最终答案

备选方案3的费用: 

步骤1: 如果没有排序 O(nlogn) 时间

第2步:  O(nlogn) 时间

第3步:  O(n) 空间

**

整体O(nlogn)时间和O(n)空间

**


1
2018-03-13 04:09





如果需要列表,您可以选择一个 链表。在你的情况下,正如@Chris所说,ArrayList实现将移动每次删除中的所有元素。

使用LinkedList,您可以获得更好的随机添加/删除性能。看到这个 岗位


0
2018-03-12 21:13