二叉排序树(二叉搜索树)【C++】

12 篇文章 0 订阅
2 篇文章 0 订阅

本次整理树的部分大概包括:二叉树、二叉搜索树、AVL树、红黑树、B树、T树。


第二部分 二叉排序树(BST)

1、定义:

二叉排序树,又称二叉搜索树。二叉排序树是一棵空树,或者是具有以下性质的二叉树:

  • 每个节点都有一个作为搜索依据的关键码(key),所有节点的关键码互不相同。
  • 左子树(如果存在)上所有节点的关键码的值都小于根节点的关键码
  • 右子树(如果存在)上所有节点的关键码的值都大于根节点的关键码
  • 左子树和右子树也是一棵二叉排序树

例如:
在这里插入图片描述

2、二叉排序树的存储

和二叉树相似,二叉排序树的链式存储如下:

//二叉排序树
typedef int Elemtype;
typedef struct BstNode
{
    Elemtype data;
    struct BstNode* leftchild;
    struct BstNode* parent;
    struct BstNode* rightchild;
}BstNode, * BstTree;

区别点在于,结点多了一个parent域,方便查找结点的父节点。

二叉排序树的创建
实际上每次插入一个新的结点,都是按照下面的步骤来执行的:
①首先判断树的根空不空,若为空,则创建新根,否则到第二步;
②寻找这棵树中是否已经相同关键码的结点,若有则不插入,返回;否则继续执行;
③若不含有相同关键码的结点,经过第2步,找到的位置就应该是此关键码即将要插入的位置;
④申请新节点,进行初始化,插入这棵树种(完善节点间指向关系)

//申请新结点
BstNode* Buynode()
{
    BstNode* s = (BstNode*)malloc(sizeof(BstNode));
    if (s == NULL) exit(1);
    //memset(s, 0, sizeof(BstNode));
    s->data = 0;
    s->parent = NULL;
    s->leftchild = NULL;
    s->rightchild = NULL;
    return s;
}

BstNode* MakeRoot(Elemtype kx)
{
    BstNode* s = Buynode();
    s->data = kx;
    return s;
}
bool Insert(BstTree& ptr, Elemtype kx)
{
    if (ptr == NULL)
    {
        ptr = MakeRoot(kx);
        return true;
    }
    BstNode* pa = NULL;
    BstNode* p = ptr;
    while (p != NULL && p->data != kx)
    {
        pa = p;
        p = kx < p->data ? p->leftchild : p->rightchild;
    }
    if (p != NULL && p->data == kx) return false;//找到了不插入

    p = Buynode();
    p->data = kx;
    p->parent = pa;
    if (pa==NULL)
    {
        ptr = p;
    }
    else
    {
        if (p->data < pa->data)
        {
            pa->leftchild = p;
        }
        else
        {
            pa->rightchild = p;
        }
    }
    return true;
}

int main()
{
    BstTree root = NULL;

    int ar[] = { 53,17,78,9,45,65,87,23,81,94,88,100 };
    int n = sizeof(ar) / sizeof(ar[0]);
    for (int i = 0 ; i < n; ++i)
    {
        cout << Insert(root, ar[i]) << endl;
    }
}

二叉排序树的遍历

//先序遍历(递归)
void PreOrder(BstNode* ptr)
{
    if (ptr != NULL)
    {
        cout << ptr->data<<" ";
        PreOrder(ptr->leftchild);
        PreOrder(ptr->rightchild);
    }
    
}
//中序遍历(递归)
void InOrder(BstNode* ptr)
{
    if (ptr != NULL)
    {
        InOrder(ptr->leftchild);
        cout << ptr->data << " ";
        InOrder(ptr->rightchild);
    }

}

//按照关键码从小到大遍历
void NiceOrder(BstNode* ptr)//小——>大
{
    for (BstNode* p = First(ptr); p != NULL; p = Next(p))
    {
        cout << p->data << " ";
    }
    cout << endl;
}
//按照关键码从大到小遍历
void Nicereverse(BstNode* ptr)
{
    for (BstNode* p = Last(ptr); p != NULL; p = Pre(p))
    {
        cout << p->data << " ";
    }
    cout << endl;
}

寻找二叉排序树的第一个元素结点
因为二叉排序树的定义是要这样的,每个节点其左子树的所有节点的关键码都小于其值;其右子树的所有节点的关键码都大于其值。因此,一棵二叉排序树的第一个元素结点一定是最左的那个叶结点。
同理,二叉排序树得到最后一个元素结点一定在其最右边的叶子结点上。

BstNode* First(BstNode* ptr)
{
	while(ptr!=NULL && ptr->leftchild!=NULL)
	{
		ptr=ptr->leftchild;
	}
	return ptr;
}
BstNode* Last(BstNode* ptr)
{
    while (ptr != NULL && ptr->rightchild != NULL)
    {
        
        ptr = ptr->rightchild;
    }
    return ptr;
}

寻找某结点的上一个元素结点,若给结点有左子树,上一个元素结点就是其左子树的Last()结点;若没有左子树,则向上回溯,若此节点是父节点的右孩子,则返回父节点,反之一直向上回溯。
同理,寻找某结点的下一元素结点,若该节点有右子树,则下一结点就是右子树的第一个元素结点;否则,向上回溯,若此节点是父节点的左孩子,返回父节点,反之一直向上回溯。

BstNode* Pre(BstNode* ptr)
{
    if (ptr == NULL) return NULL;
    if (ptr->leftchild != NULL)
    {
        return Last(ptr->leftchild);
    }
    else//左孩子为空
    {
        BstNode* pa = ptr->parent;
        while (pa != NULL && pa->rightchild != ptr)
        {
            ptr = pa;
            pa = pa->parent;
        }
        return pa;
    }
}
BstNode* Next(BstNode* ptr)
{
    if (ptr == NULL)return NULL;
    if (ptr->rightchild != NULL) return First(ptr->rightchild);
    else
    {
        BstNode* pa = ptr->parent;
        while (pa != NULL && pa->leftchild != ptr)
        {
            ptr = pa;
            pa = pa->parent;
        }
        return pa;
    }
}

二叉排序树的删除:
首先,判断该二叉排序树中是否有该节点,若无,则返回;
若存在,且当前节点是双分支,则找到该节点的下一元素结点,交换两节点值,这样就变成了删除某个叶子结点;
此时,要删除的结点要么是叶结点,要么是个单分支节点:删除其父节点即可。

bool Remove(BstNode* ptr,Elemtype kx)
{
    if (ptr == NULL) return false;
    BstNode* pa = nullptr;
    BstNode* p = ptr;
    while (p != NULL && p->data != kx)
    {
        p = kx > p->data ? p->rightchild : p->leftchild;
    }
    if (p == NULL) return false;//未找到kx值

    if (p->leftchild != nullptr && p->rightchild != NULL) //双分支
    {
        BstNode* q = First(p->rightchild);//找next(p)
        p->data = q->data;
        p = q;//替换去删
    }
    //p ->leaf叶子
    pa = p->parent;
    BstNode* child = p->leftchild ? p->leftchild : p->rightchild;//要么是单要么是空
    if (child != NULL)
    {
        child->parent = pa;
    }
    else
    {
        if (pa->leftchild == p)//p本来是pa的左孩子
        {
            pa->leftchild = child;
        }
        else
        {
            pa->rightchild = child;
        }
    }
    free(p);
    return true;
}

下一节:二叉平衡树...

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值