LinkedList
- Java 1.8之前是双向循环链表
- Java 1.8之后是双向不循环链表
- 建议同学们自行实现一个 双向不循环链表,并且实现追加,插入,删除,遍历操作
二叉树
- 每个父节点只有两种子节点的树形数据结构
- 左子节点中存储的数据小于父节点数据,右子节点存储数据大于父节点数据
- 由于操作性能是2分查找性能,经常用于排序和查找
二叉树添加元素: 递归添加元素,相同元素不添加,右侧添加小的,右侧添加大的
二叉树遍历: - 先序遍历: 输出顺序 中 左 右
- 中序遍历: 输出顺序 左 中 右 , 最常见遍历输出,输出结果是排序结果
- 后序遍历: 输出顺序 左 右 中
案例:
/**
* 二叉树,由于元素需要比较大小,所有元素应该实现
* Comparable接口
* E extends Comparable 泛型E必须实现 Comparable
* 用于比较两个元素的大小
* @param
*/
public class Tree<E extends Comparable<E>>{
private Node root;
private int size=0;
private class Node{
E data;
Node parent;
Node left;
Node right;
public Node(E e) {
data = e;
}
boolean addChild(E e) {
//比较数据
//val == 0 则 e和data相等
//val > 0 则 e大于data
//val < 0 则 e小于data
int val = e.compareTo(data);
if(val==0) {
return false;
}
if(val < 0) {
//向左侧添加节点
if(left==null) {
left = new Node(e);
//左侧新节点的父节点是当前节点
left.parent = this;
size++;
return true;
} else {
//如果左侧已经有节点了,就在左侧递归添加子节点
return left.addChild(e);
}
}else {
//向右侧添加节点
if(right == null) {
right=new Node(e);
right.parent = this;
size++;
return true;
}else {
return right.addChild(e);
}
}
}
/**
* 中序遍历算法
*/
public void appendTo(StringBuilder buf) {
//输出顺序是 左 中 右
if(left!=null) {
//将左侧数据添加到 buf
left.appendTo(buf);
}
//添加“中”数据, 就是当前的data
buf.append(data).append(", ");
if(right!=null) {
//将右侧数据添加到 buf
right.appendTo(buf);
}
}
}
public boolean add(E e) {
if(root==null) {
//第一次添加根节点
root = new Node(e);
size++;
return true;
} else {
//Child 孩子
//为根元素添加子节点
return root.addChild(e);
}
}
/**
* 实现二叉树的中序遍历输出
*/
public String toString() {
if(root==null) {
return "[]";
}
StringBuilder buf = new StringBuilder("[");
root.appendTo(buf); //递归算法,实现中序遍历
//去除最后一个 逗号
int index = buf.lastIndexOf(",");
buf.delete(index, buf.length());
buf.append("]");
return buf.toString();
}
}
红黑树
自平衡二叉树,采用5个(平衡)规则:
- 每个节点不是红的就是黑的,每个节点的红黑可以转换
- 根元素是黑的。
- 所有null子节点,算黑的。
- 如果一个节点是红的,下一个一定是黑的
- 从一个节点开始,其子孙路径上是全部黑数量需要一致。
如果不符合如上规则,就进行转置调整。直到满足5条规则为止。
关于集合框架
接口
Collecion
|-- List
| |-- ArrayList
| |-- LinkedList
|-- Set
|-- HashSet 内部是 HashMap,只使用key存储数据
|-- SortedSet //排序的
|-- TreeSet 内部是 TreeMap,只使用key存储数据
Map
|-- HashMap 散列表算法
|-- SortedMap
|- TreeMap 红黑树--自平衡二叉树
HashMap 工作原理
- 散列表内部封装了散列数组,数组元素类型是 散列桶 节点来下
- 散列桶是一个链表结构
- (Java 8)如果链表节点数量超过8个元素,会转换为红黑树!
- 添加数据时候
- 先根据key的hashCode计算出 散列数组的下标位置,
- 再在散列桶中利用equals方法查找key
- 找到就替换,没有找到就插入
- 如果元素数量超过 散列数组容量的75%(加载因子),则对散列数组进行扩容(1倍)
- 扩容后,散列表会将元素进行“重新散列”
- 查找时候
- 先根据key的hashCode计算出 散列数组的下标位置,
- 再在散列桶中利用equals方法查找key
- 找到就返回value,没有找到返回null
为啥快:
- 相对于顺序顺序查找,散列查找可以根据key快速定位到 散列桶位置,在散列桶中,元素较少,可以开始搜索到数据。
- Java 8 以后,在散列桶中元素较多时候,会组织成“红黑树”进一步提高散列桶中的查找效率。
关于hashCode方法: - hashCode() 是java设计者为 散列表 而设计方法。
- hashCode() 的默认值,不是对象的内存地址!Java8 中是稳定的随机数。每次调用都一样。
- Java编程建议:
- 在重写equals方法时候,要一起重写hashCode()
- 两个对象equals相等时候,其hashCode() 必须一样
- 两个对象equals不等时候,其hashCode() 尽可能不同