AVL tree is a special binary search tree, by definition, any node, its left tree height and right tree height difference is not more than 1. The purpose of AVL tree is to try best to reduce the search time complexity. if the binary search tree is too deep, that will increase the search cost. By converting it to AVL, the search time can be stably controlled within O(LogN).
Data Structure and High Level API
public class AVLTreeNode { public int data { get; set; } public AVLTreeNode leftChild { get; set; } public AVLTreeNode rightChild { get; set; } public int height { get; set; } public AVLTreeNode(int data) { this.data = data; this.height = 1; } }
AVLTreeNode Insert(AVLTreeNode node, int key)
INParam: current root node, incoming key OUT: the new root node AVLNode Insert(AVLTreeNode node, int key) = 1) if node is null, return new AVLNode(key) 2) if key is greater than current node, node.rightChild = Insert(node.rightChild, key) 3) if key is smaller than current node, node.leftChild = Insert(node.leftChild, key)
public class AVLTree { public AVLTreeNode root { get; set; } private int Height(AVLTreeNode node) { if (node == null) { return 0; } if (node.leftChild == null && node.rightChild == null) { return 1; } else if (node.leftChild == null) { return 1 + node.rightChild.height; } else if (node.rightChild == null) { return 1 + node.leftChild.height; } return 1 + Math.Max(node.leftChild.height, node.rightChild.height); } private int GetBalance(AVLTreeNode node) { if (node == null) { return 0; } return Height(node.leftChild) - Height(node.rightChild); } // 右旋,左孩子和右孙子 private AVLTreeNode RightRotation(AVLTreeNode node) { AVLTreeNode childNode = node.leftChild; AVLTreeNode grandChildNode = childNode.rightChild; childNode.rightChild = node; node.leftChild = grandChildNode; // for affected nodes, update their height node.height = Math.Max(Height(node.leftChild), Height(node.rightChild)) + 1; childNode.height = Math.Max(Height(childNode.rightChild), Height(childNode.leftChild)) + 1; return childNode; }
// 左旋
// 右孩子和左孙子 private AVLTreeNode LeftRotation(AVLTreeNode node) { AVLTreeNode childNode = node.rightChild; AVLTreeNode grandChildNode = childNode.leftChild; childNode.leftChild = node; node.rightChild = grandChildNode; node.height = Math.Max(Height(node.leftChild), Height(node.rightChild)) + 1; childNode.height = Math.Max(Height(childNode.rightChild), Height(childNode.leftChild)) + 1; return childNode; } public AVLTreeNode Insert(AVLTreeNode node, int key) { if (node == null) { return new AVLTreeNode(key); } if (key < node.data) { node.leftChild = Insert(node.leftChild, key); } else { node.rightChild = Insert(node.rightChild, key); } node.height = 1 + Math.Max(Height(node.leftChild), Height(node.rightChild)); // after insertion, calculate the balance int balance = GetBalance(node); // left left case if (balance > 1 && node.leftChild.data > key) // balance is greater than 1, which means node must have left child. { // right rotation return RightRotation(node); // 向右转, 左左组合,入参是当前根节点, 要动谁,谁就是参数 } // left right case
6
/
4
5
if (balance > 1 && node.leftChild.data <= key) { // left rotation first node.leftChild = LeftRotation(node.leftChild); // 左旋,传入参数是左子节点 // then do right rotation return RightRotation(node); } // right right case if (balance < -1 && node.rightChild.data <= key) { // left rotation return LeftRotation(node); } // right left case if (balance < -1 && node.rightChild.data > key) { // right rotation node.rightChild = RightRotation(node.rightChild); // 右旋,传入参数是node rightChild // left rotation return LeftRotation(node); } return node; } public void InOrder(AVLTreeNode node) { if (node == null) { return; } InOrder(node.leftChild); Console.WriteLine(node.data); InOrder(node.rightChild); } }
左旋和右旋分别cover两种情况,举个例子,右旋既可以解决左左的旋转,也可以解决右侧子树, 右左的情况。所以旋转函数只有两个API,左旋和右旋,no more choice!