二叉搜索树的应用(C++实现 附源码)

本文介绍了二叉排序树的基本概念,包括其性质和构建方法。通过示例详细阐述了如何构建以数字8为根的二叉排序树,以及如何进行搜索和删除节点的操作。在删除节点时,讨论了不同情况下的处理策略,如无子节点、单子节点和双子节点的情况。最后提供了一段C++代码实现二叉排序树的插入、搜索和删除功能。
摘要由CSDN通过智能技术生成

目录

二叉排序树的概念

二叉排序树的构建

二叉排序树的搜索

二叉排序树的删除


1.什么是二叉排序树?

二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树

性质:

一棵空树,或者是具有下列性质的二叉树

(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

(3)左、右子树也分别为二叉排序树;

2.二叉排序树如何构建?

假设有8 4 2 5 10 9 13一系列数字,要求以8为根结底构造二叉排序树

 要清楚构建二叉排序树就是一个一个插入节点的过程,要找到待插节点的前一个位置,用prev表示,若待插节点比prev大,则插到prev右边,否则插到prev左边;

问题进一步简化,变成了如何找prev节点?

   Node*temp=root;
    Node*prev=NULL;
    while(temp!=NULL){
        prev=temp;
        if(key<temp->data){
            temp=temp->left;
        }
        else if(key>temp->data){
            temp=temp->right;
        }
        else return;//排除相等的存在
    }

插入节点完整代码化

void Insert(int key){//插入每个节点时都是从根开始遍历一遍
    Node*temp=root;
    Node*prev=NULL;
    while(temp!=NULL){
        prev=temp;
        if(key<temp->data){
            temp=temp->left;
        }
        else if(key>temp->data){
            temp=temp->right;
        }
        else return;//排除相等的存在
    }
    if(key<prev->data){
        prev->left=(Node*)malloc(sizeof(Node));
        prev->left->data=key;
        prev->left->left=NULL;
        prev->left->right=NULL;
    }
    if(key>prev->data){
        prev->right=(Node*)malloc(sizeof(Node));
        prev->right->data=key;
        prev->right->left=NULL;
        prev->right->right=NULL;
    }
}

3.二叉排序树如何搜索?

二叉排序树的搜索过程有一点类似于二分查找,最好的情况下时间复杂度为O(logn)。查找其实很简单,从根节点root开始,如果关键字Key小于根节点的值,那么查找根的左子树;否则,查找根的右子树。

bool search(int key){
    Node*temp=root;
    while(temp!=NULL){
        if(key==temp->data) return true;//找到
        if(key<temp->data) temp=temp->left;//查找左子树
        if(key>temp->data) temp=temp->right;//查找右子树

    }
    return false;
}

4.二叉排序树节点删除?

接下来要说说比较麻烦的删除操作:删除某个节点后,要保证剩下的节点仍然是一棵二叉排序树。

删除操作分为三种情况:

(1)假设待删除节点D只有右孩子,没有左孩子。那么只要将要删除结点D的右孩子赋值给节点D,然后删除右孩子节点。

(2)假设待删除节点D只有左孩子,没有右孩子。那么只要将要删除结点D的左孩子赋值给节点D,然后删除右孩子节点。

例如要删除节点10,操作如下

 

 (3)假设待删除节点既有左孩子又有右孩子。

 假设删除节点8,

我们的目标依然是要保证删除结点8后,再次中序遍历它,仍不改变其升序的排列方式。 那么我们需要用5替换原来的位置

为什么需要用5替换8的位置?先对这棵树中序遍历看看 2 4 5 8 9 10 13 ,8前面的数是5,删除8后我们期望得到2 4 5  9 10 13的中序遍历序列,因此要用5覆盖掉8,再把原来5节点删除。

对代码的解释说明:

(1)在删除节点时,使用了指向指针的引用Node*&node,以便能够修改指向指针的值,避免了在函数中使用临时指针的情况。

(2)delete node; node = temp;这两句代码,将node空间释放了,为什么还能给nodes赋值?

delete node; 是用来释放待删除节点的内存空间的操作。然后 node = temp; 是将左子树中值最大的节点(即temp)赋值给待删除节点(即node),以实现节点的替换。这里注意的是,释放内存空间并不会立即将指针变量的值置为NULL,而是保持原有的指向。在这种情况下,node = temp; 将node指向了左子树中的新节点,以确保树的结构仍然正确。

int del(Node*& node, int key) {
    if (node == NULL) return -1;
    if (key < node->data) {
        return del(node->left, key);
    }
    else if (key > node->data) {
        return del(node->right, key);
    }
    else {
        if (node->left == NULL) {
            Node* temp = node->right;
            delete node;
            node = temp;
        }
        else if (node->right == NULL) {
            Node* temp = node->left;
            delete node;
            node = temp;
        }
        else {
            Node* temp = node->left;
            Node* prev = node;
            while (temp->right != NULL) {
                prev = temp;
                temp = temp->right;
            }
            node->data = temp->data;
            del(prev->right, temp->data);//递归删除用来覆盖待删除节点值的节点
        }
    }
    return 0;
}

完整代码

#include <bits/types/struct_tm.h>
#include <cstdlib>
#include<iostream>
#include <memory>
#include <ostream>
#include <type_traits>
using namespace std;
typedef struct SortTree{
    int data;
    struct SortTree*left;
    struct SortTree*right;
}Node,*Tree;
Tree root;
void Init(int key){//初始化根节点
    root=(Node*)malloc(sizeof(Node));
    root->data=key;
    root->left=NULL;
    root->right=NULL;
}
void Insert(int key){//插入每个节点时都是从根开始遍历一遍
    Node*temp=root;
    Node*prev=NULL;
    while(temp!=NULL){
        prev=temp;
        if(key<temp->data){
            temp=temp->left;
        }
        else if(key>temp->data){
            temp=temp->right;
        }
        else return;//排除相等的存在
    }
    if(key<prev->data){
        prev->left=(Node*)malloc(sizeof(Node));
        prev->left->data=key;
        prev->left->left=NULL;
        prev->left->right=NULL;
    }
    if(key>prev->data){
        prev->right=(Node*)malloc(sizeof(Node));
        prev->right->data=key;
        prev->right->left=NULL;
        prev->right->right=NULL;
    }
}
void show(Node *p){//中序遍历输出二叉排序树结果
    if(p!=NULL){
        show(p->left);
        cout<<p->data<<" ";
        show(p->right);
    }
}
bool search(int key){
    Node*temp=root;
    while(temp!=NULL){
        if(key==temp->data) return true;
        if(key<temp->data) temp=temp->left;
        if(key>temp->data) temp=temp->right;

    }
    return false;
}

int del(Node*& node, int key) {
    if (node == NULL) return -1;
    if (key < node->data) {
        return del(node->left, key);
    }
    else if (key > node->data) {
        return del(node->right, key);
    }
    else {
        if (node->left == NULL) {
            Node* temp = node->right;
            delete node;
            node = temp;
        }
        else if (node->right == NULL) {
            Node* temp = node->left;
            delete node;
            node = temp;
        }
        else {
            Node* temp = node->left;
            Node* prev = node;
            while (temp->right != NULL) {
                prev = temp;
                temp = temp->right;
            }
            node->data = temp->data;
            del(prev->right, temp->data);
        }
    }
    return 0;
}



int main(){
    int r;
    int q;
    cout<<"请输入根节点的值:"<<endl;
    cin>>r;
    Init(r);
    int x;
    int y;
    cout<<"请输入等待插入的节点的值(按-1结束)"<<endl;
    cin>>x;
    while(x!=-1){
        Insert(x);
        cin>>x;
    }
    cout<<"请输入要查询的值:"<<endl;
    cin>>q;
    if(search(q)) cout<<"存在"<<endl;
    else cout<<"查询失败"<<endl;
    show(root);
    puts("");
    cout<<"请输入待删除节点:"<<endl;
    cin>>y;
   if(del(root,y)==0) {
        show(root);
   }else{
       cout<<"删除失败"<<endl;
   }
   return 0;
}
/*
请输入根节点的值:
8
请输入等待插入的节点的值:
4 2 5 10 9 13 -1
请输入要查询的值:
4
存在
2 4 5 8 9 10 13
请输入待删除节点:
8
2 4 5 9 10 13
*/

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值