数据结构——二叉搜索树

2023-09-18 13:43:31

二叉搜索树是二叉树的一种特殊形式。 二叉搜索树具有以下性质:
1.每个节点中的值必须大于(或等于)其左侧子树中的任何值
2.每个节点中的值必须小于(或等于)其右侧子树中的任何值。
在这里插入图片描述
像普通的二叉树一样,我们可以按照前序、中序和后序来遍历一个二叉搜索树。 但是值得注意的是,对于二叉搜索树,我们可以通过中序遍历得到一个递增的有序序列。因此,中序遍历是二叉搜索树中最常用的遍历方法。

二叉树搜索:
1.如果目标值等于节点的值,则返回节点;
2.如果目标值小于节点的值,则继续在左子树中搜索;
3.如果目标值大于节点的值,则继续在右子树中搜索。

二叉树插入:
1.根据节点值与目标节点值的关系,搜索左子树或右子树;
2.重复步骤 1 直到到达外部节点;
3.根据节点的值与目标节点的值的关系,将新节点添加为其左侧或右侧的子节点。

二叉树删除:

  1. 如果目标节点没有子节点,我们可以直接移除该目标节点。
  2. 如果目标节只有一个子节点,我们可以用其子节点作为替换。
  3. 如果目标节点有两个子节点,我们需要用其中序后继节点或者前驱节点来替换,再删除该目标节点。
#include <iostream>

// 定义二叉搜索树节点
struct TreeNode {
    int data;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int val) : data(val), left(nullptr), right(nullptr) {}
};

class BinarySearchTree {
private:
    TreeNode* root;

    // 插入节点的辅助函数
    TreeNode* insert(TreeNode* node, int val) {
        if (node == nullptr) {
            return new TreeNode(val);
        }

        if (val < node->data) {
            node->left = insert(node->left, val);
        } else if (val > node->data) {
            node->right = insert(node->right, val);
        }

        return node;
    }

    // 中序遍历的辅助函数
    void inorderTraversal(TreeNode* node) {
        if (node == nullptr) {
            return;
        }

        inorderTraversal(node->left);
        std::cout << node->data << " ";
        inorderTraversal(node->right);
    }

    // 查找最小值的辅助函数
    TreeNode* findMin(TreeNode* node) {
        while (node->left != nullptr) {
            node = node->left;
        }
        return node;
    }

    // 删除节点的辅助函数
    TreeNode* remove(TreeNode* node, int val) {
        if (node == nullptr) {
            return node;
        }

        if (val < node->data) {
            node->left = remove(node->left, val);
        } else if (val > node->data) {
            node->right = remove(node->right, val);
        } else {
            if (node->left == nullptr) {
                TreeNode* temp = node->right;
                delete node;
                return temp;
            } else if (node->right == nullptr) {
                TreeNode* temp = node->left;
                delete node;
                return temp;
            }

            TreeNode* temp = findMin(node->right);
            node->data = temp->data;
            node->right = remove(node->right, temp->data);
        }

        return node;
    }

public:
    BinarySearchTree() : root(nullptr) {}

    // 插入节点
    void insert(int val) {
        root = insert(root, val);
    }

    // 搜索节点
    bool search(int val) {
        TreeNode* current = root;
        while (current != nullptr) {
            if (current->data == val) {
                return true;
            } else if (val < current->data) {
                current = current->left;
            } else {
                current = current->right;
            }
        }
        return false;
    }

    // 删除节点
    void remove(int val) {
        root = remove(root, val);
    }

    // 中序遍历
    void inorderTraversal() {
        inorderTraversal(root);
        std::cout << std::endl;
    }
};

int main() {
    BinarySearchTree bst;
    bst.insert(50);
    bst.insert(30);
    bst.insert(70);
    bst.insert(20);
    bst.insert(40);
    bst.insert(60);
    bst.insert(80);

    std::cout << "Inorder Traversal: ";
    bst.inorderTraversal();

    std::cout << "Search 60: " << (bst.search(60) ? "Found" : "Not Found") << std::endl;
    std::cout << "Search 90: " << (bst.search(90) ? "Found" : "Not Found") << std::endl;

    bst.remove(30);
    std::cout << "Inorder Traversal after removing 30: ";
    bst.inorderTraversal();

    return 0;
}

更多推荐

Vue2+Vue3基础入门到实战项目全套教程的学习笔记

内容的视频链接点击此处可进入这套笔记是按照视频和视频笔记总结的笔记,主要是方便vue的学习或温习,基本抛弃css样式的添加,专注于vue的使用。第一天Vue快速上手Vue的概念Vue是一个用于构建用户界面的渐进式框架创建实例el指定挂载点,选择器指定控制的是哪个盒子插值表达式{{}}利用表达式进行插值,渲染到页面中(表

【Node.js】定时任务cron:

文章目录一、文档:【Nodejs插件】二、安装与使用【1】安装【2】使用三、cron表达式:{秒数}{分钟}{小时}{日期}{月份}{星期}{年份(可为空)}四、案例:一、文档:【说明文档】https://www.npmjs.com/package/cron【Cron表达式生成器】http://www.bejson.c

使用烧瓶的简单电子商务API

一、说明让我们试一试烧瓶(Flask)这个模型框架,这个应用程序可让您管理和扩展您的云端业务;它允许管理人员浏览和计算商店的总销售额并从在线商店-服装。二、什么是烧瓶?什么是烧瓶?它是一个Web框架-一个极简主义和轻量级的设计,用于在Python中构建Web应用程序。我们将在网上开设一家服装店。以下是我们的架构:实际实

总结:nginx配置

一、nginxrewrite与proxy_pass区别rewrite和proxy_pass都是Nginx的常用指令,但它们的功能和使用场景有所不同。1、rewrite:是一个用来修改请求URI的指令。在Nginx收到一个请求后,rewrite指令可以基于特定的条件改变这个请求的URI,可能是改变文件路径,可能是重定向到

视频如何压缩?视频压缩到100M以内这样做

在日常生活中,我们常常需要处理各种各样的视频文件,但往往视频的大小会给我们的存储和传输带来困扰。那么,如何有效地压缩视频呢?下面就给大家分享三种解决方法,一起来看看吧。方法一:嗨格式压缩大师这是一款功能强大的视频压缩工具,它不仅支持多种格式的视频压缩,还具备高质量的输出效果和极快的压缩速度1、打开嗨格式压缩大师,在几个

成集云 | 金蝶云星空集成聚水潭ERP(金蝶云星空主管供应链)| 解决方案

源系统成集云目标系统方案介绍金蝶云星空是金蝶软件(中国)有限公司研发的新一代战略性企业管理软件,致力于为企业提供端到端的供应链整体解决方案,它可以帮助企业构建敏捷供应链体系,降低供应链成本,提高企业利润。此外,金蝶云星空还可以实现高效组织协作,支持多种模式、多场景、多类别的过程精细化管控,满足企业对库存进行批号、保质期

在 Vue 项目中添加字典翻译工具(二)

封装字段翻译组件,可以格式化字典、枚举、字段优点:使用简单,一次配置多次使用,缓存降低后端请求次数,扩展性强store的fieldFormat.js(这里用的store的modules)exportdefault{namespaced:true,state:{types:{}},mutations:{ADD_TYPE:

Spring Bean循环依赖学习与探究

文章目录原理学习源码溯源本文参考:画图带你彻底弄懂三级缓存和循环依赖的问题Spring三级缓存解决bean循环依赖,为何用三级缓存而非二级_笑矣乎的博客-CSDN博客Spring为何需要三级缓存解决循环依赖,而不是二级缓存?_石杉的架构笔记的博客-CSDN博客原理学习主要的三级缓存工作机理学习参考画图带你彻底弄懂三级缓

php在header增加key,sign,timestamp,实现鉴权

在PHP中,您可以通过在HTTP请求的Header中增加Key、Sign和Timestamp等信息来进行安全性鉴权。以下是一种基本的思路和示例,用于说明如何实现这种鉴权机制:生成Key和Sign:服务端和客户端之间共享一个密钥(Key)。当客户端发起请求时,它需要使用密钥生成一个签名(Sign)。签名可以使用加密算法(

数据库JDBC编程

JDBCJDBC是干啥的呢?简单来说就是用java代码操作数据库各种数据库,在开发的时候,就会提供一组编程接口(API)API:ApplicationProgramInterface简单来说就是有个软件,这个软件给你一些功能,你基于这些功能能对这个软件干啥API往往是以函数,类的形式来提供的,说白了就是这个API在这个

130. 被围绕的区域

130.被围绕的区域题目-中等难度示例1.新建board+bfs2.哈希+bfs题目-中等难度给你一个mxn的矩阵board,由若干字符‘X’和‘O’,找到所有被‘X’围绕的区域,并将这些区域里所有的‘O’用‘X’填充。示例示例1:输入:board=[[“X”,“X”,“X”,“X”],[“X”,“O”,“O”,“X”

热文推荐