定义
根节点的值大于其左子树任意节点的值,小于其右子树任意节点的值。这一规则适用于二叉查找树种的每一个节点。且没有键值相等的节点。
叶节点:也叫叶子节点,没有子节点的节点
删除节点:寻找比删除节点值大的节点集合种最小的一个节点。
一般不物理删除,直接逻辑删除。
对二叉查找树进行中序遍历,即可得到有序的数列。
普通的二叉查找树容易失去平衡,退化成线性的链表。导致查找和插入的复杂度降低至O(N)。
插入:直接作为叶子节点插入
平衡二叉树,又称AVL树。
每个节点的左右子树的高度差的绝对值最大为1。
构建平衡二叉树时,当有新节点插入时,都会判断插入后是否平衡,不平衡,就需要调整。
左旋:以某个节点为支点(旋转节点),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点(把晋升之后多余的左子节点出让给降级节点的右子节点)
右旋:以某个节点为支点(旋转节点),其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点(把晋升之后多余的右子节点出让给降级节点的左子节点)
旋转的目的,是将节点多的一只,出让节点给节点少的一支。
需要调整的情况有四种:左左、左右、右左、右右。
左左:在原来的平衡二叉树上,在节点的左子树的左子树下,有新节点插入
左右:在原来的平衡二叉树上,在节点的左子树的右子树下,有新节点插入。需要先左旋,使二叉树变成左左,再右旋。
右左:
右右:
平衡二叉树构建的过程,就是节点插入的过程,插入失衡情况就上面4种,算简单了,下面讲下平衡二叉树节点的删除,删除的情况会复杂一点,复杂的原因主要在于删除了节点之后要维系二叉树的平衡,但是删除二叉树节点总结起来就两个判断:①删除的是什么类型的节点?②删除了节点之后是否导致失衡?
节点的类型有三种:1.叶子节点;2.只有左子树或只有右子树;3.既有左子树又有右子树。
针对这三种节点类型,再引入判断②,所以处理思路分别是:
(1)当删除的节点是叶子节点,则将节点删除,然后从父节点开始,判断是否失衡,如果没有失衡,则再判断父节点的父节点是否失衡,直到根节点,此时到根节点还发现没有失衡,则说此时树是平衡的;如果中间过程发现失衡,则判断属于哪种类型的失衡(左左,左右,右左,右右),然后进行调整。
(2)删除的节点只有左子树或只有右子树,这种情况其实就比删除叶子节点的步骤多一步,就是将节点删除,然后把仅有一支的左子树或右子树替代原有结点的位置,后面的步骤就一样了,从父节点开始,判断是否失衡,如果没有失衡,则再判断父节点的父节点是否失衡,直到根节点,如果中间过程发现失衡,则根据失衡的类型进行调整。
(3)删除的节点既有左子树又有右子树,这种情况又比上面这种多一步,就是中序遍历,找到待删除节点的前驱或者后驱都行,然后与待删除节点互换位置,然后把待删除的节点删掉,后面的步骤也是一样,判断是否失衡,然后根据失衡类型进行调整。
package com.tree;
import java.util.Stack;
public class BinaryTree {
public static void main(String[] args) {
Node root = null;
for (int i = 10; i > 0; i--) {
root = insert(root, new Node(i));
}
for (int i = 50; i > 40; i--) {
root = insert(root, new Node(i));
}
for (int i = 30; i > 20; i--) {
root = insert(root, new Node(i));
}
list(root);
listStack(root);
}
//s使用递归方式遍历
public static void list(Node root) {
if (root != null) {
list(root.getLeft());
System.out.print(root.getData());
System.out.print("\t");
list(root.getRight());
}
}
//利用栈的后进先出遍历
public static void listStack(Node p) {
System.out.println("");
Stack<Node> stack = new Stack<>();
while (!stack.isEmpty() || p != null) {
while (p != null) {
stack.push(p);
p = p.getLeft();
}
p = stack.pop();
System.out.print(p.getData() + "\t");
p = p.getRight();
}
}
//二叉查找树的插入
public static Node insert(Node root, Node newNode) {
if (root == null) {
root = newNode;
root.setParent(null);
return root;
}
Node tmp = root;
while (tmp != null) {
if (newNode.getData() < tmp.getData()) {
if (tmp.getLeft() == null) {
tmp.setLeft(newNode);
newNode.setParent(tmp);
break;
} else {
tmp = tmp.getLeft();
continue;
}
}
if (newNode.getData() > tmp.getData()) {
if (tmp.getRight() == null) {
tmp.setRight(newNode);
newNode.setParent(tmp);
break;
} else {
tmp = tmp.getRight();
continue;
}
}
}
return root;
}
}