AVL树的插入

原文连接:https://www.geeksforgeeks.org/avl-tree-set-1-insertion/
AVL是一个自平衡的二叉搜索树(BST),和普通二叉搜索树的区别是AVL树的所有节点的左子树和右子树的高度差不大于1.

一个AVL树的例子:
在这里插入图片描述
上面是一个AVL树因为每一个树节点的左子树和右子树的高度差小于或者等于1.

一个不是AVL树的例子:
在这里插入图片描述
上面不是一个AVL树因为左子树8和右子树18 的高度差大于1.

什么是AVL树?
大多数二叉搜索树(BST)的操作(如:搜索,最大,最小,插入,删除…等)需要O(h)的时间(h是BST的高度)。但是对于歪斜树(skewed Binary tree)操作时间变成了O(n)(n是树的节点数量)。如果我们确保树的高度在每次插入和删除后仍然是O(Logn),那么我们就能保证所有这些操作时间的上限是O(Logn)。而AVL树的高度总是O{Logn)。

插入
为了确保树每次插入后保持AVL,我们需要在标准的BST插入中增加一些重新平衡的操作。下面是两个基础的操作用来重新平衡BST而不违反BST的特性(keys(left) < key(root) < keys(right))。
1)左旋
2)右旋

T1,T2和T3是根节点y(左边)或者跟节点x(右边)的子树
		y                          x
       / \	        右旋	      / \
      x   T3  - - - - - - - >    T1   y 
     / \      < - - - - - - -        / \
    T1  T2          左旋            T2  T3
上面两个树的节点值都遵循下面的顺序:
keys(T1) < key(x) < keys(T2) < key(y) < keys(T3)

插入的步骤
设新插入的节点为w
1)标准的BST插入法插入w。
2)从w开始,往上寻找第一不平衡的节点,设z为第一个不平衡的节点,设y为从w到z路径上z的子节点,x为从w到z的路径上的z的孙节点。
3)通过对以z为根节点的子树适当的旋转来重新平衡。那么就需要处理下面四种情况(排列组合):
a)y是z的左子节点,同时x是z的左子节点(左 左)
b)y是z的左子节点,同时x是z的右子节点(左 左)
c)y是z的右子节点,同时x是z的右子节点(左 左)
d)y是z的右子节点,同时x是z的左子节点(左 左)

下面是这四种情况的操作,在所有的情况中,我们只需要重新平衡以z为根节点的子树,那么整个树就平衡了,因为平衡后的以z为根节点的子树的高度和插入节点前一样。
a)左 左:

T1, T2, T3 and T4 是子树
         z                                      y 
        / \                                   /   \
       y   T4            右旋(z)             x      z
      / \          - - - - - - - - ->      /  \    /  \ 
     x   T3                               T1  T2  T3  T4
    / \
  T1   T2

b左 右:

    z                               z                           x
   / \                            /   \                        /  \ 
  y   T4       左旋(y)            x    T4      右旋(z)        y      z
 / \      - - - - - - - - ->    /  \      - - - - - - - ->  / \    / \
T1   x                          y    T3                    T1  T2 T3  T4
    / \                        / \
  T2   T3                    T1   T2

c)右 右:

  z                                y
 /  \                            /   \ 
T1   y          左旋(z)         z      x
    /  \   - - - - - - - ->    / \    / \
   T2   x                     T1  T2 T3  T4
       / \
     T3  T4

c)右 左:

   z                            z                            x
  / \                          / \                          /  \ 
T1   y        右旋 (y)       T1   x         左旋(z)        z      y
    / \  - - - - - - - - ->     /  \   - - - - - - - ->  / \    / \
   x   T4                      T2   y                  T1  T2  T3  T4
  / \                              /  \
T2   T3                           T3   T4

插入的例子:
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
C语言代码实现:

// C program to insert a node in AVL tree 
#include<stdio.h> 
#include<stdlib.h> 

// An AVL tree node 
struct Node 
{ 
	int key; 
	struct Node *left; 
	struct Node *right; 
	int height; 
}; 

// A utility function to get maximum of two integers 
int max(int a, int b); 

// A utility function to get the height of the tree 
int height(struct Node *N) 
{ 
	if (N == NULL) 
		return 0; 
	return N->height; 
} 

// A utility function to get maximum of two integers 
int max(int a, int b) 
{ 
	return (a > b)? a : b; 
} 

/* Helper function that allocates a new node with the given key and 
	NULL left and right pointers. */
struct Node* newNode(int key) 
{ 
	struct Node* node = (struct Node*) 
						malloc(sizeof(struct Node)); 
	node->key = key; 
	node->left = NULL; 
	node->right = NULL; 
	node->height = 1; // new node is initially added at leaf 
	return(node); 
} 

// A utility function to right rotate subtree rooted with y 
// See the diagram given above. 
struct Node *rightRotate(struct Node *y) 
{ 
	struct Node *x = y->left; 
	struct Node *T2 = x->right; 

	// Perform rotation 
	x->right = y; 
	y->left = T2; 

	// Update heights 
	y->height = max(height(y->left), height(y->right))+1; 
	x->height = max(height(x->left), height(x->right))+1; 

	// Return new root 
	return x; 
} 

// A utility function to left rotate subtree rooted with x 
// See the diagram given above. 
struct Node *leftRotate(struct Node *x) 
{ 
	struct Node *y = x->right; 
	struct Node *T2 = y->left; 

	// Perform rotation 
	y->left = x; 
	x->right = T2; 

	// Update heights 
	x->height = max(height(x->left), height(x->right))+1; 
	y->height = max(height(y->left), height(y->right))+1; 

	// Return new root 
	return y; 
} 

// Get Balance factor of node N 
int getBalance(struct Node *N) 
{ 
	if (N == NULL) 
		return 0; 
	return height(N->left) - height(N->right); 
} 

// Recursive function to insert a key in the subtree rooted 
// with node and returns the new root of the subtree. 
struct Node* insert(struct Node* node, int key) 
{ 
	/* 1. Perform the normal BST insertion */
	if (node == NULL) 
		return(newNode(key)); 

	if (key < node->key) 
		node->left = insert(node->left, key); 
	else if (key > node->key) 
		node->right = insert(node->right, key); 
	else // Equal keys are not allowed in BST 
		return node; 

	/* 2. Update height of this ancestor node */
	node->height = 1 + max(height(node->left), 
						height(node->right)); 

	/* 3. Get the balance factor of this ancestor 
		node to check whether this node became 
		unbalanced */
	int balance = getBalance(node); 

	// If this node becomes unbalanced, then 
	// there are 4 cases 

	// Left Left Case 
	if (balance > 1 && key < node->left->key) 
		return rightRotate(node); 

	// Right Right Case 
	if (balance < -1 && key > node->right->key) 
		return leftRotate(node); 

	// Left Right Case 
	if (balance > 1 && key > node->left->key) 
	{ 
		node->left = leftRotate(node->left); 
		return rightRotate(node); 
	} 

	// Right Left Case 
	if (balance < -1 && key < node->right->key) 
	{ 
		node->right = rightRotate(node->right); 
		return leftRotate(node); 
	} 

	/* return the (unchanged) node pointer */
	return node; 
} 

// A utility function to print preorder traversal 
// of the tree. 
// The function also prints height of every node 
void preOrder(struct Node *root) 
{ 
	if(root != NULL) 
	{ 
		printf("%d ", root->key); 
		preOrder(root->left); 
		preOrder(root->right); 
	} 
} 

/* Drier program to test above function*/
int main() 
{ 
struct Node *root = NULL; 

/* Constructing tree given in the above figure */
root = insert(root, 10); 
root = insert(root, 20); 
root = insert(root, 30); 
root = insert(root, 40); 
root = insert(root, 50); 
root = insert(root, 25); 

/* The constructed AVL Tree would be 
			30 
		/ \ 
		20 40 
		/ \	 \ 
	10 25 50 
*/

printf("Preorder traversal of the constructed AVL"
		" tree is \n"); 
preOrder(root); 

return 0; 
} 

输出:

  Preorder traversal of the constructed AVL tree is
  30 20 10 25 40 50
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值