链表表示二叉树+二叉搜索树+AVL树 复习

36 篇文章 0 订阅
4 篇文章 0 订阅
这篇博客主要复习了链表表示的二叉树,包括二叉树的节点表示和遍历方式,如中序、前序、后序及层序遍历。接着介绍了二叉搜索树的插入和删除操作,以及平衡二叉树——AVL树的原理,如插入节点时的四种旋转调整(RR、LL、LR、RL)来保持树的平衡。
摘要由CSDN通过智能技术生成

二叉树的结点表示

左子树,右子树,结点数据

typedef struct TNode *Position;
typedef Position BinTree; /* 二叉树类型 */
struct TNode{ /* 树结点定义 */
    ElementType Data; /* 结点数据 */
    BinTree Left;     /* 指向左子树 */
    BinTree Right;    /* 指向右子树 */
};

二叉树的遍历(递归)

printf根节点的数据;

中序遍历,左子树->根节点->右子树;

void InorderTraversal( BinTree BT )
{
    if( BT ) {
        InorderTraversal( BT->Left );
        /* 此处假设对BT结点的访问就是打印数据 */
        printf("%d ", BT->Data); /* 假设数据为整型 */
        InorderTraversal( BT->Right );
    }
}

前序遍历,根节点->左子树->右子树;

void PreorderTraversal( BinTree BT )
{
    if( BT ) {
        printf("%d ", BT->Data );
        PreorderTraversal( BT->Left );
        PreorderTraversal( BT->Right );
    }
}

后序遍历,左子树->右子树->根节点;

void PostorderTraversal( BinTree BT )
{
    if( BT ) {
        PostorderTraversal( BT->Left );
        PostorderTraversal( BT->Right );
        printf("%d ", BT->Data);
    }
}

层序遍历——类似BFS
创建队列,从根节点开始入队,子树从左至右入队;
结点出队后输出,并且左右子树顺序入队,即可完成层序遍历;

void LevelorderTraversal ( BinTree BT )
{ 
    Queue Q; 
    BinTree T;
 
    if ( !BT ) return; /* 若是空树则直接返回 */
     
    Q = CreatQueue(); /* 创建空队列Q */
    AddQ( Q, BT );
    while ( !IsEmpty(Q) ) {
        T = DeleteQ( Q );
        printf("%d ", T->Data); /* 访问取出队列的结点 */
        if ( T->Left )   AddQ( Q, T->Left );
        if ( T->Right )  AddQ( Q, T->Right );
    }
} 

二叉搜索树

1.插入结点
将X插入BST中;

若结点为空,创建节点对象,X赋值给data;(终止条件)
若结点不为空,比较X和节点的data大小,X小则往左子树找,X大则往右子树找;
直到找到子树为空的结点,插入该空位即可;

BinTree Insert( BinTree BST, ElementType X )
{
    if( !BST ){ /* 若原树为空,生成并返回一个结点的二叉搜索树 */
        BST = (BinTree)malloc(sizeof(struct TNode));
        BST->Data = X;
        BST->Left = BST->Right = NULL;
    }
    else { /* 开始找要插入元素的位置 */
        if( X < BST->Data )
            BST->Left = Insert( BST->Left, X );   /*递归插入左子树*/
        else  if( X > BST->Data )
            BST->Right = Insert( BST->Right, X ); /*递归插入右子树*/
        /* else X已经存在,什么都不做 */
    }
    return BST;
}

2.结点删除函数

在BST中删除X;
通过比较找到X,若直到空结点都未找到X,说明不存在要删除的X;

若找到X,需分类讨论:
(1)要删除的结点有左右子树:
从左子树中找到最大值或者从右子树中找到最小值结点,填充被删除的结点位置,删除该最大,最小结点(最大最小结点必只有一个子树或没有子树)
(2)要删除的结点有一个和子树或没有子树
若只有右子树:右子树接替被删除的结点的位置;
若只有左子树:左子树接替被删除的结点的位置;
若没有子树:被删除的结点位置变为空结点;

BinTree Delete( BinTree BST, ElementType X ) 
{ 
    Position Tmp; 
 
    if( !BST ) 
        printf("要删除的元素未找到"); 
    else {
        if( X < BST->Data ) 
            BST->Left = Delete( BST->Left, X );   /* 从左子树递归删除 */
        else if( X > BST->Data ) 
            BST->Right = Delete( BST->Right, X ); /* 从右子树递归删除 */
        else { /* BST就是要删除的结点 */
            /* 如果被删除结点有左右两个子结点 */ 
            if( BST->Left && BST->Right ) {
                /* 从右子树中找最小的元素填充删除结点 */
                Tmp = FindMin( BST->Right );
                BST->Data = Tmp->Data;
                /* 从右子树中删除最小元素 */
                BST->Right = Delete( BST->Right, BST->Data );
            }
            else { /* 被删除结点有一个或无子结点 */
                Tmp = BST; 
                if( !BST->Left )       /* 只有右孩子或无子结点 */
                    BST = BST->Right; 
                else                   /* 只有左孩子 */
                    BST = BST->Left;
                free( Tmp );
            }
        }
    }
    return BST;
}

平衡二叉树——AVL树

改善二叉搜索树,使得树不会一边高一边低;

1.树结点
增加树高的记录;
左子树+右子树+结点数据;

typedef struct AVLNode *Position;
typedef Position AVLTree; /* AVL树类型 */
struct AVLNode{
    ElementType Data; /* 结点数据 */
    AVLTree Left;     /* 指向左子树 */
    AVLTree Right;    /* 指向右子树 */
    int Height;       /* 树高 */
};

防止树一边高一边低的方法
在插入结点时调整;
若插入新结点导致上面一节点的高度差变为2,需要根据新节点和老节点的位置进行相应调整;
(1)新节点在老节点的右子树的右子树,进行RR旋转,即左旋;
老节点的右子树变为原右子树的左子树;
老节点的右子树的左子树变为老节点;
更新老节点的树高和老节点的右子树的书高;

AVLTree rightright(AVLTree A)   //右右 ——左旋 
{
	AVLTree B=A->right;
	A->right=B->left;
	B->left=A;
	A->height=max(getheight(A->left),getheight(A->right));
	B->height=max(getheight(B->right),A->height);
	return B;
}

(2)新节点在老节点的左子树的左子树,进行LL旋转,即右旋;
老节点的左子树指向老节点左子树的右子树;
老节点的左子树的右子树指向老节点;
更新老节点的树高和老节点的左子树的树高;

AVLTree leftleft(AVLTree A){    //左左 ——右旋 
	AVLTree B=A->left;
	A->left=B->right;
	B->right=A;
	//计算高度
	A->height=max(getheight(A->left),getheight(A->right));
	B->height=max(getheight(B->left),A->height);
    //要写一个getheight函数——递归得到给定节点的height	
	return B;
}

(3)新节点在老节点的左子树的右子节点上,即LR旋转,(对L子树进行RR,再对自己进行LL);

AVLTree leftright(AVLTree A)
{
	//先把左边左旋,再把自己右旋
	A->left=rightright(A->left);
	return leftleft(A); 
 } 

先对老节点的左子树进行RR旋转,即左旋;
再对老节点进行LL旋转,即右旋;

AVLTree DoubleLeftRightRotation ( AVLTree A )
{ /* 注意:A必须有一个左子结点B,且B必须有一个右子结点C */
  /* 将A、B与C做两次单旋,返回新的根结点C */
     
    /* 将B与C做右单旋,C被返回 */
    A->Left = SingleRightRotation(A->Left);
    /* 将A与C做左单旋,C被返回 */
    return SingleLeftRotation(A);
}

(4)新节点在老节点的右子树的左节点上,即RL旋转,(对R子树进行LL,再对自己进行RR)
先对老节点的右子树进行LL旋转,即右旋;
再对老节点机械能RR旋转,即左旋;

AVLTree rightleft(AVLTree A)     
//先把右边的右旋,再把自己左旋 
{
	A->right=leftleft(A->right);
	return rightright(A);
}

2.插入函数
与搜索二叉树相同,找到空结点后插入值为X的新结点;
在插入的过程中每次更新经过的结点的左右高度差,当高度差为2时,插入节点往左子树的左边走时使用LL旋转,往左子树的右边走时使用LR旋转;
同理添加RR旋转和RL旋转;
插入后需要更新根节点的高度;

AVLTree Insert( AVLTree T, ElementType X )
{ /* 将X插入AVL树T中,并且返回调整后的AVL树 */
    if ( !T ) { /* 若插入空树,则新建包含一个结点的树 */
        T = (AVLTree)malloc(sizeof(struct AVLNode));
        T->Data = X;
        T->Height = 0;
        T->Left = T->Right = NULL;
    } /* if (插入空树) 结束 */
 
    else if ( X < T->Data ) {
        /* 插入T的左子树 */
        T->Left = Insert( T->Left, X);
        /* 如果需要左旋 */
        if ( GetHeight(T->Left)-GetHeight(T->Right) == 2 )
            if ( X < T->Left->Data ) 
               T = SingleLeftRotation(T);      /* 左单旋 */
            else 
               T = DoubleLeftRightRotation(T); /* 左-右双旋 */
    } /* else if (插入左子树) 结束 */
     
    else if ( X > T->Data ) {
        /* 插入T的右子树 */
        T->Right = Insert( T->Right, X );
        /* 如果需要右旋 */
        if ( GetHeight(T->Left)-GetHeight(T->Right) == -2 )
            if ( X > T->Right->Data ) 
               T = SingleRightRotation(T);     /* 右单旋 */
            else 
               T = DoubleRightLeftRotation(T); /* 右-左双旋 */
    } /* else if (插入右子树) 结束 */
 
    /* else X == T->Data,无须插入 */
 
    /* 别忘了更新树高 */
    T->Height = Max( GetHeight(T->Left), GetHeight(T->Right) ) + 1;
     
    return T;
} 

3.getheight函数
递归方式遍历结点,得到结点高度

int getheight(AVLTree A)
{
	if(!A) return 0;
	return max(getheight(A->left),getheight(A->right))+1; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值