请输入您要查询的百科知识:

 

词条 Approved Vendor List
释义

AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。

AVL的含义

1.品质管理系统中,AVL是Approved Vendor List,及一般意义上的合格供应商目录。

2.在计算机科学中,AVL树是最先发明的自平衡二叉查找树。在AVL树中任何节点的两个儿子子树的高度最大差别为一,所以它也被称为高度平衡树。查找、插入和删除在平均和最坏情况下都是O(log n)。增加和删除可能需要通过一次或多次树旋转来重新平衡这个树。AVL树得名于它的发明者 G.M. Adelson-Velsky 和 E.M. Landis,他们在 1962 年的论文 "An algorithm for the organization of information" 中发表了它。

AVL 节点数计算

高度为 h 的 AVL 树, 节点数 N 最多2 − 1; 最少 ( 其中 )。

最少节点数 n 如以费伯纳西数列可以用数学归纳法证明:

Nh = Fh + 2 - 1 (Fh + 2是 Fibonacci polynomial)。

即:

N0 = 0 (表示 AVL Tree 高度为0的节点总数)

N1 = 1 (表示 AVL Tree 高度为1的节点总数)

N2 = 2 (表示 AVL Tree 高度为2的节点总数)

Nh = Nh − 1 + Nh − 2 + 1 (表示 AVL Tree 高度为h的节点总数)

换句话说,当节点数为 N 时,高度 h 最多为 。

节点的平衡因子是它的右子树的高度减去它的左子树的高度。带有平衡因子 1、0 或 -1 的节点被认为是平衡的。带有平衡因子 -2 或 2 的节点被认为是不平衡的,并需要重新平衡这个树。平衡因子可以直接存储在每个节点中,或从可能存储在节点中的子树高度计算出来。

AVL 操作

AVL树的基本操作一般涉及运做同在不平衡的二叉查找树所运做的同样的算法。但是要进行预先或随后做一次或多次所谓的"AVL 旋转"。

假设由于在二叉排序树上插入结点而失去平衡的最小子树根结点的指针为a(即a是离插入点最近,且平衡因子绝对值超过1的祖先结点),则失去平衡后进行进行的规律可归纳为下列四种情况:

单向右旋平衡处理RR:由于在*a的左子树根结点的左子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行一次右旋转操作;

单向左旋平衡处理LL:由于在*a的右子树根结点的右子树上插入结点,*a的平衡因子由-1变为-2,致使以*a为根的子树失去平衡,则需进行一次左旋转操作;

双向旋转(先左后右)平衡处理LR:由于在*a的左子树根结点的右子树上插入结点,*a的平衡因子由1增至2,致使以*a为根的子树失去平衡,则需进行两次旋转(先左旋后右旋)操作。

双向旋转(先右后左)平衡处理RL:由于在*a的右子树根结点的左子树上插入结点,*a的平衡因子由-1变为-2,致使以*a为根的子树失去平衡,则需进行两次旋转(先右旋后左旋)操作。

插入

向AVL树插入可以通过如同它是未平衡的二叉查找树一样把给定的值插入树中,接着自底向上向根节点折回,于在插入期间成为不平衡的所有节点上进行旋转来完成。因为折回到根节点的路途上最多有 1.5 乘 log n 个节点,而每次 AVL 旋转都耗费恒定的时间,插入处理在整体上耗费 O(log n) 时间。

在平衡的的二叉排序树Balanced BST上插入一个新的数据元素e的递归算法可描述如下:

若BBST为空树,则插入一个数据元素为e的新结点作为BBST的根结点,树的深度增1;

若e的关键字和BBST的根结点的关键字相等,则不进行;

若e的关键字小于BBST的根结点的关键字,而且在BBST的左子树中不存在和e有相同关键字的结点,则将e插入在BBST的左子树上,并且当插入之后的左子树深度增加(+1)时,分别就下列不同情况处理之:

BBST的根结点的平衡因子为-1(右子树的深度大于左子树的深度,则将根结点的平衡因子更改为0,BBST的深度不变;

BBST的根结点的平衡因子为0(左、右子树的深度相等):则将根结点的平衡因子更改为1,BBST的深度增1;

BBST的根结点的平衡因子为1(左子树的深度大于右子树的深度):则若BBST的左子树根结点的平衡因子为1:则需进行单向右旋平衡处理,并且在右旋处理之后,将根结点和其右子树根结点的平衡因子更改为0,树的深度不变;

若e的关键字大于BBST的根结点的关键字,而且在BBST的右子树中不存在和e有相同关键字的结点,则将e插入在BBST的右子树上,并且当插入之后的右子树深度增加(+1)时,分别就不同情况处理之。

删除

从AVL树中删除可以通过把要删除的节点向下旋转成一个叶子节点,接着直接剪除这个叶子节点来完成。因为在旋转成叶子节点期间最多有 log n个节点被旋转,而每次 AVL 旋转耗费恒定的时间,删除处理在整体上耗费 O(log n) 时间。

查找

在AVL树中查找同在一般BST完全一样的进行,所以耗费 O(log n) 时间,因为AVL树总是保持平衡的。不需要特殊的准备,树的结构不会由于查询而改变。(这是与伸展树查找相对立的,它会因为查找而变更树结构。)

参考实现

给出一个操作AVLTREE的完整程序 大部分由Peter Brass编写

#include <iostream.h>

#include <math.h>

#include <stdlib.h>

//建立一个整数类型

typedef struct obj_n_t

{

int obj_key;

} obj_node_t;

//建立树结点的基本机构

typedef struct tree_n_t

{

int key;

struct tree_n_t *left,*right;

int height;

} tree_node_t;

//建立堆栈

#define MAXSIZE 512

tree_node_t *stack[MAXSIZE]; //warning!the tree can contain 256 leaves at most!

int i=0; //堆栈计数器

//堆栈清空

void stack_clear()

{

while(i!=0)

{

stack[i-1]=NULL;

i--;

}

}

//堆栈为空

int stack_empty()

{

return(i==0);

}

//入栈函数

int push(tree_node_t *node)

{

if(i<MAXSIZE)

{

stack[i++]=node;

return(0);

}

else

return(-1);

}

//出栈函数

tree_node_t *pop()

{

if(i>0)

return(stack[--i]);

else

return(0);

}

//建立get_node函数,用于动态分配内存空间

tree_node_t *get_node()

{

tree_node_t *tmp;

tmp=(tree_node_t *)malloc(sizeof(tree_node_t));

return(tmp);

}

//建立return_node函数,用于释放内存

void return_node(tree_node_t *free_node)

随便看

 

百科全书收录4421916条中文百科知识,基本涵盖了大多数领域的百科知识,是一部内容开放、自由的电子版百科全书。

 

Copyright © 2004-2023 Cnenc.net All Rights Reserved
更新时间:2025/3/14 19:11:51