Tree
查找性能和插入性能都优于线性结构
二叉树
任何一个节点的子节点数量不超过2
满二叉树
所有叶子节点都在最后一层,而且节点的总数为2^n - 1,n是树的高度
完全二叉树
所有叶子结点都在最后一层或倒数第二层,且最后一层的叶子结点在左边连续,倒数第二层的叶子节点在右边连续
链式存储
public class TreeNode {
int value;
TreeNode lNode;
TreeNode rNode;
public TreeNode(int value){
this.value = value;
}
public void setlNode(TreeNode lNode) {
this.lNode = lNode;
}
public void setrNode(TreeNode rNode) {
this.rNode = rNode;
}
//前序遍历
public void frontShow(){
System.out.println(value);
if (lNode != null)
lNode.frontShow();
if (rNode != null)
rNode.frontShow();
}
//中序遍历
public void midShow(){
if (lNode != null)
lNode.midShow();
System.out.println(value);
if (rNode != null)
rNode.midShow();
}
//后序遍历
public void afterShow(){
if (lNode != null)
lNode.afterShow();
if (rNode != null)
rNode.afterShow();
System.out.println(value);
}
//前序查找
public TreeNode frontSearch(int tag){
TreeNode target = null;
if (this.value == tag){
return this;
}else {
if (lNode != null)
target = lNode.frontSearch(tag);
if (target != null)
return target;
if (rNode != null)
target = rNode.frontSearch(tag);
}
return target;
}
//中序查找
public TreeNode midSearch(int tag){
TreeNode target = null;
if (lNode != null)
target = lNode.midSearch(tag);
if (this.value == tag)
return this;
if (target != null)
return target;
if (rNode != null)
target = rNode.midSearch(tag);
return target;
}
//后序查找
public TreeNode afterSearch(int tag){
TreeNode target = null;
if (lNode != null)
target = lNode.afterSearch(tag);
if (target != null)
return target;
if (rNode != null)
target = rNode.afterSearch(tag);
if (this.value == tag)
return this;
return target;
}
//删除子树
public void delete(int tag){
TreeNode parent = this;
if (parent.lNode != null && parent.lNode.value == tag){
parent.lNode = null;
return;
}
if (parent.rNode != null && parent.rNode.value == tag){
parent.rNode = null;
return;
}
parent = lNode;
if (parent != null)
parent.delete(tag);
parent = rNode;
if (parent != null)
parent.delete(tag);
}
顺序存储
顺序存储的二叉树通常情况只考虑完全二叉树
第n个元素的左子节点是:2^n + 1;
第n个元素的右子节点是:2^n + 2;
第n个元素的父节点是:(n - 1)/2;
public class ArrayBinaryTree {
int[] data;
public ArrayBinaryTree(int[] data){
this.data = data;
}
public void show(){
frontShow(0);
}
//前序遍历
public void frontShow(int index){
if (data == null || data.length == 0){
return;
}
System.out.println(data[index]);
//2*n+1
if (2 * index + 1 < data.length)
frontShow(2 * index + 1);
//2*n+2
if (2 * index + 2 < data.length)
frontShow(2 * index + 2);
}
线索二叉树
线索化二叉树,一个节点的前一个节点,叫做前驱节点
线索化二叉树,一个节点的后一个节点,叫做后继节点
public class ThreadedBinaryTree {
ThreadedNode root;
//存储前驱节点
ThreadedNode pre = null;
public void setRoot(ThreadedNode root) {
this.root = root;
}
//遍历
public void threadIterate(){
ThreadedNode node = root;
while (node != null){
while (node.leftType == 0){
node = node.leftNode;
}
System.out.println(node.value);
while (node.rightType == 1){
node = node.rightNode;
System.out.println(node.value);
}
node = node.rightNode;
}
}
//中序线索化
public void midThread(ThreadedNode node){
if (node == null)
return;
//left
midThread(node.leftNode);
if (node.leftNode == null){
node.leftNode = pre;
node.leftType = 1;
}
if (pre != null && pre.rightNode == null){
pre.rightNode = node;
pre.rightType = 1;
}
pre = node;
//right
midThread(node.rightNode);
}
public ThreadedNode getRoot() {
return root;
}
霍夫曼树
是n个带权叶子节点构成的所有二叉树中,带权路径长度最小的二叉树
1,先排序
2,取最小两个,两两组合成一棵树,根节点权值为两节点之和
3,将根节点加入序列,重复1,2,过程,直至为零
HuffmanNode
public class HuffmanNode implements Comparable<HuffmanNode>{
int value;
HuffmanNode left;
HuffmanNode right;
public HuffmanNode(int value){
this.value = value;
}
@Override
public int compareTo(HuffmanNode o) {
return -(this.value - o.value);
}
@Override
public String toString() {
return "HuffmanNode{" +
"value=" + value +
", left=" + left +
", right=" + right +
'}';
}
HuffmanTree
public class HuffmanTree {
public static void main(String[] args) {
int[] arr = new int[] {3, 7, 8, 29, 5, 11, 23, 14};
HuffmanNode root = createHuffmanTree(arr);
System.out.println(root);
}
public static HuffmanNode createHuffmanTree(int[] arr){
//先创建若干个节点
List<HuffmanNode> nodes = new ArrayList<>();
for (int value:arr)
nodes.add(new HuffmanNode(value));
while (nodes.size() > 1){
//sort
Collections.sort(nodes);
//取出最小两个节点
HuffmanNode left = nodes.get(nodes.size() - 1);
HuffmanNode right = nodes.get(nodes.size() - 2);
//创建新的二叉树
HuffmanNode parent = new HuffmanNode(left.value + right.value);
parent.left = left;
parent.right = right;
//移除取出的两个节点
nodes.remove(left);
nodes.remove(right);
//放入原来二叉树
nodes.add(parent);
}
return nodes.get(0);
}
霍夫曼编码
- 定长编码
can
99 97 110
01100011 01100001 01101110
- 非定长编码
ca n a n n
c:1 a:2 n:3 :4
定义: 0 = , 1=n, 10 = a, 11 = c,
11 10 0 1 0 10 0 1 0 1
注意:字符的编码都不能是其他字符编码的前缀,符合此要求的编码叫前缀编码
- 霍夫曼编码
ca n a n n
c:1 a:2 n:3 :4
字符为叶子节点,次数为权重,左 0 ,右 1 ,构建霍夫曼树
public class Node implements Comparable<Node>{
int weight;
Node left;
Node right;
//字符
Byte data;
public Node(Byte data, int weight){
this.weight = weight;
this.data = data;
}
Huffman 解压缩文件源码:https://github.com/MAPENGMASK/Java/tree/master/src/datastructure/huffman
二叉排序树 BST
对于二叉树中的任何一个非叶子节点,要求左子节点比当前节点值小,右子节点比当前节点值大。
优化查找效率
BST 编码实现:https://github.com/MAPENGMASK/Java/tree/master/src/datastructure/bst
AVL树
进一步优化二叉排序树查找效率
左子树与右子树的高度差的绝对值不超过1
左子树和右子树都是平衡二叉树
多路查找树
页是计算机管理存储器的逻辑块,硬件及操作系统往往将主存和磁盘存储区分割为连续的大小相等的块,每个存储块称为一页(默认大小为 4 k),主存和磁盘以页为单位交换数据。
文件系统及数据库设计者利用磁盘预读原理,将一个节点的大小设为等于一页,这样每个节点只需一次I/O就可完全载入。
数据量较小时,存储在内存中
数据量较大时,存储到磁盘里,必须要面对多次磁盘I/O操作,耗时比较大的问题
如果扩展树中的节点,可以很好的解决上述问题
2-3树
1,所有叶子节点都在同一层
2,有二节点存在,二节点要么有两个子节点,要么没有节点
3,有三节点存在,三节点要么有三个子节点,要么没有节点
B树,B+树
B树:节点扩充,规则如2-3树,也可以是2-3-4 树
B树的阶为该树中最高节点规模数,如2-3树的阶为3
B+树:B树的变形,非叶子节点只存储索引信息,不存储数据
叶子节点最右边指针指向下一个相邻的叶节点
所有的叶节点组成一个有序链表
优点:便于搜索,通过读取非叶子节点,再通过一次I/O找到所要的数据