C语言 AVL平衡二叉查找树 插入/删除/遍历/查找
AVl树:平衡二叉查找树,树中任何节点的两个子树的高度最大差别为1。如下图所示
AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。
如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。
1. AVL树的结构
typedef struct AVLTreeNode{
Type key; // 关键字(键值)
int height; //当前节点高度
struct AVLTreeNode *left; // 左孩子
struct AVLTreeNode *right; // 右孩子
}Node, *AVLTree;
2 AVL树的旋转操作
2.1 LL旋转
LL旋转:左单旋。也称为"左左"。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。如图所示:
RR旋转:右单旋。也称为"右"。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。如图所示:
RL旋转:右双旋转。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,导致"根的右子树的高度"比"根的左子树的高度"大2,导致AVL树失去了平衡。如图所示:
LR旋转:左双旋转。根节点的左子树的右子树还有非空子节点,导致"根的左子树的高度"比"根的右子树的高度"大2,导致AVL树失去了平衡。如图所示
3 代码实现:
先看avltree.h文件
#ifndef _AVL_TREE_H_
#define _AVL_TREE_H_
//AVL: 平衡二叉树
typedef int Type;
typedef struct AVLTreeNode{
Type key; // 关键字(键值)
int height; //当前节点高度
struct AVLTreeNode *left; // 左孩子
struct AVLTreeNode *right; // 右孩子
}Node, *AVLTree;
// 获取AVL树的高度
int avltree_height(AVLTree tree);
// 前序遍历"AVL树"
void preorder_avltree(AVLTree tree);
// 中序遍历"AVL树"
void inorder_avltree(AVLTree tree);
// 后序遍历"AVL树"
void postorder_avltree(AVLTree tree);
void print_avltree(AVLTree tree, Type key, int direction);
// (递归实现)查找"AVL树tree"中键值为key的节点
Node* avltree_search(AVLTree tree, Type key);
// (非递归实现)查找"AVL树tree"中键值为key的节点
Node* iterative_avltree_search(AVLTree tree, Type key);
// 查找最小结点:返回tree为根结点的AVL树的最小结点。
Node* avltree_minimum(AVLTree tree);
// 查找最大结点:返回tree为根结点的AVL树的最大结点。
Node* avltree_maximum(AVLTree tree);
// 将结点插入到AVL树中,返回根节点
Node* avltree_insert(AVLTree tree, Type key);
// 删除结点(key是节点值),返回根节点
Node* avltree_delete(AVLTree tree, Type key);
// 销毁AVL树
void destroy_avltree(AVLTree tree);
#endif
在看avltree.cpp文件
#include <stdio.h>
#include <stdlib.h>
#include "avltree.h"
#define HEIGHT(p) ( (p==NULL) ? 0: (((Node *)(p))->height) )
#define MAX(a, b) ( (a) > (b) ? (a) : (b) )
// 获取AVL树的高度
int avltree_height(AVLTree tree)
{
return HEIGHT(tree);
}
// 前序遍历"AVL树" 先读取根节点,然后读取左子树,在读取右子树
void preorder_avltree(AVLTree tree)
{
if (tree != NULL)
{
printf(" %d ", tree->key);
preorder_avltree(tree->left);
preorder_avltree(tree->right);
}
}
// 中序遍历"AVL树" 先读取左子树,然后读取根节点,在读取右子树
void inorder_avltree(AVLTree tree)
{
if (tree != NULL)
{
inorder_avltree(tree->left);
printf(" %d ", tree->key);
inorder_avltree(tree->right);
}
}
// 后序遍历"AVL树" 先读取左子树,然后读取右子树,在读取根节点
void postorder_avltree(AVLTree tree)
{
if (tree != NULL)
{
postorder_avltree(tree->left);
postorder_avltree(tree->right);
printf(" %d ", tree->key);
}
}
/*
* 打印"AVL树"
* tree -- AVL树的节点
* key -- 节点的键值
* direction -- 0,表示该节点是根节点;
* -1,表示该节点是它的父结点的左孩子;
* 1,表示该节点是它的父结点的右孩子。
*/
void print_avltree(AVLTree tree, Type key, int direction)
{
if (tree != NULL)
{
if (direction == 0)
{
printf("%2d is root\n", tree->key, key);
}
else
{
printf("%2d is %2d's %6s child\n", tree->key, key, direction==1?"right" : "left");
}
print_avltree(tree->left, tree->key, -1);
print_avltree(tree->right, tree->key, 1);
}
}
// (递归实现)查找"AVL树x"中键值为key的节点
Node* avltree_search(AVLTree tree, Type key)
{
if (tree==NULL || tree->key == key)
{
return tree;
}
if (tree->key > key) //小于根节点
{
avltree_search(tree->left, key);
}
else
{
avltree_search(tree->right, key);
}
}
// (非递归实现)查找"AVL树x"中键值为key的节点
Node* iterative_avltree_search(AVLTree tree, Type key)
{
while ((tree!=NULL) && (tree->key != key))
{
if (tree->key > key)
{
tree = tree->left;
}
else
{
tree = tree->right;
}
}
return tree;
}
// 查找最小结点:返回tree为根结点的AVL树的最小结点。avl是有序树,所以查找左子树叶节点即可
Node* avltree_minimum(AVLTree tree)
{
if (tree == NULL)
{
return NULL;
}
while (tree->left != NULL)
{
tree = tree->left;
}
return tree;
}
// 查找最大结点:返回tree为根结点的AVL树的最大结点。与最小节点相反查找右子树叶节点
Node* avltree_maximum(AVLTree tree)
{
if (tree == NULL)
{
return NULL;
}
while (tree->right != NULL)
{
tree = tree->right;
}
return tree;
}
/*创建节点
*left 新节点的左叶节点
*right 新节点的右叶节点
*/
static Node* Create_AVLtree_Node(Type key, Node* left, Node* right)
{
Node* pNode = (Node*)malloc(sizeof(Node));
if (pNode == NULL)
{
return NULL;
}
pNode->key = key;
pNode->height = 0;
pNode->left = left;
pNode->right = right;
return pNode;
}
/*
* LL : 左单旋转
* 返回值:旋转后的根节点
*/
static Node* left_left_rotation(AVLTree k2)
{
AVLTree k1;
k1 = k2->left;
k2->left = k1->right;
k1->right = k2;
k2->height = MAX(HEIGHT(k2->left), HEIGHT(k2->right))+1;
k1->height = MAX(HEIGHT(k1->left), k2->height)+1;
return k1;
}
/*
* RR : 右单旋转
* 返回值:旋转后的根节点
*/
static Node* right_right_rotation(AVLTree k1)
{
AVLTree k2;
k2 = k1->right;
k1->right = k2->left;
k2->left = k1;
k1->height = MAX(HEIGHT(k1->left), HEIGHT(k1->right))+1;
k2->height = MAX(HEIGHT(k2->right), k1->height)+1;
return k2;
}
/*
* LR : 左双旋转
* 返回值:旋转后的根节点
*/
static Node* left_right_rotation(AVLTree k3)
{
k3->left = right_right_rotation(k3->left);
return left_left_rotation(k3);
}
/*
* RL : 右双旋转
* 返回值:旋转后的根节点
*/
static Node* right_left_rotation(AVLTree k1)
{
k1->right = left_left_rotation(k1->right);
return right_right_rotation(k1);
}
/* 将结点插入到AVL树中,返回根节点
* tree AVL树根节点
* key 插入的节点的键值
* 返回值:根节点
*/
Node* avltree_insert(AVLTree tree, Type key)
{
if (tree == NULL)
{
tree = Create_AVLtree_Node(key, NULL, NULL);
if (tree == NULL)
{
printf("create Node fail\n");
return NULL;
}
}
else if (key > tree->key) //大于根节点,插入右子树
{
tree->right = avltree_insert(tree->right, key);
if (HEIGHT(tree->right) - HEIGHT(tree->left) == 2)
{
if (key > tree->right->key)
{
tree = right_right_rotation(tree);
}
else
{
tree = right_left_rotation(tree);
}
}
}
else if(key < tree->key)
{
tree->left = avltree_insert(tree->left, key);
if (HEIGHT(tree->left) - HEIGHT(tree->right) == 2)
{
if (key < tree->left->key)
{
tree = left_left_rotation(tree);
}
else
{
tree = left_right_rotation(tree);
}
}
}
else
{
printf("don't allow insert the same value\n");
}
tree->height = MAX( HEIGHT(tree->left), HEIGHT(tree->right)) + 1;
return tree;
}
/*
* tree AVL树根节点
* key 要删除的节点的键值
* 返回值:新根节点
*/
static Node* delteNode(AVLTree tree, Node* pdel)
{
if (tree == NULL || pdel == NULL)
{
return NULL;
}
if (pdel->key < tree->key) //删除节点在左子树
{
tree->left = delteNode(tree->left, pdel);
if (HEIGHT(tree->right) - HEIGHT(tree->left) == 2)
{
Node* pRTemp = tree->right;
//调整平衡
if (HEIGHT(pRTemp->left) > HEIGHT(pRTemp->right))
{
tree = right_left_rotation(pRTemp);
}
else
{
tree = right_right_rotation(pRTemp);
}
}
}
else if(pdel->key > tree->key) //删除节点在右子树
{
tree->right = delteNode(tree->right, pdel);
if (HEIGHT(tree->left) - HEIGHT(tree->right) == 2)
{
Node* pLTemp = tree->left;
if (HEIGHT(pLTemp->right) > HEIGHT(pLTemp->left))
{
tree = left_right_rotation(pLTemp);
}
else
{
tree = left_left_rotation(pLTemp);
}
}
}
else //当前根节点就是要删除的节点
{
//节点左右孩子为空
if ((tree->left) && (tree->right))
{
if (HEIGHT(tree->left) > HEIGHT(tree->right))
{
//左子树比右子树搞,找出tree的左子树最大节点,将该最大节点的值付给tree,然后该最大节点
Node* maxnode = avltree_maximum(tree->left);
tree->key = maxnode->key;
tree->left = delteNode(tree->left, maxnode);
}
else
{
//如果左子树不比右子树高,找出tree右子树中的最小节点,将最小节点的值赋给tree,删除该最小节点
Node* minnode = avltree_minimum(tree->right);
tree->key = minnode->key;
tree->right = delteNode(tree->right, minnode);
}
}
else
{
Node* pTemp = tree;
tree = tree->left ? tree->left : tree->right;
free(pTemp);
}
}
return tree;
}
// 删除结点(key是节点值),返回根节点
Node* avltree_delete(AVLTree tree, Type key)
{
Node* pTmp;
if ((pTmp = avltree_search(tree, key)) != NULL)
{
tree = delteNode(tree, pTmp);
}
return tree;
}
// 销毁AVL树
void destroy_avltree(AVLTree tree)
{
if (tree == NULL)
{
return;
}
if (tree->left != NULL)
{
destroy_avltree(tree->left);
}
if (tree->right != NULL)
{
destroy_avltree(tree->right);
}
free(tree);
}
在看测试代码main.cpp
#include <stdio.h>
#include <iostream>
#include "avltree.h"
static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
#define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) )
int main()
{
int i,ilen;
AVLTree root=NULL;
printf(" 高度: %d\n", avltree_height(root));
printf(" 依次添加: ");
ilen = TBL_SIZE(arr);
for(i=0; i<ilen; i++)
{
printf("%d ", arr[i]);
root = avltree_insert(root, arr[i]);
}
printf("\n 前序遍历: ");
preorder_avltree(root);
printf("\n 中序遍历: ");
inorder_avltree(root);
printf("\n 后序遍历: ");
postorder_avltree(root);
printf("\n");
printf(" 高度: %d\n", avltree_height(root));
printf(" 最小值: %d\n", avltree_minimum(root)->key);
printf(" 最大值: %d\n", avltree_maximum(root)->key);
printf(" 树的详细信息: \n");
print_avltree(root, root->key, 0);
i = 8;
printf("\n 删除根节点: %d", i);
root = avltree_delete(root, i);
printf("\n 高度: %d", avltree_height(root));
printf("\n 中序遍历: ");
inorder_avltree(root);
printf("\n 树的详细信息: \n");
print_avltree(root, root->key, 0);
// 销毁二叉树
destroy_avltree(root);
system("pause");
return 0;
}
最后看测试结果:
4 图解操作
4.1 插入操作
这就是以上代码插入的结果示意图。
前序遍历结果:7 4 2 1 3 6 5 13 11 9 8 10 12 15 14 16
中序遍历结果:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
后序遍历结果:1 3 2 5 6 4 8 10 9 12 11 14 16 15 13 7
树的深度为 5
最大值为 16
最下值为 1
4.2 删除操作
删除节点 8
中序遍历结果 :1 2 3 4 5 6 7 9 10 11 12 13 14 15 16
以上就是所有的代码和结果,如果程序中有不严谨的地方,请在下方留言。