1 Java中的数据结构
存放数据最常用的数据结构有:栈
、队列
、数组
、链表
和散列
。
先看一个解释:
火车在人字形轨道调头,头先进去,尾巴先出来,这就是栈
。
排队等公交,先来的先上车,这就是队列
。
上体育课的时候,老师说:你们站一队,每个人记住自己是第几个,我喊到几,那个人就举手,这就是数组
。
老是说,你们每个人记住自己前面的人和后面的人,然后老师只知道第一人是谁,然后你们各自由活动,老是要找某一个人,是不是每次都是从第一个开始往自己身后的人开始传达?这就是链表
。
老师说: 大家1,2,3,4报数,凡是报1,为1队,凡是报2的为2队。。。 这就是散列(哈希)
。
这个4就相当于预定义好的桶
的个数。
1.1 栈
数据操作:先进后出,能够保证递归的正确顺序(按顺序的执行,按顺序的返回)。
应用:Java栈中的操作数栈
,不管深度
如何,都能保证线程
按正确顺序执行。
1.2 队列
数据操作: 先进先出。
应用:Java中的阻塞队列(BlockingQueue)
。
1.3 数组
操作数据(增加): 是将原数组的数据复制一份,再加上增加的对应位置的数据,形成一个新的数组。所以较慢。
查找数据:数组是有下标的,根通过索引(下标),可以快速访问指定位置的元素。
应用:Java中的数组(Array)
。
1.4 链表
一个链表的数据单元分两部分
,一部分是存储数据
,一部分是下一个链表单元数据的地址
,一个指向下一个,就这样构成了链表:
数据1|单元2地址
数据2|单元3地址
数据3|单元4地址
...
操作数据(增加):如 a-b。在ab之间增加一个c,增加c这个单元,并修改c的“下一个链表单元的地址”为b的地址,并将a的“下一个链表单元的地址”修改为c的地址即可。
取出数据:根据上一个数据,才能找到下一个数据,这个操作有点慢。
应用:Java中链表的实现很多有ArrayList
等,而LinkedList
是双向的。
单元1地址|数据2|单元3地址
单元2地址|数据3|单元4地址
单元3地址|数据4|单元5地址
...
1.5 哈希(散列)
1.5.1 概念
哈希表:是数组
和链表
的结合体,将数据(Value)
转成Hash值(Key)
然后存在一个数组
中,而数据(Value)
放到了链表中,它俩有一个映射关系,能通过Key找到该Value。
结构:{Key1:Value1},{Key2:Value2},{Key3:Value3}
Hash表是个链接式列表的阵列,每个链表称为一个
buckets
(哈希表元);
对象位置的计算index = HashCode % buckets
(HashCode为对象哈希码,buckets为哈希表元总数);
关键字K之间建立一个对应关系H,使每个关键字K与结构中的一个位置相对应;
这个对应关系H为哈希函数,H(K)的值为哈希地址或散列地址,按这个思想建立的表为哈希表。
应用:Java中的实现有HashMap
等。
1.5.2 哈希冲突
对不同的关键字可能根据哈希函数得到相同的地址值,即有:K1≠K2,而H(K1)=H(K2)
,这种现象称为冲突,具有相同函数值的不同关键字称为同义词。
解决hash冲突的方式有两种:链地址法
,公共溢出区
。
- 1 链地址法
挂链式的思想在产生冲突的hash地址指向一个链表,将具有相同的key值的数据存放到链表中。
例如,某个对象的哈希码是7,而哈希表元为3,那么7%3=1,因此,该对象就放在哈希表元为1的链表中。
如果该表上已经有一个对象了,那么就接着这个对象放在后面就行了。
- 2 公共溢出区
建立一个公共溢出区,将所有产生冲突的数据都存放到公共溢出区,也可以使问题解决。
1.6 树
树是一个有序的数据结构,可以以任意顺序将数据插入树中,每将一个元素添加到树中时,都会被放置到正确的排序位置上。
应用:Java中的实现有TreeSet
、TreeMap
等。