码迷,mamicode.com
首页 > 其他好文 > 详细

AVL树

时间:2015-08-19 17:48:33      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:linux c

AVL树的节点声明:

typedef int ElementType;
#ifndef _AvlTree_H

struct AvlNode;
typedef struct AvlNode *Position;
typedef struct AvlNode *AvlTree;

AvlTree MakeEmpty(AvlTree T);
Position Find(ElementType X,AvlTree T);
Position FindMin(AvlTree T);
Position FindMax(AvlTree T);
AvlTree Insert(ElementType X,AvlTree T);
AvlTree Delete(ElementType X,AvlTree T);
ElementType Retrieve(Position P);

#endif

struct AvlNode
{
    ElementType Element;
    AvlTree Left;
    AvlTree Right;
    int Height;
};

下面只是写出了Insert函数以及它调用的函数的程序:

static int Height(Position P)
{
    if(P==NULL)
	return -1;
    else
	return P->Height;
}

static Position SingleRotateWithLeft(Position K2)
{
    Position 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;
}

static Position SingleRotateWithRight(Position K2)
{
    Position K1;
    K1=K2->Right;
    K2->Right=K1->Left;
    K1->Left=K2;
    K2->Height=Max(Height(K2->Left),Height(K2->Right))+1;
    K1->Height=Max(K2->Height,Height(K1->Right))+1;
    return K1;
}
static Position DoubleRotateWithLeft(Position K3)
{
    K3->Left=SingleRotateWithRight(K3->Left);
    return SingleRotateWithLeft(K3);
}

static Position DoubleRotateWithRight(Position K3)
{
    K3->Right=SingleRotateWithLeft(K3->Right);
    return SingleRotateWithRight(K3);
}

AvlTree Insert(ElementType X,AvlTree T)
{
    if(T==NULL)
    {
        T=malloc(sizeof(struct AvlNode));
        if(T==NULL)
        {
	    printf("Out of space !\n");
        }

        p->Element=X;
        p->Left=NULL; p->Right=NULL;
        p->Height=0;	
    } 
    else
    {  
        if(X < T->Element )
        {
	    T->Left=Insert(X,T->Left);
	    if(Height(T->Left)-Height(T->Right)==2)
	    {
		if(X < T->Left->Element)
		    T=SingleRotateWithLeft(T);
		else
		    T=DoubleRotateWithLeft(T);
	    }
        }
        else if(X > T->Element )
        {
	    T->Right=Insert(X,T->Right);
	    if(Height(T->Right)-Height(T->Left)==2)
	    {
		if(X > T->Right->Element)
		    T=SingleRotateWithRight(T);
		else
		    T=DoubleRotateWithRight(T);
	    }
        } 
    }

    T->Height=Max(Height(T->Left),Height(T->Right))+1;
    return T;
}

在上面的Insert程序中,if(X < T->Element) 和 else if(X > T->Element)的内容是我没有写出来的,也就是几乎整个程序都没写出来。这个函数是需要谨记的!!!


仔细看这个程序的话,就会发现不是表面上看上去的那么简单!

递归调用Insert函数,接下来如果调整树。最先调整的是,距离插入节点到根的路径上,最先出现不平衡的那个子树。然后检验往上的路径中的子树是否是平衡的。


以上是书上的一个递归Insert程序。

下面是我自己写的一个非递归Insert程序:

AvlTree Insert(ElementType X,AvlTree T)
{
    Position q=malloc(sizeof(struct AvlNode));
    if(q==NULL)
    {
	printf("malloc space fail !\n");
	return T;
    }
    q->Element=X;
    q->Left=NULL; q->Right=NULL;
    q->Height=0;

    if(T==NULL)
        return q;
    if(Find(X,T))
	return T;

    Position p=T;
    while(p!=NULL)
    {
	if(X < p->Element )
   	{
	    p->Height=0;
	    Push(p,s);
	    p=p->Left;
        }
        else if(X > p->Element )
        {
	    p->Height=1;
	    Push(p,s);
	    p=p->Right;
        } 
    }
    
    p=TopAndPop(s);
    int i=2, first, second=p->Height;
    if(p->Height==0)
    {
	p->Left=q;
	p->Height=1;
    }
    else
	p->Right=q;
    
    Position tmp;
    while(!IsEmpty(s))
    {
	p=TopAndPop(s);
	first=p->Height;
	p->Height=i;
	
	if(first==0)
	{
	    if(Height(p->Left)-Height(p->Right)==2)
	    {
		if(second==0)
		    tmp=SingleRotateWithLeft(p);
		else
		    tmp=DoubleRotateWithLeft(p);
		if(IsEmpty(s))
		{
		    p=tmp;
		}
		else
		{
		    p=Top(Stack(s));
		    if(p->Height==0)
			p->Left=tmp;
		    else
			p->Right=tmp;
		}
	    }
	}
	else
	{
	    if(Height(p->Right)-Height(p->Left)==2)
	    {
		if(second==1)
		    tmp=SingleRotateWithRight(p);
		else
		    tmp=DoubleRotateWithRight(p);
		if(IsEmpty(s))
		{
		    p=tmp;
		}
		else
		{
		    p=Top(Stack(s));
		    if(p->Height==0)
			p->Left=tmp;
		    else
			p->Right=tmp;
		}
	    }
	}
	second=first;
   	i++;
    }

    return p;
}

这个非递归程序的思想是这样的:

创建一个Position节点q,将Insert函数参数中的X放进去。

  1. 先判断函数的参数T是否为NULL,若是,那就返回q。

  2. 查找AVL树T中是否有元素X,若有,返回T;

  3. 第18行到33行,查找元素X的位置。从根到元素位置的路径上经过的每个节点p(包括根节点,但不包括元素X所在的节点):如果元素在它左边,这个节点的p->Height=0;如果元素在它右边,这个节点的p->Height=1, p入栈。

  4. 第35到43行,将元素X插入到正确位置,它的父节点为p,且p->Height=1。

  5. 从45行到98行,将栈s中的指针依次出栈。用i表示出栈的对应节点p的Height的值,first=0表示元素X在p的左子树上,first=1表示元素X在p的右子树上。second=0表示元素X在p的儿子的左子树上,second=1表示元素X在p的儿子的右子树上。 对于出栈的每个节点p,检查是否平衡。如果不平衡,根据first和second调用相应的单旋转或双旋转使子树p平衡。并且,根据节点p的父亲的Height值,使平衡后的子树p重新成为它父亲的对应儿子( p的父亲的Height=0,那么p在平衡前是左儿子,平衡后也应该成为左儿子)。

AVL树

标签:linux c

原文地址:http://yuzwei.blog.51cto.com/10126623/1685775

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!