数据结构-动态查找表(二叉排序树,插入、删除)

本文介绍如何使用C++实现二叉查找树,包括创建树、插入节点、搜索节点及删除节点的步骤,并通过实例展示了先序遍历的前后变化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#include <iostream>
#include <iomanip>
using namespace std;

typedef int ElemType;
typedef struct Node {
	ElemType data;
	struct Node* lchild, * rchild;//左右孩子
}BiTNode;//二叉树结点
typedef struct {
    BiTNode* root;//根节点
    int num;
}BiTree;//二叉树

bool Search_BST(BiTree T, ElemType key, BiTNode*& fa, BiTNode*& p);//由p返回值为key的二叉树结点,fa返回它的父节点
bool Insert_BST(BiTree& T, ElemType key);
void Create_BST(BiTree& T);//建立二叉查找树
void Delete_BST(BiTree& T, ElemType key);

void Create_BST(BiTree& T) {
    cout << "输入结点个数:" << endl;
    int n;  cin >> n;
    if (n <= 0)return;
    T.num = 0; T.root = NULL;//初始化二叉树根节点为空,结点数目为0
    cout << "输入结点关键字值:";
    ElemType e;
    for (int i = 0; i < n; i++) {
        cin >> e;
        Insert_BST(T, e);
    }
}
bool Insert_BST(BiTree& T, ElemType key){
    BiTNode* fa, * p;
    if (Search_BST(T, key, fa, p))//返回父节点和key所在的p结点,若key已经存在与二叉树内,则不用再插入
        return 0;
    else {
        BiTNode* newNode = new BiTNode;//创建新结点
        if (!newNode)exit(0);
        newNode->data = key;
        newNode->rchild = newNode->lchild = NULL;//初始化新结点左右子树为空
        if (!fa)//若未找到key,且返回的父节点为空,则插入的即是父节点
            T.root = newNode;
        else if (fa->data > key)//若插入值较小则放在二叉树左边
            fa->lchild = newNode;
        else
            fa->rchild = newNode;//若插入值较大则放在二叉树右边
        T.num++;
        return true;
    }
}
bool Search_BST(BiTree T, ElemType key, BiTNode*& fa, BiTNode*& p){
    p = T.root; fa = NULL;
    while (p) {
        if (p->data == key)
            return true;
        else if (p->data > key) {
            fa = p;
            p = p->lchild;
        }
        else {
            fa = p;
            p = p->rchild;
        }
    }
    return false;
}
void Delete_BST(BiTree& T, ElemType key) {
    BiTNode* fa, * p;
    Search_BST(T, key, fa, p);
    //T有两棵非空子树。可以选择将该结点元素替换成它的左子树的最大元素或右子树的最小元素
    //(代码中采用的是前者,即用左子树的最大元素替换被删除的节点),然后在删除被替换的元素。
    if (p->lchild && p->rchild) {//若p结点左右子树均存在
        BiTNode* q = p;
        BiTNode* s = p->lchild;
        while (s->rchild) {//找到了s结点,它的值比为p结点小的结点中最大的,它的父节点是q
            q = s;
            s = s->rchild;
        }
        p->data = s->data;//将这个值提上来
        if (q != p)//s即左子树的最大值点,它的父节点q与结点p不是同一结点,
            //也就是说经历了while循环,s是q的右子树,因此s比q大,s的左子树要挂在q的右子树上
            q->rchild = s->lchild;
        else//s即左子树的最大值点,它的父节点q与结点p是同一结点,
            //也就是说只经历了初始化赋值,s是q的左子树,因此s比q小,s的左子树要挂在q的左子树上
            q->lchild = s->lchild;
        delete s;//s的值已经赋给了p,删除s
    }
    else {//若p结点左右子树并非均存在
        //因此找到p结点的唯一子树,q是唯一子树的父节点,即被删除结点
        BiTNode* q = NULL;
        if (!p->lchild) {//左子树不存在,唯一子树就是右子树
            q = p;
            p = p->rchild;
        }
        else{//左子树存在,唯一子树就是左子树
            q = p;
            p = p->lchild;
        }
        if (!fa)//若被删除结点p没有父节点,证明p是根节点,删除根节点后它的唯一子树就是新的根节点
            //(在这个条件分支中被删除的结点左右子树并非均存在)
            T.root = p;
        else {//被删除结点不是根节点
            if (fa->lchild == q)//此时的q是被删除结点,那么接下来就很显然了
                fa->lchild = p;
            else
                fa->rchild = p;
        }
        delete q;
    }
    T.num--;
}
void preorder(BiTNode* p) {
    if (!p)
        return;
    cout << setw(4) << p->data;
    preorder(p->lchild);
    preorder(p->rchild);
}
void Preorder(BiTree T) {
    cout << setw(4) << T.root->data;
    preorder(T.root->lchild);
    preorder(T.root->rchild);
}



int main()
{
    BiTree T;
    Create_BST(T);//建立二叉查找树;
    cout << "\n删除前先序遍历:";
    Preorder(T);//先序遍历
    ElemType key;
    cout << "\n输入要查找的元素的关键字:" << endl;
    cin >> key;
    BiTNode* p, * fa;
    if (Search_BST(T, key, fa, p)) {
        cout << p->data << "找到了!" << endl;
        Delete_BST(T, p->data);
        cout << "删除后先序遍历:";
        Preorder(T);//先序遍历
    }
    else {
        cout << "没找到!" << endl;
    }
    return 0;
}

实验样例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

菜菜的大鹏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值