linux 自平衡AVL树
作者:互联网
简介
仔细观察BST会发现,虽然它有良好的“搜索”特性,也就是可以利用其节点之前的大小关系,很容易地从根节点开始往下走找到我们所要的节点,但它无法保证这种搜索所需要的时间长短,因为建立BST时节点的随机性可能会导致它极其“不平衡”。
如上图所示是一棵二叉树,显然左轻右重,事实上这棵树已经退化成了一条链表,在这棵树中搜索某一个节点的时间复杂度和链表是一样的。
这种左轻右重或者左重右轻的长短腿的情形,就是所谓的不平衡;一棵树不平衡,那么他的搜索性能将会受到影响。具体来讲,当树保持平衡时,其搜索时间复杂度是O(log2n);当树退化成链表时,其搜索时间复杂度是O(n),其他情况下树的平均搜索时间复杂度就介于这两者之间。现在的目标就是要升级我们的BST,使之带有自平衡的特性,当它发现自己的左腿长或右腿长是,会及时调整,保持平衡。
要达到此目的,首先需要量化所谓的“平衡”,其严格数学定义是:在一棵树中,如果其任意一个节点的左右子树的高度差绝对值小于或等于1,那么它就是平衡的。
下面是AVL树的算法实现,包括了节点的创建、插入、删除、旋转、算法。
算法实现
head4tree.h
//////////////////////////////////////////////////////////////////
// Description: 本文件为二叉树核心头文件。
// 任何使用本二叉树结构算法的程序,在包含本头文件之前
// 都需要将如下宏定义成二叉树节点需要表达的数据类型:
//
// TREE_NODE_DATATYPE
//
// 否则二叉树的节点数据类型一律默认为 int
//////////////////////////////////////////////////////////////////
#ifndef _HEAD4TREE_H_
#define _HEAD4TREE_H_
/*
* Any application applying this linked-tree data structure should
* define the macro "TREE_NODE_DATATYPE" before include this head
* file, otherwise, the macro will be defined to 'int' as follow.
*
*/
#ifndef TREE_NODE_DATATYPE
#define TREE_NODE_DATATYPE int
#endif
#include "commonheader.h"
#define MAX(a, b) ({ \
typeof(a) _a = a; \
typeof(b) _b = b; \
(void)(&_a == &_b);\
_a > _b? _a : _b; \
})
typedef TREE_NODE_DATATYPE tn_datatype;
typedef struct _tree_node
{
tn_datatype data;
struct _tree_node *lchild;
struct _tree_node *rchild;
#ifdef AVL
int height;
#endif
}treenode, *linktree;
void pre_travel(linktree, void (*handler)(linktree));
void mid_travel(linktree, void (*handler)(linktree));
void post_travel(linktree, void (*handler)(linktree));
void level_travel(linktree, void (*handler)(linktree));
linktree bst_insert(linktree root, linktree new);
linktree bst_remove(linktree root, tn_datatype data);
linktree bst_find(linktree root, tn_datatype data);
#ifdef AVL
linktree avl_insert(linktree root, linktree new);
linktree avl_remove(linktree root, tn_datatype data);
linktree avl_rotate_left (linktree root);
linktree avl_rotate_right(linktree root);
linktree avl_rotate_leftright(linktree root);
linktree avl_rotate_rightleft(linktree root);
static int height(linktree root)
{
return root==NULL ? 0 : root->height;
}
#endif
static linktree new_node(tn_datatype data)
{
linktree new = malloc(sizeof(treenode));
if(new != NULL)
{
new->data = data;
new->lchild = NULL;
new->rchild = NULL;
#ifdef AVL
new->height = 1;
#endif
}
return new;
}
#endif
avl.c
////////////////////////////////////////////////////////////////////
// Description: AVL算法实现代码
////////////////////////////////////////////////////////////////////
#include "head4tree.h"
#include "drawtree.h"
linktree avl_rotate_right(linktree root)
{
linktree tmp = root->lchild;
root->lchild = tmp->rchild;
tmp->rchild = root;
root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
tmp->height = MAX(height(tmp->lchild), root->height) + 1;
return tmp;
}
linktree avl_rotate_left(linktree root)
{
linktree tmp = root->rchild;
root->rchild = tmp->lchild;
tmp->lchild = root;
root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
tmp->height = MAX(root->height, height(tmp->rchild)) + 1;
return tmp;
}
linktree avl_rotate_leftright(linktree root)
{
root->lchild = avl_rotate_left(root->lchild);
return avl_rotate_right(root);
}
linktree avl_rotate_rightleft(linktree root)
{
root->rchild = avl_rotate_right(root->rchild);
return avl_rotate_left(root);
}
linktree avl_insert(linktree root, linktree new)
{
if(root == NULL)
return new;
if(new->data < root->data)
root->lchild = avl_insert(root->lchild, new);
else if(new->data > root->data)
root->rchild = avl_insert(root->rchild, new);
else
{
printf("%d is already exist.\n", new->data);
}
if(height(root->lchild) - height(root->rchild) == 2)
{
if(new->data < root->lchild->data)
root = avl_rotate_right(root);
else if(new->data > root->lchild->data)
root = avl_rotate_leftright(root);
}
else if(height(root->rchild) - height(root->lchild) == 2)
{
if(new->data > root->rchild->data)
root = avl_rotate_left(root);
else if(new->data < root->rchild->data)
root = avl_rotate_rightleft(root);
}
root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
return root;
}
linktree avl_remove(linktree root, tn_datatype data)
{
if(root == NULL)
return NULL;
if(data < root->data)
root->lchild = avl_remove(root->lchild, data);
else if(data > root->data)
root->rchild = avl_remove(root->rchild, data);
else
{
linktree p;
if(root->lchild != NULL)
{
for(p=root->lchild; p->rchild!=NULL; p=p->rchild){;}
root->data = p->data;
root->lchild = avl_remove(root->lchild, p->data);
}
else if(root->rchild != NULL)
{
for(p=root->rchild; p->lchild!=NULL; p=p->lchild){;}
root->data = p->data;
root->rchild = avl_remove(root->rchild, p->data);
}
else
{
free(root);
return NULL;
}
}
if(height(root->lchild) - height(root->rchild) == 2)
{
if(height(root->lchild->rchild)-height(root->lchild->rchild) == 1)
root = avl_rotate_leftright(root);
else
root = avl_rotate_right(root);
}
else if(height(root->rchild) - height(root->lchild) == 2)
{
if(height(root->rchild->lchild)-height(root->rchild->rchild) == 1)
root = avl_rotate_rightleft(root);
else
root = avl_rotate_left(root);
}
root->height = MAX(height(root->lchild), height(root->rchild)) + 1;
return root;
}
int main(void)
{
linktree root = NULL;
printf("输入大于0的数插入节点\n");
printf("输入小于0的数删除节点\n");
printf("输入0退出程序\n");
int n;
while(1)
{
scanf("%d", &n);
if(n > 0)
{
linktree new = new_node(n);
root = avl_insert(root, new);
}
else if(n < 0)
{
root = avl_remove(root, -n);
}
else
break;
draw(root);
system("firefox -new-tab *.html &");
}
system("rm *.html");
return 0;
}
示例
直接使用上面的文件,上述的main函数实现了以下功能:
1、输入一个正整数,则插入该节点
2、输入一个负整数,则删除其绝对值对应的节点
3、输入0,退出程序
4、退出程序前在网页上画出该二叉树
运行效果如下:
zzc@zzc-virtual-machine:~/share/example/数据结构$ ./avl
输入大于0的数插入节点
输入小于0的数删除节点
输入0退出程序
1
2
3
4
54
5
8
6
2
2 is already exist.
8
8 is already exist.
9
10
0
在网页上显示该二叉树:
注意事项
1、上述示例程序中使用了draw函数,用于在网页上画出二叉树。
2、上述示例用到的源代码(一些头文件和c文件)放在以下博文中:
https://blog.csdn.net/gogo0707/article/details/124855232
3、AVL树也是BST树,所以查找某一个节点时直接使用BST查找算法即可
总结
本文介绍了AVL树的基本概念,进行了算法的实现,并通过示例程序演示了二叉树如何实现自平衡。
后续我有时间再慢慢补充有关AVL树的知识点和一些可能遇到的问题。
标签:linktree,data,height,AVL,avl,linux,平衡,root,rchild 来源: https://www.cnblogs.com/lxyjrx/p/16290968.html