二叉排序树及平衡二叉树的实现

二叉排序树及平衡二叉树的实现

二叉排序树

二叉排序树,又称为二叉查找树。它或者是一颗空树,或者具有下列性质 的二叉树。

•若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;

•若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;

•它的左、右子树也分别为二叉排序树。

构造一颗二叉排序树的目的,其实并不是为了排序,而是为了提高查找和>插入删除关键字的速度。不管怎么说,在一个有序数据集上的查找,速度总是要快于无序数据集的,而二叉排序树这种非线性的结构,也有利于插入和删除的实现。

插入和查找比较简单,在这里我就不详细说明了。

1、二叉排序树的插入

bool BinSortInsert(BTree *root,int num)
{
    if(*root == NULL)
    {
        *root = (BTree)malloc(sizeof(BtNode));
        (*root)->data = num;
        (*root)->left = NULL;
        (*root)->right = NULL;
        return true;
    }
    if((*root)->data == num)
    {
        cout<<"要插入的结点已存在!"<<endl;
        return false; 
    }
    if((*root)->data > num)
    {
        BinSortInsert(&(*root)->left,num); 
    }
    else
    {
        BinSortInsert(&(*root)->right,num);
    }
}

2、二叉排序树的查找

BtNode* BinSortSearch(BTree root,int num)
{
    BtNode* p = root;

    if(p == NULL)
    {
        return NULL;//若为空则没有该节点 
    }
    if(p->data == num)
    {
        return p;
    }
    if(p->data > num)
    {
        p = BinSortSearch(p->left,num);
    } 
    else
    {
        p = BinSortSearch(p->right,num);
    }
    return p;
}

下面着重讲下删除操作:
首先,找到要删除的结点p,可以遍历,也可以调用上面已经写好的查找函数。
然后,p的情况分为三种:
(1)、p为叶子节点;直接删除p。

   free(p);

《二叉排序树及平衡二叉树的实现》
(2)、p的左右子树之一为空;

左孩子为空,用q保存p结点,让p指向它的右孩子,再释放q;

   BtNode *q;
   q = p;
   p = p->right;
   free(q);

《二叉排序树及平衡二叉树的实现》

右孩子为空,用q保存p结点,让p指向它的左孩子,再释放q;

   BtNode *q;
   q = p;
   p = p->left;
   free(q);

《二叉排序树及平衡二叉树的实现》
(3)、p的左右子树都不为空;
左右孩子都不为空,则先找到p的直接前驱结点s,并记录s的父节点q;

    BtNode *q,*s;
    q->right = s->left;
    p->data = s->data;
    free(s);

《二叉排序树及平衡二叉树的实现》

3、二叉排序树的删除

void DeleteNode(BtNode **p)
{
    BtNode *q,*s;
    if((*p)->left == NULL && (*p)->right == NULL)
    {
        free(*p);
    }
    else if((*p) == NULL)
    {
        q = *p;
        *p = (*p)->right;
        free(q);
    }
    else if((*p) == NULL)
    {
        q = *p;
        *p = (*p)->left;
        free(q);
    }
    else
    {
        q = *p;
        s = q->left;
        while(s->right)
        {
            q = s;
            s = s->right;
        }
        q->right = s->left;
        (*p)->data = s->data;
        free(s);
    }
}
void BinSortDelete(BTree *root,int num)
{
    BtNode * p = BinSortSearch(*root,num);
    if(p == NULL)
    {
        return;
    } 
    DeleteNode(&p);
    /*
    BtNode *p = *root;

    if(p == NULL)
    {
        return;
    } 
    if(p->data == num)
    {
        DeleteNode(&p);
    }
    else if (p->data > num)
    {
        BinSortDelete(&(p->left),num);
    }
    else
    {
        BinSortDelete(&(p->right),num);
    }*/

}

4、二叉排序树整体实现

int main()
{
    BTree BT = NULL;
    int num;
    cin>>num;
    while(num != -1)
    {
        if(BinSortInsert(&BT,num))
        {
            cin>>num;
        }
        else
        {
            break;
        }
    }
    BinSortDelete(&BT,32);
    PrintBTree(BT);

    return 0;
}


总结:二叉排序树的时间复杂度为O(logn),n为节点个数,log为树的深度,最坏的情况logn = n 即时间复杂度为O(n)优点在于采用链式存储(插入删除较方便)的同时,还能保证查找的时间复杂度不会太高。
但是它的缺点在于,随着插入的进行,树的形状可能会趋于不平衡,如下图所示。所以才有了AV树,通过插入后的旋转,改善了二叉排序树插入、删除导致的不平衡。

AV(平衡二叉树)树

1、av树的插入

    原文作者:平衡二叉树
    原文地址: https://blog.csdn.net/ssqqdns/article/details/76192849
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞