二叉排序树:
二叉排序树 删除结点的三种情况:
第一种情况:
删除叶子节点 (比如:2, 5, 9, 12)
思路
(1) 需求先去找到要删除的结点 targetNode
(2) 找到targetNode 的 父结点 parent
(3) 确定 targetNode 是 parent的左子结点 还是右子结点
(4) 根据前面的情况来对应删除
左子结点 parent.left = null
右子结点 parent.right = null;
第二种情况:
删除只有一颗子树的节点 比如 1
思路
(1) 需求先去找到要删除的结点 targetNode
(2) 找到targetNode 的 父结点 parent
(3) 确定targetNode 的子结点是左子结点还是右子结点
(4) targetNode 是 parent 的左子结点还是右子结点
(5) 如果targetNode 有左子结点
5. 1 如果 targetNode 是 parent 的左子结点
parent.left = targetNode.left;
5.2 如果 targetNode 是 parent 的右子结点
parent.right = targetNode.left;
(6) 如果targetNode 有右子结点
6.1 如果 targetNode 是 parent 的左子结点
parent.left = targetNode.right;
6.2 如果 targetNode 是 parent 的右子结点
parent.right = targetNode.right
第三种情况 :
删除有两颗子树的节点. (比如:7, 3,10 )
思路
(1) 需求先去找到要删除的结点 targetNode
(2) 找到targetNode 的 父结点 parent
(3) 从targetNode 的右子树找到最小的结点
(4) 用一个临时变量,将 最小结点的值保存 temp = 11
(5) 删除该最小结点
(6) targetNode.value = temp
二叉排序树和相应操作实现:
public class BinaryTreeSort {
public static void main(String[] args) {
int[] arr = { 7, 3, 10, 12, 5, 1, 9 };
BinarySortTree tree = new BinarySortTree();
for (int i = 0; i < arr.length; i++) {
tree.add(new Node(arr[i]));
}
tree.infixOrder();
}
}
class BinarySortTree {
public Node rootNode;
public void add(Node node) {
if (rootNode == null) {
this.rootNode = node;
} else {
rootNode.add(node);
}
}
public void delNode(int value) {
if (rootNode == null) {
return;
} else {
Node targetNode = rootNode.search(value);
// 发现要删除的结点不存在,直接返回
if (targetNode == null) {
return;
}
// 找到了结点,如果此时树里只有这一个结点,则说明要删除最有一个结点
if (rootNode.leftNode == null && rootNode.rightNode == null) {
rootNode = null;
return;
}
//
Node parentNode = rootNode.searchParent(value);
// 如果删除的结点是叶子结点
if (targetNode.leftNode == null && targetNode.rightNode == null) {
// 如果要删除的结点是父节点的左节点
if (parentNode != null)
if (parentNode.leftNode != null && parentNode.leftNode.value == targetNode.value) {
parentNode.leftNode = null;
} else if (parentNode.rightNode != null && parentNode.rightNode.value == targetNode.value) {
parentNode.rightNode = null;
}
// 要删除的结点右两颗子树
} else if (targetNode.leftNode != null && targetNode.rightNode != null) {
// int min = delRightTreeMin(targetNode.rightNode);
// targetNode.value = min;
int max = delLeftTreeMax(targetNode.leftNode);
targetNode.value = max;
// 两种方法:
// 找到右子树最小结点,覆盖要删除的结点数据,删除右子树找到的那个结点
// 找到左子树最大结点,覆盖要删除的结点数据,删除左子树找到的那个结点
// 要删除的结点有一颗子树
} else {
if (targetNode.leftNode != null) {
if (parentNode != null) {
if (parentNode.leftNode.value == value) {
parentNode.leftNode = targetNode.leftNode;
} else {
parentNode.rightNode = targetNode.leftNode;
}
} else {
rootNode = targetNode.leftNode;
}
} else {
if (parentNode != null) {
if (parentNode.leftNode.value == value) {
parentNode.leftNode = targetNode.rightNode;
} else {
parentNode.rightNode = targetNode.rightNode;
}
} else {
rootNode = targetNode.rightNode;
}
}
}
}
}
public Node search(int value) {
if (rootNode == null) {
return null;
} else {
return rootNode.search(value);
}
}
public Node searchParent(int value) {
if (rootNode == null) {
return null;
} else {
return rootNode.searchParent(value);
}
}
public void infixOrder() {
if (rootNode == null) {
System.out.println("为空");
} else {
rootNode.infixOrder();
}
}
/**
* 删除左子树的最大结点
*
* @param node 父节点
* @return 最大节点值
*/
public int delLeftTreeMax(Node node) {
Node targetNode = node;
while (targetNode.rightNode != null) {
targetNode = targetNode.rightNode;
}
delNode(targetNode.value);
return targetNode.value;
}
/**
* 删除右子树的最小结点
*
* @param node 父节点
* @return 最小结点的值
*/
public int delRightTreeMin(Node node) {
Node targetNode = node;
// 找到最小的,一直向左循环
while (targetNode.leftNode != null) {
targetNode = targetNode.leftNode;
}
delNode(targetNode.value);
return targetNode.value;
}
}
class Node {
int value;
Node rightNode;
Node leftNode;
public Node(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
public Node search(int value) {
if (this.value == value) {
return this;
}
if (value < this.value) {
if (this.leftNode != null) {
return this.leftNode.search(value);
} else {
return null;
}
} else {
if (this.rightNode != null) {
return this.rightNode.search(value);
} else {
return null;
}
}
}
public Node searchParent(int value) {
// 如果当前结点的子节点就是寻找的结点,则返回
if ((this.leftNode != null && this.leftNode.value == value)
|| (this.rightNode != null && this.rightNode.value == value)) {
return this;
} else {
// 如果查找的值小于当前结点的值
if (value < this.value && this.leftNode != null) {
return this.leftNode.searchParent(value);
} else if (value >= this.value && this.rightNode != null) {
return this.rightNode.searchParent(value);
} else {
return null;
}
}
}
public void infixOrder() {
if (this.leftNode != null) {
this.leftNode.infixOrder();
}
System.out.println(this);
if (this.rightNode != null) {
this.rightNode.infixOrder();
}
}
public void add(Node node) {
if (node == null) {
return;
}
if (node.value > this.value) {
if (this.rightNode != null) {
this.rightNode.add(node);
} else {
this.rightNode = node;
}
} else {
if (this.leftNode != null) {
this.leftNode.add(node);
} else {
this.leftNode = node;
}
}
}
}
平衡二叉树(AVL树):
左旋转(将头结点左下旋转):
右旋转(将头结点右下旋转):
平衡二叉树其实是二叉排序树的升级版:
双旋转:
有时即使使用了旋转,左右子树的高度差依然大于1,这时需要先对(左\右)子树进行旋转,再对根结点进行旋转。
AVL树代码示例:
package bst;
public class AVLTreeDemo {
public static void main(String[] args) {
int[] arr = { 10, 11, 7, 6, 8, 9 };
AVLTree avlTree = new AVLTree();
for (int i = 0; i < arr.length; i++) {
avlTree.add(new Node2(arr[i]));
}
avlTree.infixOrder();
}
}
class AVLTree {
public Node2 rootNode;
public void add(Node2 node) {
if (rootNode == null) {
this.rootNode = node;
} else {
rootNode.add(node);
}
}
public void delNode(int value) {
if (rootNode == null) {
return;
} else {
Node2 targetNode = rootNode.search(value);
// 发现要删除的结点不存在,直接返回
if (targetNode == null) {
return;
}
// 找到了结点,如果此时树里只有这一个结点,则说明要删除最有一个结点
if (rootNode.leftNode == null && rootNode.rightNode == null) {
rootNode = null;
return;
}
//
Node2 parentNode = rootNode.searchParent(value);
// 如果删除的结点是叶子结点
if (targetNode.leftNode == null && targetNode.rightNode == null) {
// 如果要删除的结点是父节点的左节点
if (parentNode != null)
if (parentNode.leftNode != null && parentNode.leftNode.value == targetNode.value) {
parentNode.leftNode = null;
} else if (parentNode.rightNode != null && parentNode.rightNode.value == targetNode.value) {
parentNode.rightNode = null;
}
// 要删除的结点右两颗子树
} else if (targetNode.leftNode != null && targetNode.rightNode != null) {
// int min = delRightTreeMin(targetNode.rightNode);
// targetNode.value = min;
int max = delLeftTreeMax(targetNode.leftNode);
targetNode.value = max;
// 两种方法:
// 找到右子树最小结点,覆盖要删除的结点数据,删除右子树找到的那个结点
// 找到左子树最大结点,覆盖要删除的结点数据,删除左子树找到的那个结点
// 要删除的结点有一颗子树
} else {
if (targetNode.leftNode != null) {
if (parentNode != null) {
if (parentNode.leftNode.value == value) {
parentNode.leftNode = targetNode.leftNode;
} else {
parentNode.rightNode = targetNode.leftNode;
}
} else {
rootNode = targetNode.leftNode;
}
} else {
if (parentNode != null) {
if (parentNode.leftNode.value == value) {
parentNode.leftNode = targetNode.rightNode;
} else {
parentNode.rightNode = targetNode.rightNode;
}
} else {
rootNode = targetNode.rightNode;
}
}
}
}
}
public Node2 search(int value) {
if (rootNode == null) {
return null;
} else {
return rootNode.search(value);
}
}
public Node2 searchParent(int value) {
if (rootNode == null) {
return null;
} else {
return rootNode.searchParent(value);
}
}
public void infixOrder() {
if (rootNode == null) {
System.out.println("为空");
} else {
rootNode.infixOrder();
}
}
/**
* 删除左子树的最大结点
*
* @param node 父节点
* @return 最大节点值
*/
public int delLeftTreeMax(Node2 node) {
Node2 targetNode = node;
while (targetNode.rightNode != null) {
targetNode = targetNode.rightNode;
}
delNode(targetNode.value);
return targetNode.value;
}
/**
* 删除右子树的最小结点
*
* @param node 父节点
* @return 最小结点的值
*/
public int delRightTreeMin(Node node) {
Node targetNode = node;
// 找到最小的,一直向左循环
while (targetNode.leftNode != null) {
targetNode = targetNode.leftNode;
}
delNode(targetNode.value);
return targetNode.value;
}
}
class Node2 {
int value;
Node2 rightNode;
Node2 leftNode;
public int leftHeight() {
if (leftNode == null) {
return 0;
}
return leftNode.height();
}
public int rightHeight() {
if (rightNode == null) {
return 0;
}
return rightNode.height();
}
public int height() {
return Math.max(leftNode == null ? 0 : leftNode.height(), rightNode == null ? 0 : rightNode.height()) + 1;
}
// 传入头结点
public void rightRotate() {
// 定义新的结点,为头结点的副本
Node2 newNode = new Node2(value);
// 新节点接管原头结点的右节点
newNode.rightNode = this.rightNode;
// 新节点接管原头结点的左子结点的右子节点
newNode.leftNode = this.leftNode.rightNode;
// 至此在树的结构不发生变化的情况下,新的结点完成了原头结点的任务
// 原头结点可以被覆盖了
// 用左节点的值覆盖原头结点
this.value = leftNode.value;
// 此时左节点成为垃圾,接管左子树(右子树已被接管)
this.leftNode = this.leftNode.leftNode;
// 将副本结点加入树结构
this.rightNode = newNode;
// Node2 temp = this.leftNode;
// this.leftNode = temp.rightNode;
// temp.rightNode = this;
//
}
public void leftRotate() {
// 创建新的结点,用当前结点的值
Node2 newNode = new Node2(value);
// 把新结点的左子树设置成当前结点的左子树
newNode.leftNode = this.leftNode;
// 把新结点的右子树设置为当前结点的右子树的左子树
newNode.rightNode = this.rightNode.leftNode;
// 把当前结点的值替换成右子结点的值
this.value = this.rightNode.value;
// 把当前结点的右子树设置成当前结点的右子树的右子树
this.rightNode = this.rightNode.rightNode;
// 把当前结点的左子树设置为新的结点
leftNode = newNode;
}
public Node2(int value) {
this.value = value;
}
@Override
public String toString() {
return "Node [value=" + value + "]";
}
public Node2 search(int value) {
if (this.value == value) {
return this;
}
if (value < this.value) {
if (this.leftNode != null) {
return this.leftNode.search(value);
} else {
return null;
}
} else {
if (this.rightNode != null) {
return this.rightNode.search(value);
} else {
return null;
}
}
}
public Node2 searchParent(int value) {
// 如果当前结点的子节点就是寻找的结点,则返回
if ((this.leftNode != null && this.leftNode.value == value)
|| (this.rightNode != null && this.rightNode.value == value)) {
return this;
} else {
// 如果查找的值小于当前结点的值
if (value < this.value && this.leftNode != null) {
return this.leftNode.searchParent(value);
} else if (value >= this.value && this.rightNode != null) {
return this.rightNode.searchParent(value);
} else {
return null;
}
}
}
public void infixOrder() {
if (this.leftNode != null) {
this.leftNode.infixOrder();
}
System.out.println(this);
if (this.rightNode != null) {
this.rightNode.infixOrder();
}
}
public void add(Node2 node) {
if (node == null) {
return;
}
if (node.value > this.value) {
if (this.rightNode != null) {
this.rightNode.add(node);
} else {
this.rightNode = node;
}
} else {
if (this.leftNode != null) {
this.leftNode.add(node);
} else {
this.leftNode = node;
}
}
// 如果右子树的高度 大于 左子树的高度,左旋转
if (rightHeight() - leftHeight() > 1) {
if (rightNode != null && rightNode.leftHeight() > rightNode.rightHeight()) {
rightNode.rightRotate();
leftRotate();
} else {
leftRotate();
}
return;
}
if (leftHeight() - rightHeight() > 1) {
// 如果它的左子树的右子树高度大于它的右子树的高度
if (leftNode != null && leftNode.rightHeight() > leftNode.leftHeight()) {
// 先对当前结点的左节点(左子树) -> 左旋转
leftNode.leftRotate();
// 再对当前结点进行右旋转
rightRotate();
} else {
// 如果不满足,直接进行右旋转接可
rightRotate();
}
return;
}
}
}