您的位置:首页 > 编程语言 > C语言/C++

AVL树原理及实现(C语言实现以及Java语言实现)

2016-11-17 21:47 741 查看
欢迎探讨,如有错误敬请指正

如需转载,请注明出处http://www.cnblogs.com/nullzx/

1. AVL定义

AVL树是一种改进版的搜索二叉树。对于一般的搜索二叉树而言,如果数据恰好是按照从小到大的顺序或者从大到小的顺序插入的,那么搜索二叉树就对退化成链表,这个时候查找,插入和删除的时间都会上升到O(n),而这对于海量数据而言,是我们无法忍受的。即使是一颗由完全随机的数据构造成的搜索二叉树,从统计角度去分析,在进行若甘次的插入和删除操作,这个搜索二叉树的高度也不能令人满意。这个时候大家就希望能有一种二叉树解决上述问题。这个时候就出现平衡搜索二叉树,它的基本原理就是在插入和删除的时候,根据情况进行调整,以降低二叉树的高度。平衡搜索二叉树典型代表就是AVL树和红黑树。

AVL树:任何一个节点的左子支高度与右子支高度之差的绝对值不超过1。需要我们注意的是,AVL树定义不是说从根节点到叶子节点的最短距离比最长短距离大1。





上图就是一颗AVL树,从根节点到叶子节点的最短距离是5,最长距离是9。

2. 旋转的定义

因为每种书中对旋转的定义不一致,所以我们有必要在这里特此说明一下

以某一个节点为轴,它的左子枝顺时针旋转,作为新子树的根,我们称之为顺时针旋转(clockwise)或者右旋转。

同理,以某一个节点为轴,它的右子枝逆针旋转,作为新子树的根,我们称之为逆时针旋转(anticlockwise)或者左旋转。

3. AVL插入操作

AVL树的插入操作首先会按照普通搜索二叉树的插入操作进行,当插入一个数据后,我们会沿着插入数据时所经过的的节点回溯,回溯的过程中会判回溯路径中的每个节点的左子支高度与右子支高度之差的绝对值是否超过1,如果超过1我们就进行调整,调整的目的是使得该节点满足AVL树的定义。调整的情况可以分为以下四旋转操作,旋转操作可以降低树的高度,同时不改变搜索二叉树的性质(即任何一个节点左子支中的全部节点小于该节点,右子支的全部节点大于该节点)。

3.1 情况1

节点X左子支比右子支高度大2,且插入的节点位于X的左孩子节点XL的左子支上



3.2 情况2

节点X右子支比左子支高度大2,且插入的节点位于节点X右孩子节点XR的右子支上





3.3 情况3

节点X左子支比右子支高度大2,且插入的节点位于节点X左孩子节点XL的右子支上



3.4 情况4

节点X左子支比右子支高度大2,且插入的节点位于节点X左孩子节点XL的右子支上



4. AVL删除操作

AVL树的删除操作和插入操作一样,首先会按照普通搜索二叉树的删除操作进行,当删除一个数据后,和插入操作一样,我们通常采取的策略是沿着删除数据时所经过的的节点回溯,回溯的过程中会判断该节点的左子支高度与右子支高度之差的绝对值是否超过1(或者说大2),如果超过1,我们就进行调整,调整的目的是使得该节点满足AVL树的定义。调整的情况可以分为四种,和插入过程完全一样,这里不在赘述。

5. C语言实现

5.1节点定义

AVLtree.h文件中的内容

#ifndef __AVLTREE_H__
#define __AVLTREE_H__
typedef struct Node{
int height; //该节点作为子树时的高度
int data;   //表示每个节点存贮的数据
Node* left;
Node* right;
}Node, *AVLtree;
//AVLtree  表示Node*
//AVLtree* 就表示Node**

int Insert(AVLtree* T, int D);
int Delete(AVLtree* T, int D);
int Find(AVLtree T, int x);
int Destroy(AVLtree* T);

//下面两个遍历函数主要用于测试
void InOredrTraverse(AVLtree T);
void PreOredrTraverse(AVLtree T);
#endif


5.2代码实现

AVLtree.cpp文件中的内容

#include"AVLtree.h"
#include<stdlib.h>
#include<stdio.h>

#define MAX(x1,x2) ((x1) > (x2) ? (x1) : (x2))

//一下函数用于辅助实现插入删除操作,作用域于仅限于AVLtree.cpp
static void PostOrderTraverse(AVLtree T);
static int GetHeight(AVLtree T);
static void LeftRotate(AVLtree* T);
static void RightRotate(AVLtree* T);
static int FindMin(AVLtree T);

//返回值用于表示插入是否成功,-1表示失败(说明树中已包含该数据),0表示成功
int Insert(AVLtree* T,int D){
//参数检查
if(T == NULL){
return -1;
}

//找到插入的位置
if(*T == NULL){
*T = (Node*)malloc(sizeof(Node));
(*T)->data = D;
(*T)->height = 1;
(*T)->left = NULL;
(*T)->right = NULL;
return 0;
}else{
//树中已存在该数据
if(D == (*T)->data){
return -1;
}else
if(D > (*T)->data){//在右子树中插入
if(Insert(&(*T)->right,D) == -1){
return -1;
}

//插入后,当回溯到该节点进行检查,如果不满足平衡条件,则调整
//因为是在右子支中插入,如果高度只差等于2,只可能是右子支比左子支高
if(GetHeight((*T)->right) - GetHeight((*T)->left) == 2){
if(D > (*T)->right->data){
LeftRotate(T);//对应情况2,左旋
}else{//对应情况4,先右旋再左旋
RightRotate(&(*T)->right);
LeftRotate(T);
}
}
}else
if(D < (*T)->data){//在左子树中插入
if(Insert(&(*T)->left,D)){
return -1;
}

if(GetHeight((*T)->left) - GetHeight((*T)->right) == 2){
if(D < (*T)->left->data){
RightRotate(T);//对应情况1,左旋
}else{//对应情况3,先右旋再左旋
LeftRotate(&(*T)->left);
RightRotate(T);
}
}
}
}

//更新当前节点的高度
(*T)->height = MAX(GetHeight((*T)->left),GetHeight((*T)->right))+1;
return 0;
}

//返回-1表示,树中没有该数据,删除失败,
int Delete(AVLtree* T,int D){
static Node* tmp;
if(T == NULL){
return -1;
}

if(*T == NULL){//树为空,或者树中没有该数据
return -1;
}else{
//找到要删除的节点
if(D == (*T)->data){
//删除的节点左右子支都不为空,一定存在前驱节点
if((*T)->left != NULL && (*T)->right != NULL){
D = FindMin((*T)->right);//找后继替换
(*T)->data = D;
Delete(&(*T)->right,D);//然后删除后继节点,一定成功
//在右子支中删除,删除后有可能左子支比右子支高度大2
if(GetHeight((*T)->left)-GetHeight((*T)->right) ==  2){
//判断哪一个左子支的的两个子支哪个比较高
if(GetHeight((*T)->left->left) >= GetHeight((*T)->left->right)){
RightRotate(T);
}else{
LeftRotate(&(*T)->left);
RightRotate(T);
}
}
}else
if((*T)->left == NULL){//左子支为空
tmp = (*T);
(*T) = tmp->right;
free(tmp);
return 0;
}else
if((*T)->right == NULL){//右子支为空
tmp = (*T);
(*T) = tmp->left;
free(tmp);
return 0;
}
}else
if(D > (*T)->data){//在右子支中寻找待删除的节点
if(Delete(&(*T)->right,D) == -1){
return -1;//删除失败,不需要调整,直接返回
}
if(GetHeight((*T)->left)-GetHeight((*T)->right) ==  2){
if(GetHeight((*T)->left->left) >= GetHeight((*T)->left->right)){
RightRotate(T);
}else{
LeftRotate(&(*T)->left);
RightRotate(T);
}
}
}else
if(D < (*T)->data){//在左子支中寻找待删除的节点
if(Delete(&(*T)->left,D) == -1){
return -1;
}
if(GetHeight((*T)->right) - GetHeight((*T)->left) == 2){
if(GetHeight((*T)->right->right) >= GetHeight((*T)->right->left)){
LeftRotate(T);
}else{
RightRotate(&(*T)->right);
LeftRotate(T);
}
}
}
}
//更新当前节点的高度
(*T)->height = MAX(GetHeight((*T)->left),GetHeight((*T)->right))+1;
return 0;
}

int Find(AVLtree T,int x){
while(T != NULL){
if(T->data == x){
return 0;
}else
if(x > T->data){
T = T->right;
}else{
T = T->left;
}
}
return -1;
}

int Destroy(AVLtree* T){
if(T == NULL){
return -1;
}

PostOrderTraverse(*T);
*T = NULL;
return 0;
}

void InOredrTraverse(AVLtree T){
if(T != NULL){
InOredrTraverse(T->left);
printf("%3d ",T->data);
InOredrTraverse(T->right);;
}
}

void PreOredrTraverse(AVLtree T){
if(T != NULL){
printf("%3d:%2d(%3d,%3d)\n",T->data,T->height,
T->left == NULL?-1:T->left->data,
T->right == NULL?-1:T->right->data
);
PreOredrTraverse(T->left);
PreOredrTraverse(T->right);
}
}

static void PostOrderTraverse(AVLtree T){
if(T != NULL){
PostOrderTraverse(T->left);
PostOrderTraverse(T->right);
free(T);
}
}

//空数的高度为0
static int GetHeight(AVLtree T){
if(T == NULL){
return 0;
}else{
return T->height;
}
}

static void LeftRotate(AVLtree* T){
Node *P,*R;
P = *T;
R = P->right;
P->right = R->left;
R->left = P;
*T = R;

//旋转以后要更新节点的高度
P->height = MAX(GetHeight(P->left),GetHeight(P->right))+1;
R->height = MAX(GetHeight(R->left),GetHeight(R->right))+1;
}

static void RightRotate(AVLtree* T){
Node *P,*L;
P = *T;
L = P->left;
P->left = L->right;
L->right = P;
*T = L;
//旋转以后要更新节点的高度
P->height = MAX(GetHeight(P->left),GetHeight(P->right))+1;
L->height = MAX(GetHeight(L->left),GetHeight(L->right))+1;
}

static int FindMin(AVLtree T){
if(T == NULL){
return -1;
}

while(T->left != NULL){
T = T->left;
}
return T->data;
}

6. Java语言泛型实现

package datastruct;

import java.util.Comparator;

public class AVLtree <E>{
private static class Node<E>{
int h;
E element;
Node<E> left;
Node<E> right;
//由于java中不像C语言那样有二级指针的概念,所以添加一个父类的引用,方便程序编写
Node<E> parent;

public Node(E element, int h, Node<E> left, Node<E> right, Node<E> parent){
this.element = element;
this.h = h;
this.left = left;
this.right = right;
this.parent = parent;
}
}

private Node<E> root;//指向伪根节点的引用
private int size = 0;//节点个数
Comparator<? super E> cmp;//节点大小的比较器

//如果调用了不带参数的构造函数,则使用该内部类作为比较器,
//但此时泛型E需要继承Comparable接口,否则运行时会抛出异常
private static class Cmp<T> implements Comparator<T>{
@SuppressWarnings({ "unchecked", "rawtypes" })
@Override
public int compare(T e1, T e2) {
return ((Comparable)e1).compareTo(e2);
}

}

//带比较器的构造函数
public AVLtree(Comparator<? super E> cmp){
if(cmp == null){
throw new IllegalArgumentException();
}
this.cmp = cmp;
//创建一个伪根节点,该节点的右子支才是真正的AVL树的根
//使用伪根节点节点的目的是,对插入和删除操作递归的形式能够统一
root = new Node<E>(null, -1, null, null, null);
}

//不带比较器的构造函数
public AVLtree(){
this.cmp = new Cmp<E>();
root = new Node<E>(null, -1, null, null, null);
}

//如果树中节点有变动,从底向上逐级调用该函数,可以更新节点的高度
private int getHight(Node<E> x){
if(x == null){
return 0;
}else{
return x.h;
}
}

//求某个节点作为根时,该子树的最小值
private E treeMin(Node<E> x){
while(x.left != null){
x = x.left;
}
return x.element;
}

public int size(){
return size;
}

//先根遍历,调试时使用
public void preorderTraverse(){
if(root != null){
preorderTraverse0(root.right);
}
}

private void preorderTraverse0(Node<E> x){
if(x != null){
System.out.print(x.element+" ");
if(x.left != null){
System.out.print(x.left.element+" ");
}else{
System.out.print("null  ");
}

if(x.right != null){
System.out.print(x.right.element+" ");
}else{
System.out.print("null  ");
}
System.out.println();
preorderTraverse0(x.left);
preorderTraverse0(x.right);
}
}

//逆时针旋转(左旋),参数表示轴节点
private void antiClockwiseRotate(Node<E> X){
Node<E> P = X.parent;
Node<E> XR = X.right;
if(P.left == X){
P.left = XR;
}else{
P.right = XR;
}
XR.parent = P;

X.right = XR.left;
if(XR.left != null){
XR.left.parent = X;
}

XR.left = X;
X.parent = XR;

//旋转后要更新这两个节点的高度
X.h = Math.max(getHight(X.left), getHight(X.right)) + 1;
XR.h = Math.max(getHight(XR.left), getHight(XR.right)) + 1;
}

//顺时针旋转(右旋),参数表示轴节点
private void clockwistRotate(Node<E> X){
Node<E> P = X.parent;
Node<E> XL = X.left;
if(P.left == X){
P.left = XL;
}else{
P.right = XL;
}
XL.parent = P;

X.left = XL.right;
if(XL.right != null){
XL.right.parent = X;
}

XL.right = X;
X.parent = XL;

//旋转后要更新这两个节点的高度
X.h = Math.max(getHight(X.left), getHight(X.right)) + 1;
XL.h = Math.max(getHight(XL.left), getHight(XL.right)) + 1;
}

//
public void insert(E e){
insert0(root.right, e);
}

private void insert0(Node<E> x, E e){
if(x == null){
root.right = new Node<E>(e, 1, null, null, root);//根节点
size++;
return;
}

if(cmp.compare(e, x.element) > 0){
if(x.right != null){
insert0(x.right, e);
int lh = getHight(x.left);
int rh = getHight(x.right);
if(rh - lh == 2){
if(cmp.compare(e, x.right.element) > 0){
antiClockwiseRotate(x);
}else{
clockwistRotate(x.right);
antiClockwiseRotate(x);
}
}
}else{
size++;
x.right = new Node<E>(e, 1, null, null, x);
}
}else
if(cmp.compare(e, x.element) < 0){
if(x.left != null){
insert0(x.left, e);
int lh = getHight(x.left);
int rh = getHight(x.right);
if(lh - rh == 2){
if(cmp.compare(e, x.left.element) < 0){
clockwistRotate(x);
}else{
antiClockwiseRotate(x.left);
clockwistRotate(x);
}
}
}else{
size++;
x.left = new Node<E>(e, 1, null, null, x);
}
}else{
//元素已存在,我们用新的元素更新旧,
//compare返回值等于0,并不表示两个对象完全相等
x.element = e;
}
x.h = Math.max(getHight(x.left), getHight(x.right)) + 1;
}

public boolean delete(E e){
return delete0(root.right, e);
}

//返回值表示是否删除成功
private boolean delete0(Node<E> x, E e){
if(x == null){//没有找到待删除的元素
return false;
}

if(cmp.compare(e, x.element) > 0){
boolean reval = delete0(x.right, e);
if(reval == false){
return false;
}

int lh = getHight(x.left);
int rh = getHight(x.right);
if(lh - rh == 2){
if(getHight(x.left.left) > getHight(x.left.right)){
clockwistRotate(x);
}else{
antiClockwiseRotate(x.left);
clockwistRotate(x);
}
}
}else
if(cmp.compare(e, x.element) < 0){
boolean reval = delete0(x.left, e);
if(reval == false){
return false;
}

int lh = getHight(x.left);
int rh = getHight(x.right);
if(rh - lh == 2){
if(getHight(x.right.right) > getHight(x.right.left)){
antiClockwiseRotate(x);
}else{
clockwistRotate(x.right);
antiClockwiseRotate(x);
}
}
}else{//找到待删除的元素
Node<E> P = x.parent;

if(x.left == null){//左子支为空,可直接删除,在这一层一定不需要旋转
size--;
if(P.left == x){
P.left = x.right;
if(P.left != null){
P.left.parent = P;
}
}else{
P.right = x.right;
if(P.right != null){
P.right.parent = P;
}
}
}else
if(x.right == null){//右子支为空,可直接删除,在这一层一定不需要旋转
size--;
if(P.left == x){
P.left = x.left;
if(P.left != null){
P.left.parent = P;
}
}else{
P.right = x.left;
if(P.right != null){
P.right.parent = P;
}
}
}else{//找到待删除的节点,用后继节点代替,然后删除后继节点
E nextVal = treeMin(x.right);
x.element = nextVal;
delete0(x.right, nextVal);
int lh = getHight(x.left);
int rh = getHight(x.right);
if(lh - rh == 2){
if(getHight(x.left.left) > getHight(x.left.right)){
clockwistRotate(x);
}else{
antiClockwiseRotate(x.left);
clockwistRotate(x);
}
}
}
}
x.h = Math.max(getHight(x.left), getHight(x.right)) + 1;
return true;
}

public static void main(String[] args){
AVLtree<Integer> avl = new AVLtree<Integer>();
/*可自行添加插入,删除操作进行测试*/
avl.insert(3);
avl.insert(5);
avl.insert(6);
avl.insert(7);
avl.insert(8);
avl.insert(9);
avl.preorderTraverse();
System.out.println();
System.out.println(avl.size());

avl.delete(7);
avl.delete(8);
avl.preorderTraverse();
System.out.println();
System.out.println(avl.size());
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: