Python Implementation of AVL Tree

Source: Internet
Author: User

AVL is a binary search tree with a balance condition. Generally, the height difference between the left and right subtree of each node is 1 (the height of the empty tree is defined as-1 ).

In an AVL tree with a height of h, the minimum number of nodes S (h) is derived from S (h) = S (h-1) + S (H-2) + 1, S (0) = 1, S (1) = 2.

For example, the minimum number of nodes required for AVL trees with a height of 0, 1, and 2, respectively.

1. AVL tree implementation. traversal and search operations are the same as binary search trees.
class Node(object):    def __init__(self,key):        self.key=key        self.left=None        self.right=None        self.height=0class AVLTree(object):    def __init__(self):        self.root=None    def find(self,key):        if self.root is None:            return None        else:            return self._find(key,self.root)    def _find(self,key,node):        if node is None:            return None        elif key<node.key:            return self._find(key,self.left)        elif key>node.key:            return self._find(key,self.right)        else:            return node    def findMin(self):        if self.root is None:            return None        else:            return self._findMin(self.root)    def _findMin(self,node):        if node.left:            return self._findMin(node.left)        else:            return node    def findMax(self):        if self.root is None:            return None        else:            return self._findMax(self.root)    def _findMax(self,node):        if node.right:            return self._findMax(node.right)        else:            return node    def height(self,node):        if node is None:            return -1        else:            return node.height
2. AVL Tree Insertion

Inserting a node may damage the AVL Tree balance and can be corrected by rotation.

After a node is inserted, the balance between the inserted node and the root node may be changed. We need to find the first node that breaks the balance condition, which is called K. The height difference between the two Subtrees of K is 2.

There are four situations of imbalance:

1. Insert the left subtree of K's left son once.

2. Insert the right subtree of the Left son of K

3. Insert the left subtree of the right son of K once.

4. Insert the right subtree of K's right son once.

Case 1 and case 4 are symmetric and require a single rotation operation, while case 2 and Case 3 require a double rotation operation.

Case 1:

 

    def singleLeftRotate(self,node):        k1=node.left        node.left=k1.right        k1.right=node        node.height=max(self.height(node.right),self.height(node.left))+1        k1.height=max(self.height(k1.left),node.height)+1        return k1

  

Case 4:

 

def singleRightRotate(self,node):    k1=node.right    node.right=k1.left    k1.left=node    node.height=max(self.height(node.right),self.height(node.left))+1    k1.height=max(self.height(k1.right),node.height)+1    return k1

Case 3:

 

It is equivalent to two single rotations.

def doubleRightRotate(self,node):    node.right=self.singleLeftRotate(node.right)    return self.singleRightRotate(node)

Case 2:

Similar to case 3, a single rotation is performed twice.

def doubleLeftRotate(self,node):    node.left=self.singleRightRotate(node.left)    return self.singleLeftRotate(node)

A series of insert operations:

The insert Code is as follows:

    def put(self,key):        if not self.root:            self.root=Node(key)        else:            self.root=self._put(key,self.root)    def _put(self,key,node):        if node is None:            node=Node(key)        elif key<node.key:            node.left=self._put(key,node.left)            if (self.height(node.left)-self.height(node.right))==2:                if key<node.left.key:                    node=self.singleLeftRotate(node)                else:                    node=self.doubleLeftRotate(node)                    elif key>node.key:            node.right=self._put(key,node.right)            if (self.height(node.right)-self.height(node.left))==2:                if key<node.right.key:                    node=self.doubleRightRotate(node)                else:                    node=self.singleRightRotate(node)                        node.height=max(self.height(node.right),self.height(node.left))+1        return node

3. AVL tree deletion:

The delete operation is complicated. If any error occurs, correct it.

1. The current node is the node to be deleted and is a leaf (no subtree). The current node (None) is not balanced.

2. The current node is the node to be deleted and has only one left son or right son. Replacing the current node with the left son or right son will not affect the current node balance.

3. the current node is the node to be deleted and has the left subtree and the right subtree. If the height of the right subtree is high, select the smallest node from the right subtree and assign the value to the current node, delete the smallest node of the right subtree. If the height of the Left subtree is high, select the largest node from the left subtree, assign its value to the current node, and then delete the maximum node of the Left subtree. In this way, the current node balance will not be damaged.

4. If the current node is not the node to be deleted, perform recursive operations on its left or right subtree. The balancing condition of the current node may be damaged and you need to perform the balancing operation.

For example, if 25 is the current node and 17 is deleted from the left subtree, the balance condition is damaged. The left subtree (28) of the right subtree (30) of the current node (25) is required) determines whether the height is higher than the height of the right subtree (35). If the height is higher than the height, double rotation is performed. Otherwise, single rotation is performed.

    def delete(self,key):        self.root=self.remove(key,self.root)    def remove(self,key,node):        if node is None:            raise KeyError,'Error,key not in tree'        elif key<node.key:            node.left=self.remove(key,node.left)            if (self.height(node.right)-self.height(node.left))==2:                if self.height(node.right.right)>=self.height(node.right.left):                    node=self.singleRightRotate(node)                else:                    node=self.doubleRightRotate(node)            node.height=max(self.height(node.left),self.height(node.right))+1                                    elif key>node.key:            node.right=self.remove(key,node.right)            if (self.height(node.left)-self.height(node.right))==2:                if self.height(node.left.left)>=self.height(node.left.right):                    node=self.singleLeftRotate(node)                else:                    node=self.doubleLeftRotate(node)            node.height=max(self.height(node.left),self.height(node.right))+1                elif node.left and node.right:            if node.left.height<=node.right.height:                minNode=self._findMin(node.right)                node.key=minNode.key                node.right=self.remove(node.key,node.right)            else:                maxNode=self._findMax(node.left)                node.key=maxNode.key                node.left=self.remove(node.key,node.left)            node.height=max(self.height(node.left),self.height(node.right))+1        else:            if node.right:                node=node.right            else:                node=node.left                return node

  

All code:

class Node(object):    def __init__(self,key):        self.key=key        self.left=None        self.right=None        self.height=0class AVLTree(object):    def __init__(self):        self.root=None    def find(self,key):        if self.root is None:            return None        else:            return self._find(key,self.root)    def _find(self,key,node):        if node is None:            return None        elif key<node.key:            return self._find(key,self.left)        elif key>node.key:            return self._find(key,self.right)        else:            return node    def findMin(self):        if self.root is None:            return None        else:            return self._findMin(self.root)    def _findMin(self,node):        if node.left:            return self._findMin(node.left)        else:            return node    def findMax(self):        if self.root is None:            return None        else:            return self._findMax(self.root)    def _findMax(self,node):        if node.right:            return self._findMax(node.right)        else:            return node    def height(self,node):        if node is None:            return -1        else:            return node.height        def singleLeftRotate(self,node):        k1=node.left        node.left=k1.right        k1.right=node        node.height=max(self.height(node.right),self.height(node.left))+1        k1.height=max(self.height(k1.left),node.height)+1        return k1    def singleRightRotate(self,node):        k1=node.right        node.right=k1.left        k1.left=node        node.height=max(self.height(node.right),self.height(node.left))+1        k1.height=max(self.height(k1.right),node.height)+1        return k1    def doubleLeftRotate(self,node):        node.left=self.singleRightRotate(node.left)        return self.singleLeftRotate(node)    def doubleRightRotate(self,node):        node.right=self.singleLeftRotate(node.right)        return self.singleRightRotate(node)    def put(self,key):        if not self.root:            self.root=Node(key)        else:            self.root=self._put(key,self.root)    def _put(self,key,node):        if node is None:            node=Node(key)        elif key<node.key:            node.left=self._put(key,node.left)            if (self.height(node.left)-self.height(node.right))==2:                if key<node.left.key:                    node=self.singleLeftRotate(node)                else:                    node=self.doubleLeftRotate(node)                    elif key>node.key:            node.right=self._put(key,node.right)            if (self.height(node.right)-self.height(node.left))==2:                if key<node.right.key:                    node=self.doubleRightRotate(node)                else:                    node=self.singleRightRotate(node)                        node.height=max(self.height(node.right),self.height(node.left))+1        return node            def delete(self,key):        self.root=self.remove(key,self.root)    def remove(self,key,node):        if node is None:            raise KeyError,'Error,key not in tree'        elif key<node.key:            node.left=self.remove(key,node.left)            if (self.height(node.right)-self.height(node.left))==2:                if self.height(node.right.right)>=self.height(node.right.left):                    node=self.singleRightRotate(node)                else:                    node=self.doubleRightRotate(node)            node.height=max(self.height(node.left),self.height(node.right))+1                                    elif key>node.key:            node.right=self.remove(key,node.right)            if (self.height(node.left)-self.height(node.right))==2:                if self.height(node.left.left)>=self.height(node.left.right):                    node=self.singleLeftRotate(node)                else:                    node=self.doubleLeftRotate(node)            node.height=max(self.height(node.left),self.height(node.right))+1                elif node.left and node.right:            if node.left.height<=node.right.height:                minNode=self._findMin(node.right)                node.key=minNode.key                node.right=self.remove(node.key,node.right)            else:                maxNode=self._findMax(node.left)                node.key=maxNode.key                node.left=self.remove(node.key,node.left)            node.height=max(self.height(node.left),self.height(node.right))+1        else:            if node.right:                node=node.right            else:                node=node.left                return node

  

  

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.