單頁營銷型網(wǎng)站模板營銷課程
文章目錄
- 概述
- 一、定義與特性
- 二、平衡因子
- 三、基本操作
- 四、旋轉(zhuǎn)操作
- 五、應(yīng)用場景
- Java代碼實(shí)現(xiàn)
概述
AVL樹是一種自平衡的二叉查找樹,由兩位俄羅斯數(shù)學(xué)家G.M.Adelson-Velskii和E.M.Landis在1962年發(fā)明。想了解樹的相關(guān)概念,請(qǐng)點(diǎn)擊這里。以下是對(duì)AVL樹的詳細(xì)說明:
一、定義與特性
- 定義:AVL樹是一種二叉查找樹,其中每個(gè)節(jié)點(diǎn)的左右子樹的高度差的絕對(duì)值(即平衡因子)不超過1。
- 特性:
- 左右子樹都是AVL樹。
- 左右子樹高度之差(簡稱平衡因子)的絕對(duì)值不超過1(-1、0、1)。
- 任意節(jié)點(diǎn)的左右子樹的高度差不會(huì)超過1,這保證了樹的高度相對(duì)較低,從而提高了搜索、插入和刪除操作的效率。
二、平衡因子
平衡因子(Balance Factor,BF)是AVL樹中的一個(gè)重要概念,用于衡量節(jié)點(diǎn)的左右子樹的高度差。平衡因子的值只能是-1、0或1。具體計(jì)算方式為:節(jié)點(diǎn)的右子樹高度減去左子樹高度。
三、基本操作
AVL樹的基本操作包括插入、刪除和查找,這些操作都需要在保持樹平衡的前提下進(jìn)行。
-
插入:
- 按照二叉查找樹的方式插入新節(jié)點(diǎn)。
- 插入后,從插入點(diǎn)向上回溯,更新每個(gè)節(jié)點(diǎn)的平衡因子。
- 如果發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)的平衡因子絕對(duì)值超過1,則進(jìn)行旋轉(zhuǎn)操作以恢復(fù)平衡。
-
刪除:
- 找到要?jiǎng)h除的節(jié)點(diǎn),并將其向下旋轉(zhuǎn)成一個(gè)葉子節(jié)點(diǎn)。
- 直接刪除該葉子節(jié)點(diǎn)。
- 從刪除點(diǎn)向上回溯,更新每個(gè)節(jié)點(diǎn)的平衡因子。
- 如果發(fā)現(xiàn)某個(gè)節(jié)點(diǎn)的平衡因子絕對(duì)值超過1,則進(jìn)行旋轉(zhuǎn)操作以恢復(fù)平衡。
-
查找:
- 在AVL樹中查找元素的過程與在二叉查找樹中相同。
- 由于AVL樹總是保持平衡的,所以查找操作的時(shí)間復(fù)雜度為O(log n)。
四、旋轉(zhuǎn)操作
旋轉(zhuǎn)操作是AVL樹保持平衡的關(guān)鍵。根據(jù)節(jié)點(diǎn)插入或刪除后不平衡的具體情況,AVL樹的旋轉(zhuǎn)可以分為四種類型:
- 單向右旋(LL):當(dāng)在節(jié)點(diǎn)的左子樹的左子樹上插入新節(jié)點(diǎn)導(dǎo)致節(jié)點(diǎn)不平衡(平衡因子為2)時(shí),進(jìn)行右旋轉(zhuǎn)操作。
- 單向左旋(RR):當(dāng)在節(jié)點(diǎn)的右子樹的右子樹上插入新節(jié)點(diǎn)導(dǎo)致節(jié)點(diǎn)不平衡(平衡因子為-2)時(shí),進(jìn)行左旋轉(zhuǎn)操作。
- 雙向旋轉(zhuǎn)(先左后右,LR):當(dāng)在節(jié)點(diǎn)的左子樹的右子樹上插入新節(jié)點(diǎn)導(dǎo)致節(jié)點(diǎn)不平衡(平衡因子為2)時(shí),先進(jìn)行左旋轉(zhuǎn)再進(jìn)行右旋轉(zhuǎn)。
- 雙向旋轉(zhuǎn)(先右后左,RL):當(dāng)在節(jié)點(diǎn)的右子樹的左子樹上插入新節(jié)點(diǎn)導(dǎo)致節(jié)點(diǎn)不平衡(平衡因子為-2)時(shí),先進(jìn)行右旋轉(zhuǎn)再進(jìn)行左旋轉(zhuǎn)。
五、應(yīng)用場景
AVL樹適用于插入刪除次數(shù)較少但查找頻繁的場景。例如,Windows進(jìn)程地址空間管理就采用了AVL樹來實(shí)現(xiàn)高效的查找操作。然而,由于AVL樹在插入和刪除操作后需要進(jìn)行復(fù)雜的旋轉(zhuǎn)操作來保持平衡,所以其性能在插入和刪除操作頻繁的場景下可能不如其他數(shù)據(jù)結(jié)構(gòu)(如紅黑樹)。
綜上所述,AVL樹是一種高效的自平衡二叉查找樹,通過引入平衡因子和旋轉(zhuǎn)操作來保持樹的平衡性,從而提高了搜索、插入和刪除操作的效率。
Java代碼實(shí)現(xiàn)
下面是一個(gè)簡單的AVL樹在Java中的實(shí)現(xiàn)。這個(gè)實(shí)現(xiàn)包括了插入、刪除和查找操作,以及必要的旋轉(zhuǎn)操作來維持樹的平衡。
class AVLTree {private class Node {int key, height;Node left, right;Node(int d) {key = d;height = 1;}}private Node root;// Utility function to get the height of the treeint height(Node N) {if (N == null)return 0;return N.height;}// Utility function to get the maximum of two integersint max(int a, int b) {return (a > b) ? a : b;}// Right rotate subtree rooted with yNode rightRotate(Node y) {Node x = y.left;Node T2 = x.right;// Perform rotationx.right = y;y.left = T2;// Update heightsy.height = max(height(y.left), height(y.right)) + 1;x.height = max(height(x.left), height(x.right)) + 1;// Return new rootreturn x;}// Left rotate subtree rooted with xNode leftRotate(Node x) {Node y = x.right;Node T2 = y.left;// Perform rotationy.left = x;x.right = T2;// Update heightsx.height = max(height(x.left), height(x.right)) + 1;y.height = max(height(y.left), height(y.right)) + 1;// Return new rootreturn y;}// Get Balance factor of node Nint getBalance(Node N) {if (N == null)return 0;return height(N.left) - height(N.right);}// Insert a node with given key in the subtree rooted with node and returns the new root of the subtreeNode insert(Node node, int key) {// Perform the normal BST insertionif (node == null)return (new Node(key));if (key < node.key)node.left = insert(node.left, key);else if (key > node.key)node.right = insert(node.right, key);else // Duplicate keys are not allowed in BSTreturn node;// Update height of this ancestor nodenode.height = 1 + max(height(node.left), height(node.right));// Get the balance factor of this ancestor node to check whether this node became unbalancedint balance = getBalance(node);// If this node becomes unbalanced, then there are 4 cases// Left Left Caseif (balance > 1 && key < node.left.key)return rightRotate(node);// Right Right Caseif (balance < -1 && key > node.right.key)return leftRotate(node);// Left Right Caseif (balance > 1 && key > node.left.key) {node.left = leftRotate(node.left);return rightRotate(node);}// Right Left Caseif (balance < -1 && key < node.right.key) {node.right = rightRotate(node.right);return leftRotate(node);}// Return the (unchanged) node pointerreturn node;}// Delete a node with given key in the subtree rooted with node and returns the new root of the subtreeNode deleteNode(Node root, int key) {// Perform standard BST deleteif (root == null)return root;if (key < root.key)root.left = deleteNode(root.left, key);else if (key > root.key)root.right = deleteNode(root.right, key);else {// node with only one child or no childif ((root.left == null) || (root.right == null)) {Node temp = null;if (temp == root.left)temp = root.right;elsetemp = root.left;// No child caseif (temp == null) {temp = root;root = null;} else // One child caseroot = temp; // Copy the contents of the non-empty child} else {// node with two children: Get the inorder successor (smallest in the right subtree)Node temp = minValueNode(root.right);// Copy the inorder successor's data to this noderoot.key = temp.key;// Delete the inorder successorroot.right = deleteNode(root.right, temp.key);}}// If the tree had only one node then returnif (root == null)return root;// Update height of the current noderoot.height = max(height(root.left), height(root.right)) + 1;// Get the balance factor of this node (to check whether this node became unbalanced)int balance = getBalance(root);// If this node becomes unbalanced, then there are 4 cases// Left Left Caseif (balance > 1 && getBalance(root.left) >= 0)return rightRotate(root);// Left Right Caseif (balance > 1 && getBalance(root.left) < 0) {root.left = leftRotate(root.left);return rightRotate(root);}// Right Right Caseif (balance < -1 && getBalance(root.right) <= 0)return leftRotate(root);// Right Left Caseif (balance < -1 && getBalance(root.right) > 0) {root.right = rightRotate(root.right);return leftRotate(root);}return root;}Node minValueNode(Node node) {Node current = node;// Loop down to find the leftmost leafwhile (current.left != null)current = current.left;return current;}// A utility function to do inorder traversal of BSTvoid inorder(Node root) {if (root != null) {inorder(root.left);System.out.print(root.key + " ");inorder(root.right);}}// Main functionpublic static void main(String[] args) {AVLTree tree = new AVLTree();/* Constructing tree given in the above figure */tree.root = tree.insert(tree.root, 10);tree.root = tree.insert(tree.root, 20);tree.root = tree.insert(tree.root, 30);tree.root = tree.insert(tree.root, 40);tree.root = tree.insert(tree.root, 50);tree.root = tree.insert(tree.root, 25);/* The constructed AVL Tree would be30/ \20 40/ \ \10 25 50*/System.out.println("Inorder traversal of the constructed AVL tree is:");tree.inorder(tree.root);System.out.println("\n\nDelete 20");tree.root = tree.deleteNode(tree.root, 20);System.out.println("Inorder traversal of the modified tree is:");tree.inorder(tree.root);System.out.println("\n\nDelete 30");tree.root = tree.deleteNode(tree.root, 30);System.out.println("Inorder traversal of the modified tree is:");tree.inorder(tree.root);System.out.println("\n\nDelete 50");tree.root = tree.deleteNode(tree.root, 50);System.out.println("Inorder traversal of the modified tree is:");tree.inorder(tree