Java 对于哈希表,.contains()方法要快多少<;ArrayList<;字符串>;,布尔值>;而不是ArrayList<;ArrayList<;字符串>>;?

Java 对于哈希表,.contains()方法要快多少<;ArrayList<;字符串>;,布尔值>;而不是ArrayList<;ArrayList<;字符串>>;?,java,performance,arraylist,hashmap,hashtable,Java,Performance,Arraylist,Hashmap,Hashtable,我基本上是这样做的: For 100000 words: List: - ms, Map: 166 ms For 500000 words: List: - ms, Map: 1130 ms For 1000000 words: List: - ms, Map: 3540 ms 将DB表中的整行数据作为字符串转储到ArrayList

我基本上是这样做的:

For 100000 words: List: - ms, Map: 166 ms
For 500000 words: List: - ms, Map: 1130 ms
For 1000000 words: List: - ms, Map: 3540 ms
  • 将DB表中的整行数据作为字符串转储到
    ArrayList
  • 对另一个DB表执行相同的操作

  • 在第二个数据库中的第一个数据库中,通过迭代并执行
    a.contains(b.get(i))
    查找所有行
    ArrayList
    。如果包含的内容为
    true
    ,则我执行
    a.remove(b.get(I))

现在,如果我使用Hashtable>而不是上面提到的使用
a.containsKey(I.getKey())
的Arraylist,其中I是b的迭代器,然后使用I.remove进行删除,那么速度会快多少?这是一个足够好的增加,使变化

另外,使用Hashmap会更谨慎吗?如果是,为什么

以下内容摘录如下:

运行size、isEmpty、get、set、iterator和listIterator操作 在固定时间内。“添加”操作在摊销的固定时间内运行, 也就是说,添加n个元素需要O(n)个时间。所有其他的 操作以线性时间运行(粗略地说)。常数因子 与LinkedList实现相比,该值较低

这意味着,第二个列表上的get操作以恒定时间O(1)运行,从性能角度来看,这应该是正常的。但是contains和remove操作(在第一个列表上)以线性时间O(n)运行。调用这些操作的次数与第二个列表的大小相同,这可能会持续很长时间,特别是当两个列表都很大时

对第一个使用散列数据结构将导致调用操作contains和remove的时间为常量O(1)。我建议对第一个“列表”使用哈希集。但这只适用于所有行不相等的情况

但在尝试优化某些东西之前,您应该始终进行分析。首先,确保您优化了正确的位置。

以下内容摘录如下:

运行size、isEmpty、get、set、iterator和listIterator操作 在固定时间内。“添加”操作在摊销的固定时间内运行, 也就是说,添加n个元素需要O(n)个时间。所有其他的 操作以线性时间运行(粗略地说)。常数因子 与LinkedList实现相比,该值较低

这意味着,第二个列表上的get操作以恒定时间O(1)运行,从性能角度来看,这应该是正常的。但是contains和remove操作(在第一个列表上)以线性时间O(n)运行。调用这些操作的次数与第二个列表的大小相同,这可能会持续很长时间,特别是当两个列表都很大时

对第一个使用散列数据结构将导致调用操作contains和remove的时间为常量O(1)。我建议对第一个“列表”使用哈希集。但这只适用于所有行不相等的情况

但在尝试优化某些东西之前,您应该始终进行分析。首先确保您优化了正确的位置。

我的自下而上回答:

  • Hashtable和HashMap之间的区别已经(彻底地)在中讨论过。简短总结:HashMap更有效,应该使用它来代替Hashtable

  • 在散列数据结构(contains()和remove()操作)中查找数据的顺序为O(log2)——也就是说,它与结构中数据点数量的2对数成正比。如果有4个数据元素,则需要X时间;如果有8个元素,则需要2倍的时间、16个元素、3倍的时间,以此类推。哈希结构的数据访问时间增长非常缓慢。
    在列表中查找数据的顺序为O(N)-也就是说,与列表中元素的数量成正比。1个元素占用Y时间,2个元素占用2Y时间,4个元素占用4Y时间,依此类推。因此,时间消耗随着列表的大小呈线性增长。

  • 因此:如果必须从数据结构中随机查找大量元素,则哈希数据结构是最佳选择,只要:
    数据具有适当的hashCode()实现(ArrayList的实现是可以的)
    数据具有相互匹配的hashCode()和equals()实现,即如果a.equals(b)则a.hashCode()==b.hashCode()。ArrayList也是如此

  • 另一方面,如果您处理的是有序数据,那么还有其他算法可以大大减少搜索和删除时间。如果数据库中的数据已编制索引,则在获取数据时使用ORDER BY,然后使用排序数据的算法可能是值得的

总结:对列表a使用HashMap而不是ArrayList

我写了一个小程序来测试这个问题。结果一:该程序在Sun JVM 1.6.0)41上运行,Windows 7为32位,在核心i5 2.40 GHz CPU上运行。打印输出:

For 1000 words: List: 1 ms, Map: 2 ms
For 5000 words: List: 15 ms, Map: 12 ms
For 10000 words: List: 57 ms, Map: 12 ms
For 20000 words: List: 217 ms, Map: 37 ms
For 30000 words: List: 485 ms, Map: 45 ms
For 50000 words: List: 1365 ms, Map: 61 ms
在这样一个简单的测试中,性能特征表现得非常好。我使用更多数据运行了地图版本,并得到以下结果:

For 100000 words: List: - ms, Map: 166 ms
For 500000 words: List: - ms, Map: 1130 ms
For 1000000 words: List: - ms, Map: 3540 ms
最后,基准测试代码:

public void benchmarkListVersusMap() {
    for (int count : new int[]{1000, 5000, 10000, 20000, 30000, 50000}) {
        // Generate random sample data
        List<List<String>> words = generateData(count, 10, count);

        // Create ArrayList
        List<List<String>> list = new ArrayList<List<String>>();
        list.addAll(words);

        // Create HashMap
        Map<List<String>, Boolean> map = new HashMap<List<String>, Boolean>();
        for (List<String> row : words) {
            map.put(row, true);
        }

        // Measure:
        long timer = System.currentTimeMillis();
        for (List<String> row: words) {
            if (list.contains(row)) {
                list.remove(row);
            }
        }
        long listTime = System.currentTimeMillis() - timer;
        timer = System.currentTimeMillis();
        for (List<String> row : words) {
            if (map.containsKey(row)) {
                map.remove(row);
            }
        }
        long mapTime = System.currentTimeMillis() - timer;
        System.out.printf("For %s words: List: %s ms, Map: %s ms\n", count, listTime, mapTime);
    }
}

private List<List<String>> generateData(int rows, int cols, int noOfDifferentWords) {
    List<List<String>> list = new ArrayList<List<String>>(rows);
    List<String> dictionary = generateRandomWords(noOfDifferentWords);
    Random rnd = new Random();
    for (int row = 0; row < rows; row++) {
        List<String> l2 = new ArrayList<String>(cols);
        for (int col = 0; col < cols; col++) {
            l2.add(dictionary.get(rnd.nextInt(noOfDifferentWords)));
        }
        list.add(l2);
    }
    return list;
}

private static final String CHARS = "abcdefghijklmnopqrstuvwxyz0123456789";
private List<String> generateRandomWords(int count) {
    Random rnd = new Random();
    List<String> list = new ArrayList<String>(count);
    while (list.size() < count) {
        StringBuilder sb = new StringBuilder(20);
        for (int i = 0; i < 10; i++) {
            sb.append(CHARS.charAt(rnd.nextInt(CHARS.length())));
        }
        list.add(sb.toString());
    }
    return list;
}
public void benchmarkListVersusMap(){
对于(整数计数:新整数[]{1000、5000、10000、20000、30000、50000}){
//生成随机样本数据
列出单词=生成数据(计数,10,计数);
//创建ArrayList
列表=新的ArrayList();
list.addAll(单词);
//创建哈希映射
Map Map=newhashmap();
for(列表行:单词){
map.put(行,true);
}
//措施:
长定时器=System.currentTimeMillis();
for(列表行:单词){
if(列表包含(行)){
列表。删除(行);
}
}
long listTime=System.currentTimeMillis()-定时器;
计时器=System.currentTimeMillis();