二,具体的集合
集合类型 | 描述 |
ArrayList | 一种可以动态增长和缩减的索引序列 |
LinkedList | 一种可以在任何位置进行高效地插入和删除操作的有序序列 |
ArrayDeque | 一种用循环数组实现的双端队列 |
HashSet | 一种没有重复元素的无序集合 |
TreeSet | 一种有序集 |
EnumSet | 一种包含枚举类型值的集 |
LinkedHashSet | 一种可以记住元素插入次序的集合 |
PriorityQueue | 一种允许高效删除最小元素的集合 |
HashMap | 一种存储键/值关联的数据结构 |
TreeMap | 一种键值有序排列的映射表 |
EnumMap | 一种键值属于枚举型的映射表 |
LinkedHashMap | 一种可以记住键/值项添加次序的映射表 |
WeakHashMap | 一种其值无用武之地后可以被垃圾回收器回收的映射表 |
IdentityHashMap | 一种用==,而不是用equals比较键值的映射表 |
如上表,除了以Map结尾的类之外,其他类都实现了Collection接口。而以Map结尾的类实现了Map接口。
1.链表
数组和数组列表都有一个很大的缺陷,从数组的中间位置删除一个元素要付出很大的代价,因为数组中处于被删除元素之后的所有元素都要向数组的前端移动。在数组的中间位置上插入一个元素也是如此。然而,链表正好解决了这个问题。
所有的链表都是双向链接的,链表将每个对象存放在独立的结点中。每个结点都存放着序列中下一个结点的引用 和 前驱结点的引用。
链表提供了get()方法来访问特定的元素。绝对不应该使用for循环来遍历链表效率极低。每次查找一个元素都要从列表的头部重新开始搜索,LinkedList对象根本不做任何缓存位置信息的操作。
列表迭代器接口还有一个方法,可以告之当前位置的索引。实际上,由于Java迭代器指向两个元素之间的位置,所以可以同时产生两个索引:nextIndex方法返回下一个调用next方法时返回元素的整数索引;previousIndex方法返回下一次调用previous方法时返回元素的整数索引。这两种方法的效率比较高。
2.散列表
链表和数组可以按照人们的意愿来排序元素的次序。但是想查看某个指定的元素,却又忘记了它的位置,就需要访问所有的元素,直到找到为止。散列表解决了这个问题,散列表为每个对象计算一个整数,称为散列码(hash code)。不同数据区域的对象将产生不同的散列码。
在Java中,散列表用列表数组实现。每个列表被称为桶(bucket),如果大致知道最终会有多少个元素插入到元素中,就可以设置桶数。最好将桶数设置为一个素数,以防键的集聚,桶数设置为元素个数的75%-150%。
散列表可以用于实现几个重要的数据结构。其中最简单的是set类型。set是没有重复元素的元素集合。set的add方法首先在集中查找要添加的对象,如果不存在,就将这个对象添加进去。
Java类库中提供了一个HashSet类,它实现了基于散列表的集。可以用add方法添加元素。contains方法已经被重新定义,用来快速地查看是否某个元素已经出现在集中。
3.树集
TreeSet与散列集十分相似,不过,它比散列集有所改进。树集是一个有序集合,可以以任意顺序将元素插入到集合中,在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现。例如:
SortedSet<String> sorter = new TreeSet<String>(); sorter.add("Bob"); sorter.add("Amy"); sorter.add("Carl"); for(String sorter) System.println(s);
这时候,打印出来:Amy,Bob,Carl。将一个元素添加到树中要比添加到散列表中慢,但是,与将元素添加到数组或者链表的正确位置上相比还是快很多的。如果树中包含了n个元素,查找新元素的正确位置平均需要log以2为底n次方比较。因此,将一个元素添加到TreeSet中要比添加到HashSet中慢。
4.优先级队列
优先级队列中的元素可以按照任意顺序插入,但总是按照排序进行检索。也就是说何时调用remove方法,总会获得当前优先级队列中最小的元素。
典型实例就是任务调度。
5.映射表
通常,我们知道某些键的信息,并想要查找与之对应的元素。映射表(map)数据结构就是为此设计的。映射表用来存放键/值对。如果提供了键,就能找到值。Java类库为映射表提供了两个通用的实现:HashMap和TreeMap。这两个类都实现了Map接口。