Java 集合类的复杂度分析
本文章对基于二分搜索树实现的集合Set和基于动态链表实现的集合Set两者做一个性能上的比较。
定义测试类:
import java.util.ArrayList;
public class Main {
private static double testSet(Set<String> set, String filename){
long startTime = System.nanoTime();
System.out.println(filename);
ArrayList<String> words = new ArrayList<>();
if(FileOperation.readFile(filename, words)) {
System.out.println("Total words: " + words.size());
for (String word : words) {
set.add(word);
}
System.out.println("Total different words: " + set.getSize());
}
long endTime = System.nanoTime();
return (endTime - startTime) / 1000000000.0;
}
public static void main(String[] args) {
String filename = "pride-and-prejudice.txt";
BSTSet<String> bstSet = new BSTSet<>();
double time1 = testSet(bstSet, filename);
System.out.println("BST Set: " + time1 + " s");
System.out.println();
LinkedListSet<String> linkedListSet = new LinkedListSet<>();
double time2 = testSet(linkedListSet, filename);
System.out.println("Linked List Set: " + time2 + " s");
}
}
打印结果:
从结果可以看出基于二分搜索树实现的集合运行要比链表集合要块很多的。
分析集合:LinkedListSet、BSTSet
h为二分搜索树的深度。
由于O(n)与 O(h)中的n与h情况不一,故对此进行分析。
下面分析满的二分搜索树复杂度情况。
满的二分搜索树每一层元素的数量关系:
直到h层,那么层会有多少个节点呢?
如果令,那么
。
由于一般不关注线性关系,例如1n,2n,3n,所以
下面对logn与n进行比较:
logn | n | ||
n = 16 | 4 | 16 | 相差4倍 |
n = 1024 | 10 | 1024 | 相差100倍 |
n = 100万 | 20 | 100万 | 相差5万倍 |
虽然二分搜索树集合的平均情况为O(logn),但却是非常的快了。
最坏的二分搜索树情况O(n):二分搜索树的所有左字节点都为空,这样就形成了与链表形状的模样了。此时二分搜索树的节点树就等于它的高度,所以二分搜索树就会退化成为链表。如何优化它呢?使用平衡二叉树!