一、二叉搜索树
1.定义:二叉搜索树,又称二叉排序树,若它的左子树不为空,则左子树的结点都小于根结点;若它的右子树不为空,则右子树的结点值都大于根结点,并且子树同样遵循这个原则。(为什么叫二叉排序树呢?因为对这个树进行中序遍历是有序的。)
2.好处:使用二叉搜索树,进行数据查找时,时间复杂度为logn,有利于数据的查找。
3.缺点:有时在特殊情况下,会退化成一个链表的结构,失去其查找的优越性。所有就需要我们保证其树型结构,就需要引入我们的平衡树(即红黑树)
4.代码实现:
public class BinaryTree {
private int data;
private BinaryTree leftTree;
private BinaryTree rightTree;
//省略get/set方法
public BinaryTree(int data) {
this.data = data;
this.leftTree = null;
this.rightTree = null;
}
//构造树的方法
public void insertTree(BinaryTree root, int data) {
if (root.getData() < data) {
if (root.getRightTree() == null) {
root.setRightTree(new BinaryTree(data));
} else {
insertTree(root.getRightTree(), data);
}
} else {
if (root.getLeftTree() == null) {
root.setLeftTree(new BinaryTree(data));
} else {
insertTree(root.getLeftTree(), data);
}
}
}
//中序遍历
public void in(BinaryTree root) {
if (root != null) {
in(root.getLeftTree());
System.out.print(root.getData());
in(root.getRightTree());
}
}
public static void main(String[] args) {
//快速排序,归并排序,二叉树排序
int data[] = {0,5,9,1,2,3,10};
BinaryTree root = new BinaryTree(data[0]); //第一个点作为跟结点
for(int i = 1 ; i < data.length ; i ++) {
root.insertTree(root, data[i]);
}
System.out.println("中序遍历:");
root.in(root);
}
}
二、平衡二叉树(红黑树)
1.定义:又被称为AVL树,它是一颗空树或它的左右子树高度之差不超过1,并且左右两个子树都是一棵平衡二叉树,这样就可以避免称为一个线程结构。
2.红黑树:平衡二叉树的一种。
特点:(1).每个结点不是红色就是黑色。
(2).不可能有连着一起的红色结点。
(3).根结点都是黑色
(4).每个红色结点的二个子结点,都是黑色
(5).任意结点,到其子树中每个叶子结点的路径都有相同数量的黑色结点。
3.红黑树的旋转:
1.左旋:示意图如下:
当对左边这个树以5为结点进行左旋时,将结点5向左下方进行旋转,这时结点8就向上旋转成为根结点,因此结点5成为结点8的左子树,结点9依然还是右子树不变,因为旋转的同时,保证其数据的有序性,结点6就会成为5的右子树,左旋完成。
2.右旋:示意图如下:
当对左边这个树以结点5进行右旋时,结点5想右下方旋转,结点3上移成为根结点,这时结点5成为结点3的左子树,结点3的左子树结点2依然为结点3的左子树,因为要保证其数据的有序性,结点4将成为结点5的左子树,右旋完成。
4.红黑树的旋转和变色规则:
1.变色情况:当前结点的父亲结点是红色,且它的祖父结点的另一个结点(叔叔结点)也是红色,则就需要进行变色调整:
(1)把父结点设为黑色
(2)把叔叔也设为黑色
(3)把祖父结点(父亲的父亲)设为红色
(4)把指针定义到祖父结点设为当前要操作的。
2.左旋的情况:当前父结点是红色,叔叔是黑色的时候,且当前的结点是右子树。左旋以父结点作为左旋。
3.右旋的情况:当前父结点是红色,叔叔是黑色的时候,且当前的结点是左子树。进行右旋。
(1)把父结点变为黑色。
(2)把祖父结点变为红色(爷爷)。
(3)以祖父结点进行旋转(爷爷)。