データ構造:AVLバランスツリー(cバージョン)

AVLツリーは、バランスの取れたツリーの非常に古典的な例です。挿入と削除の過程で通常の検索ツリーは、ツリーの一方の端子の高さがツリーのもう一方の側よりもはるかに高い状況、つまり、リンクリストへのいわゆる縮退(検索は1つのノードを見つけることです)を生成する可能性があるため、検索が減少します効果。

AVLバランスツリーは一連の回転を使用するため、左側のサブツリーと右側のサブツリーの高さはそれほど変わらないため(<= 1)、検索効率は良好なレベルに維持されます。

方法は、ノードを挿入した後に
ノードの高さ更新して、親ノードの左右のサブツリー間の高さの差が2であるかどうか判別することです。その場合、対応する回転操作(4タイプ)を実行して、左右のサブツリー間の高さの差を減らします。そうでない場合は、ルートノードまで(もちろん再帰的に実行されるまで)、親ノードの親の左右のサブツリー間の高さの差が2であるかどうかを判断します。

シングル左利き、シングル右利き、左右、右左は3つのノード間の順序を調整するためのもので、コードは次のとおりです。特定の外観は描画されません。これらのポイントの順序を調整する過程で、検索ツリーのサイズの順序はまだ残っていることがわかります。通常配置。
つまり、順序どおりのトラバーサルの結果は、小さいものから大きいものへとソートされたままです。
avl_tree.h

#ifndef _Avltree_h
#define _Avltree_h
#define Max(a,b) ((a)>(b)?(a):(b))

struct AvlNode;
typedef struct AvlNode*Position;
typedef struct AvlNode*AvlTree;
typedef int ElementType ;
Position    Find(ElementType X,AvlTree T);
Position    FindMin(AvlTree T);
Position    FindMax(AvlTree T);
AvlTree MakeEmpty(AvlTree T);
AvlTree Insert(ElementType X,AvlTree T);
void InOrder_2(AvlTree T,int depth);
int  PostOrder_2(AvlTree T,int depth);
void PreOrder_2(AvlTree T,int depth);
void PreOrder(AvlTree T);
void InOrder(AvlTree T);
void PostOrder(AvlTree T);
struct AvlNode
{
    
    
    ElementType Element;
    AvlTree Left;
    AvlTree Right;
    int Height;
};
#endif


avl_tree.c

#include<stdio.h>
#include<stdlib.h>
#include"avl_tree.h"
static  Position    SingleRotateWithLeft(Position K2);
static  Position    DoubleRotateWithLeft(Position   K3);
static  Position    SingleRotateWithRight(Position K2);
static  Position    DoubleRotateWithRight(Position   K3);
static int Height (Position P);
static  Position    SingleRotateWithLeft(Position K2)
{
    
    
    // puts("右旋");

    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    DoubleRotateWithLeft(Position   K3)
{
    
    
    //puts("左右");

    K3->Left=SingleRotateWithRight(K3->Left);
    return  SingleRotateWithLeft(K3);
}
static  Position    SingleRotateWithRight(Position K2)
{
    
    
    /* 
        1
    0       2   k2
                4   k1 
                    5
        1
    0       4  k1
            2   5
     */
    // puts("单左旋");
    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(Height(K1->Left),K2->Height)+1;
    return  K1;
}
static  Position    DoubleRotateWithRight(Position   K3)
{
    
    
    // puts("右左");
/*     
    //120534
    1                                                       1                                   1               
0        2       k3       --》                   0       2       --》       0           3
            5      k3->right                                3                           2       5   
        3                                                                 5     
                
 */     
  K3->Right=SingleRotateWithLeft(K3->Right);
    return  SingleRotateWithRight(K3);
}
void InOrder(AvlTree T)
{
    
    
    if(T!=NULL){
    
    
        InOrder(T->Left);
        printf("%d\n",T->Element);
        InOrder(T->Right);
    }
}
void PostOrder(AvlTree T)
{
    
    
    if(T!=NULL){
    
    
        PostOrder(T->Left);
        PostOrder(T->Right);
        printf("%d\n",T->Element);
    }
}
void PreOrder_2(AvlTree T,int depth)
{
    
    

    if(T!=NULL){
    
    
        for (int i = 0; i < depth; i++)
            printf("\t");
        printf("%d\n",T->Element);
        PreOrder_2(T->Left,depth+1);
        PreOrder_2(T->Right,depth+1);
    }
}
void InOrder_2(AvlTree T,int depth)
{
    
    

    if(T!=NULL){
    
    
        InOrder_2(T->Left,depth+1);
        for (int i = 0; i < depth; i++)
            printf("\t");
        printf("%d\n",T->Element);
        InOrder_2(T->Right,depth+1);
    }
}
int  PostOrder_2(AvlTree T,int depth)
{
    
    
    int retSize;
    int retSize2;
    if(T!=NULL){
    
    
        retSize=PostOrder_2(T->Left,depth+1);
        retSize2=PostOrder_2(T->Right,depth+1);
        for (int i = 0; i < depth; i++)
            printf("\t");
        printf("%d(%d)\n",T->Element,T->Element+retSize+retSize2);
        return  retSize2+retSize+T->Element;
    }else{
    
    
        return  0;
    }
}
void PreOrder(AvlTree T)
{
    
    
    if(T!=NULL){
    
    
        printf("%d\n",T->Element);
        
        PreOrder(T->Left);
        PreOrder(T->Right);
    }
}

AvlTree  MakeEmpty(AvlTree T)
{
    
    
    //后序
    if(T!=NULL){
    
    
        MakeEmpty(T->Left);
        MakeEmpty(T->Right);
        free(T);
    }
    return  NULL;
}

static int Height (Position P)
{
    
    
    if(P==NULL)
        return  -1;
    else 
        return  P->Height;
}
Position    Find(ElementType X,AvlTree T)
{
    
    
    if(T==NULL)
        return  NULL;
    if(X<T->Element)
        return  Find(X,T->Left);
    else if(X>T->Element)
        return  Find(X,T->Right);
    else    
        return  T;
}

AvlTree Insert(ElementType X,AvlTree T)
{
    
    
    if(T==NULL){
    
    
        T=malloc(sizeof(struct AvlNode));
        if(T==NULL){
    
    
            fprintf(stderr,"Out of space");
            return NULL;
        }
        else{
    
    
            T->Element=X;
            T->Height=0;
            T->Left=T->Right=NULL;
        }
        //放在左(递归)
    }
    else if(X<T->Element){
    
    
        // printf("%d<%d\n",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;
}

自分で作成した新しいトラバーサル関数は、プレオーダートラバーサル(PreOrder_2)、インオーダートラバーサル(INOrder_2)、およびポストオーダートラバーサル(PostOrder_2)の効果を出力できます。

  • 事前注文トラバーサル:中央左と右(メンテナンスの深さ、子ノードは親ノードから継承)
  • ミドルオーダートラバーサル:左、中、右から小から大へ
  • 注文後のトラバーサル:左右(高さを維持し、親ノードは子ノードから取得されます)(ディレクトリのサイズをカウントするために使用でき、子ファイルのサイズがディレクトリに追加および追加されます)ここでは、代わりにノードの重みを表すために数値を直接使用しますファイルサイズと親ノードへのマージ。

(中段の印刷は木のようだと思います)

#include<stdio.h>
#include<stdlib.h>
#include"avl_tree.h"
int main()
{
    
    
    AvlTree T=NULL;
    // int X=1;
    // T=Insert(X,T);
    // X=0;
    // T=Insert(X,T);
    // X=2;
    // T=Insert(X,T);
    // X=5;
    // T=Insert(X,T);
    // X=3;
    // T=Insert(X,T);

    /* 
    
        1                      1                                1
    0   2               0       2                   0           3
            5                           3                       2       5
          3                                   5
    
     */

    for (int i = 0; i < 10; i++)
    {
    
    
        T=Insert((i+1),T);
    }
    
    // if(Find(3,T)->Right){
    
    
    //     printf("r%d\n",Find(3,T)->Right->Element);
    // }
    // if(Find(3,T)->Left){
    
    
    //     printf("l%d\n",Find(3,T)->Left->Element);
    // }
    
     puts("先");
    PreOrder(T);
    
    puts("中");
    InOrder(T);
    puts("后");
    PostOrder(T);
    // puts("后2");
    // PostOrder_2(T,0);
    // PreOrder_2(T,0);
    InOrder_2(T,0);
    MakeEmpty(T);
}

4
2
1
3
8
6
5
7
9
10
--------------------------
1
2
3
4
5
6
7
8
9
10
--------------------------
1
3
2
5
7
6
10
9
8
4
--------------------------
4
        2
                1
                3
        8
                6
                        5
                        7
                9
                        10
--------------------------
                1
        2
                3
4
                        5
                6
                        7
        8
                9
                        10
--------------------------
                1(1)
                3(3)
        2(6)
                        5(5)
                        7(7)
                6(18)
                        10(10)
                9(19)
        8(45)
4(55)
--------------------------

この記事では、AVLの効果を説明するために、あまり説明していません。
元々、123456789 10を挿入すると、ツリーがどこまで成長するかを想像できます。
ローテーションの4つの機能については、自分で理解したほうがいいですし、他の人のブログを読むよりもずっと便利です。

当時これらのアルゴリズムを発明したTucaoの人々は、私たちよりもはるかに優れています。

「データ構造とアルゴリズムC言語の説明」を参照してください。

おすすめ

転載: blog.csdn.net/adlatereturn/article/details/106845518
おすすめ