Java各种数据结构-源码与应用

Java核心类库自带的数据结构有(以下是我用过的,估计还有不少我没用过的):
Deque, 等接口

具体数据结构(Concrete Data Structures)
  1. 定长数组
  2. 双向链表(LinkedList,但不把链表结构暴露给你)
  3. 哈希表(HashMap,同样不把具体实现暴露给你)
  4. TreeMap(底层是红黑树,但还是不暴露给你)
  5. LinkedHashMap和LinkedHashSet(哈希表和链表的组合,同样不暴露底层)
  6. 优先队列(看源码底层是个二叉堆,但是不暴露给你)
抽象数据结构(Abstract Data Structures)
  1. 列表(List,一维ordered容器,有多种实现)
  2. Set(一维无重复集合,有多种实现)
  3. HashSet和TreeSet(用HashMap和TreeMap实现的set)
  4. 栈(Stack,后进先出的容器)
  5. 队列(Queue,先进先出的容器)
  6. 优先队列(PriorityQueue,又称堆,英文叫Heap,注意这玩意儿不是队列)
考虑并发的变种数据结构
  1. ConcurrentHashMap和ConcurrentHashSet等
  2. BlockingQueue
其他数据结构
  1. ArrayDeque
  2. DelayQueue
  3. ....

ArrayList(数组)

ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。

Vector(数组实现、线程同步)

Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。

LinkList(链表)

LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。

Set

Set注重独一无二的性质,该体系集合用于存储无序(存入和取出的顺序不一定相同)元素,值不能重复。对象的相等性本质是对象hashCode值(java是依据对象的内存地址计算出的此序号)判断的,如果想要让两个不同的对象视为相等的,就必须覆盖Object的hashCode方法和equals方法。

HashSet(Hash表)

哈希表边存放的是[哈希值]。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 而是按照哈希值来存的所以取数据也是按照哈希值取得。元素的哈希值是通过元素的hashcode方法来获取的, HashSet首先判断两个元素的哈希值,如果哈希值一样,接着会比较equals方法 如果 equls结果为true ,HashSet就视为同一个元素。如果equals 为false就不是同一个元素。 哈希值相同equals为false的元素是怎么存储呢,就是在同样的哈希值下顺延(可以认为哈希值相同的元素放在一个哈希桶中)。也就是哈希一样的存一列。如图1表示hashCode值不相同的情况;图2表示hashCode值相同,但[equals]不相同的情况。

HashSet通过hashCode值来确定元素在内存中的位置。一个hashCode位置上可以存放多个元素。

TreeSet([二叉树]

1.TreeSet()是使用二叉树的原理对新add()的对象按照指定的顺序排序([升序]、降序),每增加一个对象都会进行排序,将对象插入的二叉树指定的位置。
2.Integer和String对象都可以进行默认的TreeSet排序,而自定义类的对象是不可以的,自己定义的类必须实现Comparable接口,并且覆写相应的compareTo()函数,才可以正常使用。
3.在覆写compare()函数时,要返回相应的值才能使TreeSet按照一定的规则来排序
4. 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或[正整数]

LinkHashSet(HashSet+LinkedHashMap)

对于LinkedHashSet而言,它继承与HashSet、又基于LinkedHashMap来实现的。LinkedHashSet底层使用LinkedHashMap来保存所有元素,它继承与HashSet,其所有的方法操作上又与HashSet相同,因此LinkedHashSet 的实现上非常简单,只提供了四个构造方法,并通过传递一个标识参数,调用父类的构造器,底层构造一个LinkedHashMap来实现,在相关操作上与父类HashSet的操作相同,直接调用父类HashSet的方法即可。

hashmap

java7的时候:
大方向上,HashMap 里面是一个数组,然后数组中每个元素是一个单向链表。上图中,每个绿色的实体是嵌套类 Entry 的实例,Entry 包含四个属性:key, value, hash 值和用于单向链表的 next。
1. capacity:当前数组容量,始终保持 2^n,可以扩容,扩容后数组大小为当前的 2 倍。
2. loadFactor:负载因子,默认为 0.75。
3. threshold:扩容的阈值,等于 capacity * loadFactor

java8的时候:
Java8 对 HashMap 进行了一些修改,最大的不同就是利用了[红黑树],所以其由 数组+链表+红黑树 组成。 根据 Java7 HashMap 的介绍,我们知道,查找的时候,根据 hash 值我们能够快速定位到数组的具体下标,但是之后的话,需要顺着链表一个个比较下去才能找到我们需要的,时间复杂度取决于链表的长度,为 O(n)。为了降低这部分的开销,在 Java8 中,当链表中的元素超过了 8 个以后,会将链表转换为红黑树,在这些位置进行查找的时候可以降低时间复杂度为 O(logN)。

hsahHashTable

HashTable和HashMap的实现原理几乎一样,差别无非是
HashTable不允许key和value为null
HashTable是线程安全的
但是HashTable线程安全的策略实现代价却太大了,简单粗暴,get/put所有相关操作都是synchronized的,这相当于给整个哈希表加了一把大锁。
多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差。

ConcurrentHashMap

其实可以看出JDK1.8版本的ConcurrentHashMap的[数据结构]已经接近HashMap,相对而言,ConcurrentHashMap只是增加了同步的操作来控制并发,
从JDK1.7版本的ReentrantLock+Segment+HashEntry,到JDK1.8版本中synchronized+CAS+HashEntry+红黑树。
1.数据结构:取消了Segment分段锁的数据结构,取而代之的是数组+链表+红黑树的结构。
2.保证线程安全机制:
JDK1.7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。
JDK1.8采用CAS+Synchronized保证线程安全。
3.锁的粒度:原来是对需要进行数据操作的Segment加锁,现调整为对每个数组元素加锁(Node)。
4.链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。
5.查询时间复杂度:从原来的遍历链表O(n),变成遍历红黑树O(logN)。


Java常见数据结构

1、数组;
2、链表,一种递归的数据结构;
3、栈,按照“后进先出”、“先进后出”的原则来存储数据;
4、队列;
5、树,是由 n(n>0)个有限节点组成的一个具有层次关系的集合;
6、堆;
7、图;
8、哈希表。

1、数组;

优点:
按照索引查询元素的速度很快
按照索引遍历数组也很方便
缺点:
数组的大小在创建后就确定了,无法扩容
数组只能存储一种类型的数据
添加、删除元素的操作很耗时间,因为要移动其他元素。

2、链表,一种递归的数据结构;

链表是一种递归的数据结构,它或者未空,或者指向一个结点(node)的引用,该节点还有一个元素和一个指向另一条链表的引用。
Java的LinkedList类可以很形象地通过代码的形式来表示一个链表的结构。
这是一个双向链表,当前元素既有prev又有next,不过first的prev为null,last的next为null。
优点:
不需要初始化容量
可以添加任意元素
插入和删除的时候只需要更新引用

缺点:
含有大量的引用,占用内存空间大
查找元素需要遍历整个链表,耗时

3、栈,按照“后进先出”、“先进后出”的原则来存储数据;

栈就像水桶一样,底部是密封的,顶部是开口,水可以进可以出

4、队列;

队列就像水管,两端都是开口,水从一端进去,然后从另外一端出来。
队头只允许删除操作,队尾只允许插入操作

5、树,是由 n(n>0)个有限节点组成的一个具有层次关系的集合;

二叉树,满二叉树,二叉查找树,平衡二叉树,红黑树,B树

6、堆;

堆可以被看成一棵树的数组对象,
堆中某个节点的值总是不大于或不小于其父节点的值
堆总是一棵完全二叉树

7、图;

图是一种复杂的非线性结构,有顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E)
其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。

8、哈希表。

哈希表,也叫散列表,是一种可以通过关键码值(key-value)直接访问的数据结构,它最大的特点就可以快速实现查找、插入和删除。

如果哈希冲突了,Java的hashmap会在数组的同一个位置上增加链表,如果链表的长度大于8,将会转化成红黑树进行处理-这就是所谓的拉链法(数组+链表)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码云笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值