二叉树BT与二叉查找树BST概览
1、树
分析HashMap源码的时候,看到JDK8中链表的节点个数超过了泊松分布计算得出的8个节点时,链表将会被转化为红黑树,所以,在分享HaspMap的源码分析文章前,先来分享一下树的数据结构的相关知识。
概念 | 英文 |
---|---|
树 | tree |
节点 | node |
边 | edge |
儿子 | child |
父亲 | parent |
根 | root |
树叶 | leaf |
兄弟 | siblings |
祖父 | grandparent |
孙子 | grandchild |
祖先 | ancestor |
后裔 | descendant |
真祖先 | proper ancestor |
真后裔 | proper descendant |
概念 | 英文 | 解释 |
---|---|---|
节点到节点的路径 | path | 节点到节点间所有节点组成的序列 |
路径的长 | length | 路径的长是路径上所有边的条数 |
节点的深度 | depth | 从根到节点的唯一路径的长 |
节点的高 | height | 节点到一片树叶最长路径的长 |
对数 |
---|
对数是对求幂的逆运算 |
如果a的x次方等于N(a>0,且a不等于1),那么数x叫做以a为底N的对数(logarithm),记作x=logaN。其中,a叫做对数的底数,N叫做真数。
1.1、树的实现
将每个节点的所有儿子都放在树节点的链表中。
树的实现 | 箭头方向 | 英文 |
---|---|---|
向下箭头 | 第一儿子 | firstChild |
水平箭头 | 下一兄弟 | nextSibling |
1.2、树的应用-文件目录
目录 | 树 |
---|---|
文件名 | 节点 |
/ | 边 |
遍历 | 解释 | 英文 |
---|---|---|
先序遍历 | 对节点的处理工作在节点的所有儿子被处理之前进行 | preorder traversal |
后续遍历 | 对节点的处理工作在节点的所有儿子被处理之后进行 | postorder traversal |
2、二叉树-BT
概念 | 英文 |
---|---|
二叉树 | binary tree |
平均/平衡二叉树 | Balanced Binary Tree |
二叉排序/查找/搜索树 | binary search/sort tree |
二叉树
每个节点都不能多于2个儿子的树
2.1、二叉树的实现
节点是由element元素的信息,加上两个到其他节点的引用left和right组成的结构。
class BinaryNode{
Object element;
BinaryNode left;
BinaryNode right;
}
2.2、二叉树的应用-表达式树
表达式树expression tree的树叶是操作数operand,其他的节点为操作符operator。
中序遍历:左、节点、右。
构造表达式树 输入:a b + c d e + * *
输出:
3、二叉查找树 BST
查找树的ADT/Abstract Data Type/抽象数据类型,二叉排序/查找/搜索树。
二叉排序/查找/搜索树
空树或
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉排序树;
(4)没有键值相等的结点。
平均深度,O(log N)
二叉查找树实现:
public class BinarySearchTree<T extends Comparable<T>> {
//二叉查找树根节点
private BinaryNode<T> root;
//二叉树节点定义
private static class BinaryNode<T extends Comparable<T>> {
T element; //节点值
BinaryNode<T> left; //左节点
BinaryNode<T> right; //右节点
public BinaryNode(T key) {
this(key, null, null);
}
public BinaryNode(T element, BinaryNode<T> left, BinaryNode<T> right) {
this.element = element;
this.left = left;
this.right = right;
}
}
}
查找是否存在:
/**
* 查找是否存在
*
* @param search
* @param root
* @return
*/
private boolean contains(T search, BinaryNode<T> root) {
if (root == null) {
return false;
}
int compareResult = search.compareTo(root.element);
if (compareResult < 0) {
return contains(search, root.left);
} else {
return contains(search, root.right);
}
}
查找最小值:
/**
* 查找最小值
*
* @param root
* @return
*/
private BinaryNode<T> findMin(BinaryNode<T> root) {
if (root == null) {
return null;
}
if (root.left == null) {
return root;
}
return findMin(root.left);
}
查找最大值:
/**
* 查找最大值
*
* @param root
* @return
*/
private BinaryNode<T> findMax(BinaryNode<T> root) {
if (root == null) {
return null;
}
if (root.right == null) {
return root;
}
return findMax(root.right);
}
插入值:
/**
* 插入值
*
* @param insert
* @param root
* @return
*/
private BinaryNode<T> insert(T insert, BinaryNode<T> root) {
if (root == null) {
return new BinaryNode<T>(insert, null, null);
}
int compareResult = insert.compareTo(root.element);
if (compareResult < 0) {
root.left = insert(insert, root.left);
} else if (compareResult > 0) {
root.right = insert(insert, root.right);
}
return root;
}
删除值:
/**
* 删除值
* 如果是树叶,直接删除
* 如果有一个儿子:该节点在其父节点调整自己的链以绕过该节点后被删除
* 如果有两个儿子:用该节点右子树的最小的数据代替该节点的数据,并递归地删除该节点
*
* @param remove
* @param root
* @return
*/
private BinaryNode<T> remove(T remove, BinaryNode<T> root) {
if (root == null) {
return root;
}
int compareResult = remove.compareTo(root.element);
if (compareResult < 0) {
root.left = remove(remove, root.left);
} else if (compareResult > 0) {
root.left = remove(remove, root.right);
} else if (root.left != null && root.right != null) {//两个儿子
root.element = findMin(root.right).element;
root.right = remove(root.element, root.right);
} else {
root = (root.left != null) ? root.left : root.right;
}
return root;
}
前序遍历:
/**
* 前序遍历
* @param node 待遍历二叉查找树BST根节点
*/
private void preOrder(BinaryNode<T> node) {
if (node != null) {
System.out.print(node.key + " ");
preOrder(node.left);
preOrder(node.right);
}
}
中序遍历:
/**
* 中序遍历
* @param node 待遍历BST根节点
*/
private void midOrder(BinaryNode<T> node) {
if (node != null) {
midOrder(node.left);
System.out.print(node.key + " ");
midOrder(node.right);
}
}
后序遍历:
/**
* 后序遍历
* @param node 待遍历BST根节点
*/
private void postOrder(BinaryNode<T> node) {
if (node != null) {
postOrder(node.left);
postOrder(node.right);
System.out.print(node.key + " ");
}
}
4、AVL树
平均二叉/平衡二叉/AVL树
空树或每个节点的左右两子树高度差绝对值<=1的二叉查找树,每个节点的左右两子树都是平衡二叉树。
AVL树/Adelson-Velskii和Landis树是带有平衡条件的二叉查找树。
空树的高度定义为-1。
平衡条件必须要容易保持,它保证了树的深度须是
平均深度,O(根号N)
待续……
下一次树的分享将继续讲AVL树、伸展树、B树以及红黑树的相关知识……