学习目标:
掌握基于二叉树变化的数据结构
学习内容:
例如:
- 二叉搜索树
- AVL树
- 红黑树
二叉搜索树
构建
public class BSTree {
static class BSTNode {
int key;
Object value;
BSTNode left;
BSTNode right;
public BSTNode(int key) {
this.key = key;
}
public BSTNode(int key, Object value) {
this.key = key;
this.value = value;
}
public BSTNode(int key, Object value, BSTNode left, BSTNode right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
BSTNode root;
}
根据key获取值
public Object get(int key) {
BSTNode node = root;
while (node != null) {
if (key < node.key) {
node = node.left;
} else if (key > node.key) {
node = node.right;
} else {
return node.value;
}
}
return null;
}
返回最大最小值
public Object min(){
if(root == null)return null;
BSTNode p = root;
while(p.left!=null){
p = p.left;
}
return p.value;
}
public Object max(){
if(root==null)return null;
BSTNode p = root;
while(p.right!=null){
p = p.right;
}
return p.value;
}
put(有则覆盖,无则存入)
public void put(int key,Object value){
BSTNode p = root;
BSTNode parent = null;
while(p!=null){
if(key<p.key){
parent = p;
p = p.left;
} else if (key>p.key) {
parent = p;
p = p.right;
}else {
//找到了
p.value = value;
return;
}
}
if(parent==null){
root = new BSTNode(key, value);
return;
}
//没找到
if(key<parent.key){
parent.left = new BSTNode(key,value);
}else{
parent.right = new BSTNode(key,value);
}
}
找前任
需要重写max()和min(),改成有参方法
public Object predecessor(int key) {
BSTNode p = root;
BSTNode node = null;
while (p != null) {
if (key < p.key) {
p = p.left;
} else if (key > p.key) {
node = p;
p = p.right;
} else {
break;
}
}
//没找到节点
if (p == null) {
return null;
}
/*
* 找到节点
* 情况1.节点有左子树,返回左子树最大值
* 情况2:节点没有左子树,返回离它最近的,自左而来的祖先
* */
if (p.left != null) {
return max(p.left);
}
return node != null ? node.value : null;
}
找后继
public Object successor(int key) {
BSTNode p = root;
BSTNode node = null;
while (p != null) {
if (key < p.key) {
node = p;
p = p.left;
} else if (key > p.key) {
p = p.right;
} else {
break;
}
}
//没找到节点
if (p == null) {
return null;
}
if (p.right != null) {
return min(p.right);
}
return node != null ? node.value : null;
}
根据关键字删除
public BSTNode delete(int key) {
BSTNode p = root;
BSTNode parent = null;
while (p != null) {
if (key < p.key) {
parent = p;
p = p.left;
} else if (key > p.key) {
parent = p;
p = p.right;
} else {
break;
}
}
if (p == null) {
return null;
}
//执行删除操作
if (p.left == null) {
//情况1:左孩子空,右孩子非空
//情况3:被删除节点左右孩子为空,已经涵盖在内
shift(parent, p, p.right);
}
if (p.right == null) {
//情况2:左孩子非空,右孩子空
shift(parent, p, p.left);
} else {
//情况4:左右孩子都有
//4.1被删除节点的后继结点
BSTNode s = p.right;
BSTNode sParent = p;
while (s.left != null) {
sParent = s;
s = s.left;
}
//4.2处理后继节点后事
if (sParent != p) {
//不相邻
shift(sParent, s, s.right);
s.right = p.right;
}
//4.3后继取代被删除节点
shift(parent,p,s);
s.left = p.left;
}
return p;
}
/*
* 托孤方法
* */
private void shift(BSTNode parent, BSTNode deleted, BSTNode child) {
if (parent == null) {
root = child;
} else if (parent.left == deleted) {
parent.left = child;
} else {
parent.right = child;
}
}
范围查询
查询小于key的所有key对应的值
public List<Object> less(int key){
ArrayList<Object> result = new ArrayList<>();
BSTNode p = root;
LinkedList<BSTNode> stack = new LinkedList<>();
while(p!=null||!stack.isEmpty()){
if(p!=null){
stack.push(p);
p = p.left;
}else {
BSTNode pop = stack.pop();
//处理值
if(pop.key<key){
result.add(pop.value);
}else {
break;
}
p = pop.right;
}
}
return result;
}
二叉搜索树相关练习
查找最近公共祖先节点
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
//如果p和q在a的两侧,说明a是p和q的最近祖先节点
TreeNode a = root;
while (p.val < a.val && q.val < a.val || p.val > a.val && q.val > a.val) {
if (p.val < a.val){
a = a.left;
}else{
a = a.right;
}
}
return a;
}
验证二叉搜索树
static ArrayList<Integer> list = new ArrayList<>();
//验证二叉搜索树
public static boolean isBSTree(TreeNode root) {
inOrder(list, root);
System.out.println(list);
for (int i = 0; i < list.size() - 1; i++) {
if (list.get(i) > list.get(i + 1)) {
return false;
}
}
return true;
}
private static void inOrder(ArrayList<Integer> list, TreeNode root) {
if (root == null) return;
inOrder(list, root.left);
list.add(root.val);
inOrder(list, root.right);
}
范围求和
//求范围和
int sum = 0;
public int sumRange(TreeNode root, int low, int high) {
TreeNode p = root;
inOrder(root,low,high);
return sum;
}
private void inOrder(TreeNode node, int low, int high) {
if (node == null) return;
inOrder(node.left, low, high);
if (node.val > high) {
return;
}
if (node.val > low) {
sum += node.val;
}
inOrder(node.right, low, high);
}
AVL树
AVL树:自平衡二叉搜索树,任意左右子树高度差不超过1,插入和删除节点时自动平衡
构造AVL树
public class AVLTree {
static class AVLNode {
int key;
Object value;
AVLNode left;
AVLNode right;
int height = 1;
public AVLNode(int key, Object value) {
this.key = key;
this.value = value;
}
public AVLNode(int key) {
this.key = key;
}
public AVLNode(int key, Object value, AVLNode left, AVLNode right) {
this.key = key;
this.value = value;
this.left = left;
this.right = right;
}
}
//求节点高度(处理node==null的高度)
private int height(AVLNode node) {
if (node == null) return 0;
return node.height;
}
//更新节点高度(新增,删除,旋转)
private void updateHeight(AVLNode node) {
node.height = Math.max(height(node.left), height(node.right)) + 1;
}
//平衡因子(balance factor) = 左子树高度-右子树高度
private int bf(AVLNode node) {
// 0 1 -1 都是平衡的,其他值都是不平衡
return height(node.left) - height(node.right);
}
//参数:要旋转的节点,返回值:新的根节点
private AVLNode rightRotate(AVLNode red) {
AVLNode yellow = red.left;
AVLNode green = yellow.right;
yellow.right = red; //上位
red.left = green; //换爹
updateHeight(red);
updateHeight(yellow);
return yellow;
}
private AVLNode leftRotate(AVLNode red) {
AVLNode yellow = red.right;
AVLNode green = yellow.left;
yellow.left = red;
red.right = green;
updateHeight(red);
updateHeight(yellow);
return yellow;
}
//先左旋左子树,再右旋根节点
private AVLNode leftRightRotate(AVLNode node) {
node.left = leftRotate(node.left); //更新左子节点
return rightRotate(node);
}
//先右旋右子树,再左旋根节点
private AVLNode rightLeftRotate(AVLNode node) {
node.right = rightRotate(node.right);
return leftRotate(node);
}
//检查节点是否失衡,重新平衡代码
private AVLNode balance(AVLNode node) {
if (node == null) {
return null;
}
int bf = bf(node);
if (bf > 1 && bf(node.left) >= 0) { // LL
return rightRotate(node);
} else if (bf > 1 && bf(node.left) < 0) { // LR
return leftRightRotate(node);
} else if (bf < -1 && bf(node.right) > 0) { // RL
return rightLeftRotate(node);
} else if (bf < -1 && bf(node.right) <= 0) { // RR
return leftRightRotate(node);
}
return node;
}
}
新增
public void put(int key,Object value){
root = doPut(root,key,value);
}
private AVLNode doPut(AVLNode node,int key,Object value){
//1.找到空位,创建新节点返回
if(node == null){
return new AVLNode(key,value);
}
//2.key已经存在,直接更新
if(key == node.key){
node.value = value;
return node;
}
//3.继续查找
if(key<node.key){
node.left = doPut(node.left,key,value);
}else {
node.right = doPut(node.right,key,value);
}
updateHeight(node);
return balance(node);
}
删除
private AVLNode doRemove(AVLNode node, int key) {
//1.node==null
if (node == null) {
return null;
}
//2.没找到key
if (key < node.key) {
node.left = doRemove(node.left, key);
} else if (key > node.key) {
node.right = doRemove(node.right, key);
} else {
//3.找到key 3.1没有孩子 3.2只有一个孩子 3.3有两个孩子
if (node.left == null && node.right == null) {
return null;
} else if (node.left == null) {
node = node.right;
} else if (node.right == null) {
node = node.left;
} else {
AVLNode s = node.right;
while (s.left != null) {
s = s.left;
}
//s为后继节点
s.right = doRemove(node.right, s.key);
s.left = node.left;
node = s;
}
}
//4.更新高度
updateHeight(node);
//5.balance
return balance(node);
}
红黑树
红黑树也是一种自平衡的二叉搜索树,相比于AVL,插入和删除时旋转次数更少。
特点:
1.所有节点都有两种颜色:红和黑
2.所有null视为黑色
3.红色节点不能相邻
4.根节点是黑色
5.从根到任意一个叶子节点,路径中黑色节点数一样
【代码建议结合演示图分析】
public class RedBlackTree {
enum Color {
RED, BLACK;
}
private Node root;
private static class Node {
int key;
Object value;
Node left;
Node right;
Node parent; //父节点
Color color = RED; //新节点默认红色
//是否是左孩子
boolean isLeftChild() {
return parent != null && parent.left == this;
}
//叔叔
Node uncle() {
if (parent == null || parent.parent == null) {
return null;
}
if (parent.isLeftChild()) {
return parent.parent.right;
} else {
return parent.parent.left;
}
}
//兄弟
Node sibling() {
if (parent == null) {
return null;
}
if (this.isLeftChild()) {
return parent.right;
} else {
return parent.left;
}
}
}
//判断红黑
boolean isRed(Node node) {
return node != null && node.color == RED;
}
boolean isBlack(Node node) {
return node == null || node.color == BLACK;
}
//右旋 1.parent的处理 2.旋转后新根的父子关系
private void rightRotate(Node pink) {
Node parent = pink.parent;
Node yellow = pink.left;
Node green = yellow.right;
if (green != null) {
green.parent = pink;
}
yellow.right = pink;
yellow.parent = parent;
pink.left = green;
pink.parent = yellow;
if(parent==null){
root = yellow;
}else if (parent.left == pink) {
parent.left = yellow;
} else {
parent.right = yellow;
}
}
}