哈希表:
哈希表底层,使用的也是数组机制数组中也存放对象,而这些对象往数组中存放时的位置比较特殊,当需要把这些对象给数组中存放时,那么会根据这些对象的特有数据结合相应的算法,计算出这个对象在数组中的位置,然后把这个对象存放在数组中。而这样的数组就称为哈希数组,即就是哈希表。
HashMap就是一个插入慢、查询快的数据结构。
HashMap:数组+链表
HashSet:底层就是hashMap,实际也是:数组+链表
TreeMap:红黑树
TreeSet: 底层就是 TreeMap,实际也是:红黑树
SortedSet:底层是TreeSet,实际也是:红黑树
LinkedList:底层是一个双向链表
*******************************【红黑树和平衡二叉树的比较】***************************************************************
RB-Tree和AVL树作为BBST,其实现的算法时间复杂度相同,AVL作为最先提出的BBST,貌似RB-tree实现的功能都可以用AVL树是代替,那么为什么还需要引入RB-Tree呢?
- 红黑树不追求"完全平衡",即不像AVL那样要求节点的
|balFact| <= 1
,它只要求部分达到平衡,但是提出了为节点增加颜色,红黑是用非严格的平衡来换取增删节点时候旋转次数的降低,任何不平衡都会在三次旋转之内解决,而AVL是严格平衡树,因此在增加或者删除节点的时候,根据不同情况,旋转的次数比红黑树要多。 - 就插入节点导致树失衡的情况,AVL和RB-Tree都是最多两次树旋转来实现复衡rebalance,旋转的量级是O(1)
删除节点导致失衡,AVL需要维护从被删除节点到根节点root这条路径上所有节点的平衡,旋转的量级为O(logN),而RB-Tree最多只需要旋转3次实现复衡,只需O(1),所以说RB-Tree删除节点的rebalance的效率更高,开销更小! - AVL的结构相较于RB-Tree更为平衡,插入和删除引起失衡,如2所述,RB-Tree复衡效率更高;当然,由于AVL高度平衡,因此AVL的Search效率更高啦。
- 针对插入和删除节点导致失衡后的rebalance操作,红黑树能够提供一个比较"便宜"的解决方案,降低开销,是对search,insert ,以及delete效率的折衷,总体来说,RB-Tree的统计性能高于AVL.
- 故引入RB-Tree是功能、性能、空间开销的折中结果。
5.1 AVL更平衡,结构上更加直观,时间效能针对读取而言更高;维护稍慢,空间开销较大。
5.2 红黑树,读取略逊于AVL,维护强于AVL,空间开销与AVL类似,内容极多时略优于AVL,维护优于AVL。
基本上主要的几种平衡树看来,红黑树有着良好的稳定性和完整的功能,性能表现也很不错,综合实力强,在诸如STL的场景中需要稳定表现。
红黑树的查询性能略微逊色于AVL树,因为其比AVL树会稍微不平衡最多一层,也就是说红黑树的查询性能只比相同内容的AVL树最多多一次比较,但是,红黑树在插入和删除上优于AVL树,AVL树每次插入删除会进行大量的平衡度计算,而红黑树为了维持红黑性质所做的红黑变换和旋转的开销,相较于AVL树为了维持平衡的开销要小得多
HashSet
hashset集合采用hash算法来决定元素的存储位置不同,TreeSet采用红黑数的数据结构来存储集合元素,那么TreeSet的两种排序方法:自然排序和定制排序。默认情况下才用自然排序(按照升序排列);
1、不能保证元素的排序顺序,顺序可能与添加顺序不同,顺序也有可能发生变化;
2、HashSet不是同步的,如果多个线程同时访问一个HashSet,假设有两个或者两个以上线程同时修改了HashSet集合时,则必须通过代码来保证其同步;
3、集合元素值可以是NULL,键不能为NULL;
TreeSet
HashSet和TreeSet是Set的两个典型实现,到底如何选择HashSet和TreeSet呢?HashSet的性能总是比TreeSet好(特别是常用的添加、查询元素操作),因为TreeSet需要额外的的红黑书算法来维护集合元素的次序。只有当需要一个保持排序的Set时,才应该使用TreeSet,否则都应该使用HashSet。
HashSet还有一个子类:LinkedHashSet,对于普通的插入、删除操作,LinkedHashSet比HashSet要略微慢一点,这是由维护链表所带来的额外开销造成的,但由于有了链表, 遍历LinkedHashSet会更快。
EnumSet是所有Set实现类中性能最好的,但他只能保存同一个枚举的枚举值作为集合元素。
必须指出的是Set三个实现类HashSet、TreeSet、EnumSet都是线程不安全的。如果有多个线程同时访问一个Set集合,并且超过一个线程修改了该Set集合,则必须手动保持该Set集合的同步性,通过可以通过Collections工具类的synchronizedSortedSet方法来包装该Set集合。此操作最好在创建时进行,以防止对Set集合的意外非同步访问。例如:
Collection c=Collections.synchronizedCollection(new ArrayList());
EnumSet
EnumSet是一个专为枚举类型设计的集合类,EnumSet中的所有元素都必须是指定的枚举类型的枚举值,该枚举类型在创建EnumSet时显示或隐式地指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum类内的定义顺序来决定集合元素的顺序。
EnumSet在内部以位向量的形式存储,这种存储形式非常紧凑、高效,因此EnumSet对象占用的内存很小,而且运行效率很好。尤其是进行批量操作时如果其参数也EnumSet集合,则批量操作的执行速度也非常快。
EnumSet集合不允许加入null元素,如果试图插入null元素,EnumSet将抛出NullPointerException异常,如果只是想判断EnumSet是否包含null元素或者试图删除null元素都不会抛出异常,只是删除操作将返回false,因为没有任何null元素被删除。
EnumSet es1=EnumSet.allof(Season.class);
List集合
List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合允许使用重复元素,可以通过索引来访问制定位置的集合元素。List集合默认按元素的添加顺序设置元素的索引,例如第一次添加元素的索引为0,第二次添加元素的索引为1.。。。;
List作为Collection接口的子接口,当然可以使用Collection接口里的全部方法,而且由于List是有序集合,因此List集合里增加了一些根据索引来操作集合元素的方法。
ArrayList和Vector实现类
ArrayList和Vector作为List类的两个典型实现,完全支持前面介绍的List接口的全部功能;
ArrayList和Vector类都是基于数组实现的List类,所以ArrayList和Vector类封装了一个动态的、允许再分配ideaObject[]数组。ArrayList或Vector对象使用initalCapacity参数来设置该数组的长度,当向ArrayList或Vector中添加元素超出了该数组的长度时,他们的initalCapacity会自动增加。
ArrayList和Vector的显著区别是:ArrayList是线程不安全的,当多个线程访问同一个集合时,如果有超过一个线程修改了ArrayList集合,则程序必须手动保证该集合的同步性;但Vector集合是线程安全的,无须程序保证集合的同步性,因为Vector是线程安全的,所以Vector性能比ArrayList的性能要低,实际上,即使需要保证List集合线程安全,也同样不推荐使用Vector实现类,后面会介绍一个Collectioins工具类,他可以将一个ArrayList变成线程安全的。