数据结构-二叉搜索树

特点

1.若任意结点的左子树不空,则左子树上所有结点的值均不大于它的根结点的值。
2. 若任意结点的右子树不空,则右子树上所有结点的值均不小于它的根结点的值。
3.任意结点的左、右子树也分别为二叉搜索树
就如这棵树 假设数列是{12,5,18,2,9,15,19,17,16}
先拿出12作为根节点
再拿出5 发现比12小 就放在左子结点
再拿18 发现比12大就放在右子结点
再拿2 先与12比较 发现比12小 就再与12的左节点比较 发现比5小 就放在5的左子结点
再拿9 先与12比较 发现比12小 就再与12的左节点比较 发现比5大 就放在5的右结点
注意17的位置 他跟18比较 发现比18小就和18的左节点比较 发现比15大 此时不会挤掉15 而是放在15的右结点
在这里插入图片描述
如果用中序遍历就会看到一个 递增序列

代码实现

/*先创建二叉树结构体*/
typedef struct treenode    /*二叉排序树的结点类型*/
{
    KeyType key;        /*关键字*/
    struct treenode* lchild, * rchild;  /*左、右孩子指针*/
}BTNode,*BTree;
/* BTree tree 等价于 BTNode * node 这里写*BTree主要是指向根节点 方便遍历*/


BTNode* NewNode(int data)   //创建一个新的节点
{
    BTNode* New = (BTNode*)malloc(sizeof(BTNode));//给新节点分配空间
    if (nullptr == New)
    {
        exit(0);
    }
    New->key = data;//将值赋值给新节点
    New->lchild = nullptr;//将左右子结点设置为空
    New->rchild = nullptr;
    return New;//返回新节点的地址
}

void DispBStree(BTNode* bt)
{  /*用广义表显示二叉排序树函数*///应该是用中序遍历显示一个有序数列
    if (NULL != bt)
    {
        DispBStree(bt->lchild);
        printf("%d ", bt->key);
        DispBStree(bt->rchild);
    }
}

/*bst是根节点 key是要查找的目标值 f是啥 p是最终返回的指针 如果找到了 就返回结点指针 如果没找到 就返回叶子节点的位置 方便插入新节点*/
bool Search(BTree bst, KeyType key, BTree f, BTree* p)  //查找成功时,p指向值为key的节点。如果查找失败,则p指向遍历的最后一个节点
{
    if (!bst)
    {
        *p = f;
        return false;
    }
    if (bst->key == key)  //查找成功,直接返回
    {
        *p = bst;//如果找到了 则返回结点指针
        return true;
    }
    else if (bst->key < key)//如果查找值大于结点值 则找右结点
    {
        return Search(bst->rchild, key, bst, p);
    }
    return Search(bst->lchild, key, bst, p);//如果查找值小于结点则查找左节点
}
BTNode* BSTInsert(BTNode* bst, KeyType key)
{  /*二叉排序树的元素插入函数*/
    if (bst->key == NULL)  //首先判断这棵树是不是一个空树 如果是空树就创建结点
    {
        bst = NewNode(key);
        return bst;//返回根节点地址 结束插入
    }
    /*如果不是空树*/
    BTNode* p;
    //先在二叉排序树中查找要插入的值是否已经存在
    if (!Search(bst, key, NULL, &p))  //如果要插入的值不在,则插入;此时p一定指向遍历的最后一个叶子节点
    {
        BTNode* pNew = NewNode(key);//创建一个新节点
        if (key < p->key)  //将s作为p的左孩子
        {
            p->lchild = pNew;
        }
        else if (key > p->key)  //将s作为p的右孩子
        {
            p->rchild = pNew;
        }
        return bst;  //插入成功
    }
    else
    {
        printf("\nThe node(%d) already exists.\n", key);
    }
    return bst;
}

BTNode* CreateBST(KeyType str[], int n)
{  /*建立二叉排序树函数*/
    BTNode* root = new BTNode;
    root = NewNode(str[0]);
    for (int i = 1;i<n;i++)
    {
        BSTInsert(root, str[i]);
    }
    return root;
}

int Delete(BTree* p)
{
    BTree q, s;
    //情况 1,结点 p 本身为叶子结点,直接删除即可
    if (!(*p)->lchild && !(*p)->rchild) {
        *p = NULL;
    }
    else if (!(*p)->lchild) { //左子树为空,只需用结点 p 的右子树根结点代替结点 p 即可;
        q = *p;
        *p = (*p)->rchild;
        free(q);
    }
    else if (!(*p)->rchild) {//右子树为空,只需用结点 p 的左子树根结点代替结点 p 即可;
        q = *p;
        *p = (*p)->lchild;//这里不是指针 *p 指向左子树,而是将左子树存储的结点的地址赋值给指针变量 p
        free(q);
    }
    else {//左右子树均不为空,采用第 2 种方式
        q = *p;
        s = (*p)->lchild;
        //遍历,找到结点 p 的直接前驱
        while (s->rchild)
        {
            q = s;
            s = s->rchild;
        }
        //直接改变结点 p 的值
        (*p)->key = s->key;
        //判断结点 p 的左子树 s 是否有右子树,分为两种情况讨论
        if (q != *p) {
            q->rchild = s->lchild;//若有,则在删除直接前驱结点的同时,令前驱的左孩子结点改为 q 指向结点的孩子结点
        }
        else {
            q->lchild = s->lchild;//否则,直接将左子树上移即可
        }
        free(s);
    }
    return true;
}
BTNode* BSTDelete(BTNode* bt, KeyType  k)
{   /*在二叉排序树t中删除关键字为k的节点函数*/
    if (!bt) {//不存在关键字等于key的数据元素
        return bt;
    }
    else
    {
        if (k == bt->key) {
            Delete(&bt);
            return bt;
        }
        else if (k < bt->key) {
            //使用递归的方式
            return BSTDelete(bt->lchild, k);
        }
        else {
            return BSTDelete(bt->rchild, k);
        }
    }
}

BTNode* BSTSearch(BTNode* bt, KeyType k)//如果没找到怎么办
{  /*二叉排序树的元素查找函数*/
    if (nullptr == bt)//如果查找的是空树直接结束
    {
        return nullptr;
    }
    if (bt->key == k)//如果当前结点的值是要找的值 则返回当前结点
    {
        return bt;
    }
    else if (nullptr != bt->lchild)//如果左节点不为空 则对左节点进行对比
    {
        BSTSearch(bt->lchild, k);
    }
    else if (nullptr != bt->rchild)//如果右结点不为空 则对右结点进行对比
    {
        BSTSearch(bt->rchild, k);
    }
    
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值