目录
5.哈希表
如下图所示,这就是一个哈希表的结构。哈希表基于数组来进行存储,但它是通过哈希函数直接计算得到元素的具体位置,与数组的顺序存储有本质的区别。查找一个指定值的元素时,顺序存储必须从头开始遍历直到找到为止,而哈希表则只需要计算一次地址就能获取到该元素。因此,哈希表的查找速度非常的快,查找效率远胜于其他的数据结构。
常用的计算地址的哈希函数有:直接定址、数字分析、平方取中、除留余数。
常用的冲突处理办法有:开放定址法、链地址法。Java 中就使用了链地址法作为冲突处理方法。
Java 中的哈希表存储元素过程:
① 在内存中开辟一个长度为 16 的数组,可根据需求扩充;
② 通过 hashCode ( ) 方法计算元素的哈希编码;
③ 通过一个哈希函数来计算该编码在数组中的位置,查看该位置是否有元素。若没有元素新建链表并在此位置保存其地址;
④ 通过 equals ( ) 方法判断与链式存储在该位置的所有元素是否相同。若相同直接引用元素地址,若不相同则在链尾追加此元素。
注意:
在 JDK 1.8 以前,哈希表均采用数组加链表的形式。在 JDK 1.8 之后,又加入了红黑树,在链表长度大于 8 时自动转换为红黑树结构,加快了查找速度。
下面用除留余数法 + 链地址法模拟元素的存储过程:
public static void main(String[] args) {
//第一步:新建一个长度16的数组空间,使用前面文章定义的链表结构
LinkList<String>[] address = new LinkList[16];//记录链表地址
//第二步:计算字符串 "重地" 的哈希编码
String str = "重地";
int hashCode = str.hashCode();//1179395
//第三步:根据除留余数发计算哈希编码在数组中的位置
int index = hashCode % 16;//3
//第四步:判断此位置是否有元素并存储该元素
//没有元素新建链表添加元素
if (address[index] == null) {
LinkList<String> linkList = new LinkList<>();
address[index] = linkList;
linkList.add(str);
} else {
//有元素保存元素
keep(address[index], str);
}
}
//保存元素的方法
private static void keep(LinkList linkList, String element) {
//有元素使用equals()判断是否有相同元素,相同引用地址,不相同添加元素
boolean flag = false;
for (int i = 0; i < linkList.size(); i++) {
if (linkList.equals(element)) {
element = linkList.get(i);//有相同元素引用地址
flag = true;
break;
}
}
//无相同元素添加元素
if (flag == true) {
linkList.add(element);
}
}
6.红黑树
(1)什么是树结构
![](https://i-blog.csdnimg.cn/blog_migrate/cb0efe9aa75be2c53baedd4fd112489b.png)
树是一种非线性的数据结构,它是由n(n >= 1)个有限结点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
①每个结点有零个或多个子结点;没有父结点的结点称为根结点;
②每一个非根结点有且只有一个父结点;
③除了根结点外,每个子结点可以分为多个不相交的子树。
(2)二叉树的定义
①每个结点最多只有两颗子树,即每个结点的孩子结点只能有0,1,2个;
②子树有左右顺序之分,不能颠倒。
/**
* 二叉树的节点定义
*/
public class BTNode<E> {
E data;//结点数据
BTNode lchild;//左孩子
BTNode rchlid;//右孩子
}
![](https://i-blog.csdnimg.cn/blog_migrate/a409c8445f94661c325a29b97229862f.jpeg)
(3)二叉查找树(BST)的定义
①左子树的节点值均小于根结点的值;
②右子树的结点值均大于根结点的值;
③左右子树也都是二叉查找树。
(4)二叉平衡树(AVL)的定义
为了避免树的高度增长过快,降低二叉查找树的性能,规定在插入和删除二叉树结点时,要保证任意节点的左、右子树高度差的绝对值不超过1,就将这样的二叉树称为平衡二叉树。
(5)红黑树
红黑树是每个结点都带有颜色属性的平衡二叉查找树 ,颜色为红色或黑色。除了二叉查找树一般要求以外,对于任何有效的红黑树都增加了如下的额外要求:
① 结点是要么红色或要么是黑色。
② 根一定是黑色结点。
③ 每个叶子结点都带有两个空的黑色结点(称之为 NIL 结点,又被称为黑哨兵)。
④ 每个红色结点的两个子结点都是黑色(或者说从每个叶子到根的所有路径上不能有两个连续的红色结点)。
⑤从任一节点到它所能到达得叶子结点的所有简单路径都包含相同数目的黑色结点。
这些性质保证了根结点到任意叶子结点的路径长度,最多相差一半(因为路径上的黑色结点相等,差别只是不能相邻的红色结点个数),所以红黑树是一个基本平衡的二叉搜索树,它没有 AVL 树那么绝对平衡,但是同样的关键字组成的红黑树相比AVL 旋转操作要少,而且删除操作也比 AVL 树效率更高,实际应用效果也比 AVL 树更出众。
红黑树的应用比较广泛,主要是用它来存储有序的数据,它的时间复杂度是O(log n),效率非常之高。Java 集合中的TreeSet 和 TreeMap ,以及 Linux 虚拟内存的管理,都是通过红黑树去实现的。