Java笔记之 3. 数据结构

2018-03-13  本文已影响33人  黎明你好

通常学习的数据结构分为:表、栈、队列、集合、哈希、树、图。

Java对其中一部分有自己的实现。

表:线性表ArrayList,链表LinkedList,线程安全Vector。

集合:Set、SortedSet、HashSet、TreeSet。

哈希:Map、HashMap、TreeMap、Hashtable、SortedMap、LinkedHashMap。

栈:线性栈Stack

队列:Queue、Deque

主要的顶层接口:

一、List:

继承关系:


image

主要实现类功能:

add:前端O(N2),后端:都O(1)
get: O(1)
remove:O(N2)
for循环:O(N)(循环的N次)
add:前端LinkedList - O(1), 后端:O(1)
get: O(N)
remove:LinkedList - O(N),
for循环:O(N2)(循环N次,getN次)

使用了一种叫写时复制的方法,当有新元素添加到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。整个add操作都是在锁的保护下进行的。
这样做是为了避免在多线程并发add的时候,复制出多个副本出来,把数据搞乱了,导致最终的数组数据不是我们期望的。

ArrayList & LinkedList & Vector

  1. ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
  2. Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
  3. LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用

二、Set

集成关系:


image

HashSet & TreeSet

  1. TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值。
  2. HashSet 是哈希表实现的,HashSet中的数据是无序的,只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束。
  3. HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的 String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例 。

二、队列

继承关系:


image

非阻塞队列:

阻塞队列:BlockingQueue

接口和五个阻塞队列类。它实质上就是一种带有一点扭曲的 FIFO 数据结构。不是立即从队列中添加或者删除元素,线程执行操作阻塞,直到有空间或者元素可用。
五个队列所提供的各有不同:

双向队列Deque

image

三、哈希Map

继承关系:

image

主要的实现有:HashMap、TreeMap、LinkedHashMap、Hashtable

Hashtable & HashMap

Hashtable和HashMap它们的性能方面的比较类似 Vector和ArrayList,比如Hashtable的方法是同步的,而HashMap的不是。

最后:合理配置集合类的初始大小

在Java集合框架中的大部分类的大小是可以随着元素个数的增加而相应的增加的,我们似乎不用关心它的初始大小,但如果我们考虑类的性能问题时,就一定要考虑尽可能地设置好集合对象的初始大小,这将大大提高代码的性能。

比如,Hashtable缺省的初始大小为101,载入因子为0.75,即如果其中的元素个数超过75个,它就必须增加大小并重新组织元素,所以,如果你知道在创建一个新的Hashtable对象时就知道元素的确切数目如为110,那么,就应将其初始大小设为110/0.75=148,这样,就可以避免重新组织内存并增加大小

上一篇 下一篇

猜你喜欢

热点阅读