**看到空間的狗糧,我默默地打開了我的IDEA,靜靜的new了一個對象AVLTree;**讓我來慢慢描述我的這個“對象”AVL樹。
維基百科中對AVL樹的解釋:
在計算機科學中,AVL樹是最早被髮明的自平衡二叉查找樹。在AVL樹中,任一節點對應的兩棵子樹的最大高度差爲1,因此它也被稱爲高度平衡樹。查找、插入和刪除在平均和最壞情況下的時間複雜度都是{\displaystyle O(\log {n})}O(\log{n})。增加和刪除元素的操作則可能需要藉由一次或多次樹旋轉,以實現樹的重新平衡。AVL樹得名於它的發明者G. M. Adelson-Velsky和Evgenii Landis,他們在1962年的論文《An algorithm for the organization of information》中公開了這一數據結構。
節點的平衡因子是它的左子樹的高度減去它的右子樹的高度(有時相反)。帶有平衡因子1、0或 -1的節點被認爲是平衡的。帶有平衡因子 -2或2的節點被認爲是不平衡的,並需要重新平衡這個樹。平衡因子可以直接存儲在每個節點中,或從可能存儲在節點中的子樹高度計算出來。
操作:
AVL樹的基本操作一般涉及運作同在不平衡的二叉查找樹所運作的同樣的算法。但是要進行預先或隨後做一次或多次所謂的"AVL旋轉"。
以下圖表以四列表示四種情況,每行表示在該種情況下要進行的操作。在左左和右右的情況下,只需要進行一次旋轉操作;在左右和右左的情況下,需要進行兩次旋轉操作。
代碼實現:
//二叉樹類
class AVlTree {
private Node root;
//添加
public void add(Node node) {
if (root == null) root = node;
else root.add(node);
}
//中序遍歷
public void infix() {
if (root == null) throw new RuntimeException("空樹");
root.infix();
}
//刪除節點
public void delNode(int value) {
if (root == null) throw new RuntimeException("空樹");
//查找刪除的節點--->返回爲空,不存在 --->
//如果該樹只有一個節點,將根節點至於空
Node node = root.search(value);
if (node == null) throw new RuntimeException("該節點不存在");
if (root.getLeft() == null && root.getRight() == null) {
root = null;
return;
}
Node parent = root.searchParent(value);
//1、如果該節點是葉子節點-->查找到他的父節點,查看他是父節點的左節點還是右節點,刪除
if (node.getRight() == null && node.getLeft() == null) {
if (parent.getRight().getValue() == value) parent.setRight(null);
else parent.setLeft(null);
} else if (node.getRight() != null && node.getLeft() != null) {
//有兩個子節點的節點-->找到該節點右子樹的最小值進行替換
//找到該節點左子樹的最大值進行替換
int parentMin = delParentMin(node.getRight());
node.setValue(parentMin);
} else {
//如果是根節點
if (parent == null) {
if (node.getRight() != null) {
node.setValue(node.getRight().getValue());
node.setRight(null);
} else {
node.setValue(node.getLeft().getValue());
node.setLeft(null);
}
return;
}
if (node.getLeft() != null) {//該節點有左子節點是父節點的左子節點
if (parent.getLeft().getValue() == value) parent.setLeft(node.getLeft());
else parent.setRight(node.getLeft());
} else {
if (parent.getRight().getValue() == value) parent.setRight(node.getRight());
else parent.setLeft(node.getRight());//該節點是父節點的左子節點
}
}
}
/**
* 查找該節點右子樹的最小值
* 應該由父節點的右子節點調用
*
* @param node
* @return
*/
private int delParentMin(Node node) {
Node temp = node;
while (temp.getLeft() != null) temp = temp.getLeft();
delNode(temp.getValue());
return temp.getValue();
}
public Node getRoot() {
return root;
}
}
//節點類
class Node {
private int value;
private Node left;
private Node right;
public Node(int value) {
this.value = value;
}
//查找當前節點的父節點
public Node searchParent(int value) {
if ((this.getLeft() != null && this.getLeft().getValue() == value) || (this.getRight() != null && this.getRight().getValue() == value)) {
return this;
} else {
if (this.getValue() > value) {
if (this.getLeft() != null) return this.getLeft().searchParent(value);
} else {
if (this.getRight() == null) return null;
else return this.getRight().searchParent(value);
}
return null;
}
}
//查找當前節點
public Node search(int value) {
if (this.value == value) return this;
if (this.value > value) {
if (this.left != null) return this.left.search(value);
else return null;
} else {
if (this.right != null) return this.right.search(value);
else return null;
}
}
//添加
public void add(Node node) {
if (node == null) return;
if (this.value > node.value) {
if (this.left == null) this.setLeft(node);
else this.left.add(node);
} else {
if (this.right == null) this.setRight(node);
else this.right.add(node);
}
if (rightHight() - leftHight() > 1) {
if (right != null && this.getRight().leftHight() > this.getRight().rightHight()) {
rightRotate();
}
leftRotate();
return;//必須加
}
if (leftHight() - rightHight() > 1) {//右旋轉
//當符合右旋轉的條件時如果當前節點的左子樹的右子樹大於他的左子樹的高度
//先進性左旋轉
if (left != null && this.left.rightHight() > this.left.leftHight()) {
this.left.leftRotate();
}
rightRotate();
}
}
//左旋轉
public void leftRotate() {
Node newNode = new Node(this.getValue());
newNode.setLeft(this.getLeft());
newNode.setRight(this.getRight().getLeft());
this.setValue(this.getRight().getValue());
this.setRight(this.getRight().getRight());
this.setLeft(newNode);
}
//右旋轉
public void rightRotate() {
Node newNode = new Node(this.getValue());
newNode.setRight(this.getRight());
newNode.setLeft(this.getLeft().getRight());
this.setValue(this.getLeft().getValue());
this.setLeft(this.getLeft().getLeft());
this.setRight(newNode);
}
//中序遍歷
public void infix() {
if (this.left != null) this.left.infix();
System.out.println(this);
if (this.right != null) this.right.infix();
}
//求數的高度
public int hight() {
return Math.max(this.right == null ? 0 : this.right.hight(), this.left == null ? 0 : this.left.hight()) + 1;
}
//右子樹的高度
public int rightHight() {
if (this.getRight() == null) return 0;
else return this.right.hight();
}
//左子樹
public int leftHight() {
if (this.getLeft() == null) return 0;
else return this.left.hight();
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
@Override
public String toString() {
return new StringJoiner(", ", Node.class.getSimpleName() + "[", "]")
.add("value=" + value)
.toString();
}
}