[英]How to check if ArrayList<ArrayList<String>> contains a certain ArrayList<String>
[英]How much faster will a .contains() method be for a Hashtable<ArrayList<String>,boolean> than an ArrayList<ArrayList<String>>?
我基本上是在做以下事情:
ArrayList< ArrayList< String>>
。 對另一個數據庫表執行相同的操作。
通過遍歷第二個數據庫並執行a.contains(b.get(i))
來a.contains(b.get(i))
第二個數據庫中第一個數據庫中的所有行ArrayList< String>
。 如果包含為true
則執行a.remove(b.get(i))
現在,如果我改為使用Hashtable <Arraylist <String >>而不是上面使用a.containsKey(i.getKey())
提到的ArrayList的速度要快多少,其中i是b上的迭代器,然后使用i刪除。去掉 ? 進行更改是否足夠好?
另外,使用Hashmap會更謹慎嗎? 如果是這樣,為什么...
我的自下而上的答案:
Hashtable和HashMap之間的區別已經(徹底) 在HashMap和Hashtable之間的區別中進行了討論。 。 簡短摘要: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,然后對有序數據使用算法。
總結一下:使用HashMap代替ArrayList作為列表a。
我編寫了一個小程序來對問題進行基准測試。 結果優先:程序在Core i5 2.40 GHz CPU上的Windows 7(32位)的Sun JVM 1.6.0_41上運行。 打印:
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;
}
size isEmpty,get,set,iterator和listIterator操作在恆定時間內運行。 加法運算以固定的固定時間運行,也就是說,添加n個元素需要O(n)時間。 所有其他操作均以線性時間運行(大致而言)。 與LinkedList實現相比,常數因子較低。
這意味着,第二個列表上的get操作在恆定時間O(1)上運行,從性能角度來看應該可以。 但是contains和remove操作(在第一個列表上)在線性時間O(n)中運行。 以第二個列表的大小多次調用這些操作可能會持續很長時間,尤其是在兩個列表都很大的情況下。
對於第一個使用哈希數據結構將導致恆定的時間-O(1)-調用操作包含和刪除。 我建議對第一個“列表”使用HashSet。 但這僅在所有行都不相等的情況下有效。
但是,在嘗試優化某些東西之前,您應該始終進行概要分析。 首先,請確保您在正確的位置進行優化。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.