AVL树,一种平衡搜索二叉树,是BST(Binary Search Tree)二叉查找树的一种,实际上是在BST搜索树上增加了平衡条件,所谓的平衡条件指的是树中的每个结点的左孩子与右孩子的高度之差不大于1。既然是一种BST树,那么它肯定满足BST的一般性质。在计算机科学领域,二叉搜索树(BST),有时也称作有序的或者排序好的二叉树,是一种特殊类型的容器。它允许快速的查找,增加,删除结点,可以被用作动态集合的生成。BST树以有序的键值保存,这样在查找或者其他操作时可以利用二分查找原理。在了解AVL树之前,先了解下二叉查找树BST的一般性质:
1. 在一棵二叉查找树,执行查找、插入、删除等操作的时间复杂度为O(lgn)。
2. 一棵具有n个结点的BST生成线性链表,则这些操作最坏情况运行时间为O(n)。
而AVL树,则是对BST树操作的增强,对树的操作最好与最坏时间均为O(lgn),在动态生成AVL树时,如果结点的左右孩子深度之差大于1,则需要根据一定的规则来调整树,这个被称为树的旋转。由于二叉树平衡高度大于1(即需要调整的条件),从调整结点开始的子树至少深度为3(包括根结点),而从根结点到插入后的叶子结点路径,每一层都有2个方向,而2层结点则有4种可能性,即LL,RR,LR,RL等这4种情形。比如LL左平衡型,指的是从待需要调整的子树根结点开始,其左边孩子的深度比右边孩子的叶子结点大2,利用扁担原则,需要向右边平衡。下面简单用图示来说明这几种类型的调整规则:
//============================================================================
// Name : AVL.h
// Author : @CodingGeek
// Version : V1.0
// Copyright :
// Description : AVL平衡搜索二叉树代码实现
//============================================================================
#ifndef AVL_H_
#define AVL_H_
typedef int KEY_TYPE;
/* AVL树结点数据结构 */
typedef struct AVL
{
KEY_TYPE key;
int height;
struct AVL *lchild;
struct AVL *rchild;
} AVL;
int getHeight(AVL* node); //获取结点深度
AVL* LL_Rotate(AVL* k2); //LL类型
AVL* RR_Rotate(AVL* k2); //RR类型
/*
Return which the root pointer should point to
*/
AVL* LR_Rotate(AVL* k3); //LR类型
AVL* RL_Rotate(AVL* k3); //RL类型
AVL* insertNode(AVL* root, KEY_TYPE key); //插入结点
AVL* deleteNode(AVL* root, KEY_TYPE key); //删除结点
void print_tree(AVL *node); //打印AVL树结点
#endif /* AVL_H_ */
//============================================================================
// Name : AVL.cpp
// Author : @CodingGeek
// Version : V1.0
// Copyright :
// Description : AVL平衡搜索二叉树C代码实现
//============================================================================
#include "AVL.h"
#include <stdio.h>
#include <stdlib.h>
AVL* makeNode(KEY_TYPE key)
{
AVL* p_avl = (AVL*)malloc(sizeof(AVL));
p_avl->key = key;
p_avl->lchild = NULL;
p_avl->rchild = NULL;
p_avl->height = 1;
return p_avl;
}
int getHeight(AVL* node)
{
return (node == NULL)? 0: node->height;
}
inline int max(int a, int b)
{
return a > b ? a : b;
}
/* LL(Y rotates to the right):
k2 k1
/ \ / \
k1 Z ==> X k2
/ \ / \
X Y Y Z
*/
AVL* LL_Rotate(AVL* k2)
{
AVL* k1 = k2->lchild;
k2->lchild = k1->rchild;
k1->rchild = k2;
k2->height = max(getHeight(k2->lchild), getHeight(k2->rchild)) + 1;
k1->height = max(getHeight(k1->lchild), k2->height) + 1;
return k1;
}
/* RR(Y rotates to the left):
k2 k1
/ \ / \
X k1 ==> k2 Z
/ \ / \
Y Z X Y
*/
AVL* RR_Rotate(AVL* k2)
{
AVL* k1 = k2->rchild;
k2->rchild = k1->lchild;
k1->lchild = k2;
k2->height = max(getHeight(k2->lchild), getHeight(k2->rchild)) + 1;
k1->height = max(getHeight(k1->rchild), k2->height) + 1;
return k1;
}
/* LR(B rotates to the left, then C rotates to the right):
k3 k3 k2
/ \ / \ / \
k1 D k2 D k1 k3
/ \ ==> / \ ==> / \ / \
A k2 k1 C A B C D
/ \ / \
B C A B
*/
AVL* LR_Rotate(AVL* k3)
{
k3->lchild = RR_Rotate(k3->lchild);
return LL_Rotate(k3);
}
/* RL(D rotates to the right, then C rotates to the left):
k3 k3 k2
/ \ / \ / \
A k1 A k2 k3 k1
/ \ ==> / \ ==> / \ / \
k2 B C k1 A C D B
/ \ / \
C D D B
*/
AVL* RL_Rotate(AVL* k3)
{
k3->rchild = LL_Rotate(k3->rchild);
return RR_Rotate(k3);
}
AVL* insertNode(AVL* root, KEY_TYPE key)
{
if (root == NULL)
{
return makeNode(key);
}
if (root->key == key)
{
return root;
}
else if (key < root->key)
{
root->lchild = insertNode(root->lchild, key);
}
else //key >= root->key
{
root->rchild = insertNode(root->rchild, key);
}
root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
if (getHeight(root->lchild) - getHeight(root->rchild) == 2)
{
if(key < root->lchild->key)
{
root = LL_Rotate(root);
}
else
{
root = LR_Rotate(root);
}
}
else if (getHeight(root->rchild) - getHeight(root->lchild) == 2)
{
if(key > root->rchild->key)
{
root = RR_Rotate(root);
}
else
{
root = RL_Rotate(root);
}
}
return root;
}
AVL* deleteNode(AVL* root, KEY_TYPE key)
{
if (root == NULL)
{
return NULL;
}
if (key == root->key)
{
if(root->rchild == NULL)
{
AVL* temp = root;
root = root->lchild;
free(temp);
return root;
}
else
{
AVL* temp = root->rchild;
while(temp->lchild)
{
temp = temp->lchild;
}
root->key = temp->key;
root->rchild = deleteNode(root->rchild, temp->key);
}
}
else if (key < root->key)
{
root->lchild = deleteNode(root->lchild, key);
}
else
{
root->rchild = deleteNode(root->rchild, key);
}
root->height = max(getHeight(root->lchild), getHeight(root->rchild)) + 1;
if (getHeight(root->rchild) - getHeight(root->lchild) == 2)
{
if (getHeight(root->rchild->rchild) >= getHeight(root->rchild->lchild))
{
root = RR_Rotate(root);
}
else
{
root = RL_Rotate(root);
}
}
else if (getHeight(root->lchild) - getHeight(root->rchild) == 2)
{
if (getHeight(root->lchild->lchild) >= getHeight(root->lchild->rchild))
{
root = LL_Rotate(root);
}
else
{
root = LR_Rotate(root);
}
}
return root;
}
void print_tree_indent(AVL *node, int indent)
{
for (int ix = 0; ix < indent; ix++)
{
printf(" ");
}
if (node == NULL)
{
printf("Empty Child\n");
}
else
{
printf("Node: %d; Height: %d\n", node->key, node->height);
print_tree_indent(node->lchild, indent + 4);
print_tree_indent(node->rchild, indent + 4);
}
}
void print_tree(AVL *node)
{
print_tree_indent(node, 0);
}
//============================================================================
// Name : AVLTree.cpp
// Author : @CodingGeek
// Version :
// Copyright : V1.0
// Description : AVL平衡搜索二叉树代码实现
//============================================================================
#include <stdio.h>
#include "AVL.h"
int main(int argc, char* argv[])
{
srand(time(NULL));
const int num = 20;
int *pArr = (int*)malloc(sizeof(int) * num);
for (int i = 0; i < num; i++)
{
pArr[i] = rand() % 100;
printf("%d ", pArr[i]);
}
printf("\n=======================\n");
AVL *root = NULL;
for (int i = 0; i < num; i++)
{
root = insertNode(root, pArr[i]);
}
printf("AVL Tree:\n");
print_tree(root);
int input = 0x0;
do
{
printf("\nPlease input the value you want to delete:\n");
scanf("%d",&input);
root = deleteNode(root, input);
printf("\nAfter delete %d:\n",input);
print_tree(root);
}while (getHeight(root));
printf("\n");
return 0;
}