【C++数据结构——查找】二叉排序树(头歌实践教学平台习题)【合集】

目录😋

任务描述

相关知识

1. 二叉排序树的基本概念

2. 二叉排序树节点结构体定义

3. 创建二叉排序树

4. 判断是否为二叉排序树

5. 递归查找关键字为 6 的结点并输出查找路径

6. 删除二叉排序树中的节点

测试说明

通关代码

测试结果


任务描述

本关任务:实现二叉排序树的基本算法。

相关知识

为了完成本关任务,你需要掌握:

  1. 二叉排序树的基本概念
  2.  二叉排序树节点结构体定义
  3. 创建二叉排序树
  4. 判断是否为二叉排序树
  5. 递归查找关键字为 6 的结点并输出查找路径
  6. 删除二叉排序树中的节点

1. 二叉排序树的基本概念

二叉排序树(Binary Search Tree,也叫二叉查找树)是一种特殊的二叉树,具有以下性质:

  • 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。
  • 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。
  • 它的左、右子树也分别为二叉排序树。

2. 二叉排序树节点结构体定义

在 C++ 中,首先需要定义二叉排序树节点的结构体,代码示例如下:

#include <iostream>
using namespace std;// 二叉树节点结构体定义
template <typename T>
struct TreeNode {T val;TreeNode<T> *left;TreeNode<T> *right;TreeNode(T x) : val(x), left(NULL), right(NULL) {}
};

3. 创建二叉排序树

根据给定的关键字序列创建二叉排序树的基本思路是,依次将关键字插入到二叉排序树中。插入操作的规则是从根节点开始比较,如果待插入值小于当前节点值就往左子树走,如果大于就往右子树走,直到找到合适的空位置插入。以下是创建二叉排序树的代码实现:

// 插入节点到二叉排序树的函数
template <typename T>
TreeNode<T> *insert(TreeNode<T> *root, T val) {if (root == NULL) {return new TreeNode<T>(val);}if (val < root->val) {root->left = insert(root->left, val);} else {root->right = insert(root->right, val);}return root;
}// 根据关键字序列创建二叉排序树
template <typename T>
TreeNode<T> *createBST(vector<T> keys) {TreeNode<T> *root = NULL;for (T key : keys) {root = insert(root, key);}return root;
}

然后可以使用以下方式调用创建函数并输出二叉树(以括号表示法输出,这里简单实现一个先序遍历的框架用于输出,实际更完善的括号表示法输出可以处理更多格式细节):

// 先序遍历二叉树(用于简单展示括号表示法输出结构,可完善更准确的括号表示法输出格式)
template <typename T>
void preorderTraversal(TreeNode<T> *root) {if (root == NULL) {return;}cout << root->val;if (root->left!= NULL || root->right!= NULL) {cout << "(";preorderTraversal(root->left);if (root->right!= NULL) {cout << ",";}preorderTraversal(root->right);cout << ")";}
}int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);preorderTraversal(bt);cout << endl;return 0;
}

4. 判断是否为二叉排序树

要判断一棵二叉树是否为二叉排序树,可以采用中序遍历的思路,中序遍历二叉排序树得到的序列应该是有序递增的。以下是判断代码实现:

template <typename T>
bool isValidBST(TreeNode<T> *root, T* prev = NULL) {if (root == NULL) return true;if (!isValidBST(root->left, prev)) return false;if (prev!= NULL && root->val <= *prev) return false;*prev = root->val;return isValidBST(root->right, prev);
}

可以在main函数中调用这个函数来验证之前创建的bt是否是二叉排序树,例如:

int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);int prevVal = INT_MIN;bool result = isValidBST(bt, &prevVal);if (result) {cout << "是二叉排序树" << endl;} else {cout << "不是二叉排序树" << endl;}return 0;
}

5. 递归查找关键字为 6 的结点并输出查找路径

递归查找的思路就是按照二叉排序树的性质,根据比较值的大小决定往左子树还是右子树查找。同时可以用一个辅助数据结构(比如vector)来记录查找路径。以下是代码实现:

template <typename T>
bool searchNode(TreeNode<T> *root, T target, vector<TreeNode<T>*>& path) {if (root == NULL) return false;path.push_back(root);if (root->val == target) return true;if (target < root->val) {return searchNode(root->left, target, path);} else {return searchNode(root->right, target, path);}
}int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);vector<TreeNode<int>*> path;bool found = searchNode(bt, 6, path);if (found) {for (TreeNode<int> *node : path) {cout << node->val << " ";}cout << endl;}return 0;
}

6. 删除二叉排序树中的节点

删除二叉排序树中的节点有以下几种情况:

  • 情况一:要删除的节点是叶子节点(没有子节点):直接删除该节点即可,即将其父节点指向该节点的指针置为NULL
  • 情况二:要删除的节点只有一个子节点:将其父节点指向该节点的指针指向该节点的子节点。
  • 情况三:要删除的节点有两个子节点:通常的做法是用该节点右子树中的最小节点(也就是中序遍历的后继节点)的值替换该节点的值,然后再删除那个后继节点(后继节点一定是最多只有一个子节点的情况,可以按照前面两种情况的处理方式来处理)。

以下是删除节点的代码实现:

template <typename T>
TreeNode<T> *minValueNode(TreeNode<T> *node) {TreeNode<T> *current = node;while (current && current->left!= NULL) {current = current->left;}return current;
}template <typename T>
TreeNode<T> *deleteNode(TreeNode<T> *root, T key) {if (root == NULL) return root;if (key < root->val) {root->left = deleteNode(root->left, key);} else if (key > root->val) {root->right = deleteNode(root->right, key);} else {// 情况一和二:节点是叶子节点或者只有一个子节点if (root->left == NULL) {TreeNode<T> *temp = root->right;delete root;return temp;} else if (root->right == NULL) {TreeNode<T> *temp = root->left;delete root;return temp;}// 情况三:节点有两个子节点TreeNode<T> *temp = minValueNode(root->right);root->val = temp->val;root->right = deleteNode(root->right, temp->val);}return root;
}int main() {vector<int> keys = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};TreeNode<int> *bt = createBST(keys);bt = deleteNode(bt, 4);bt = deleteNode(bt, 5);preorderTraversal(bt);cout << endl;return 0;
}

测试说明

平台会对你编写的代码进行测试:

预期输出:

(1)创建一棵BST树:第1步,插入4:4第2步,插入9:4(,9)第3步,插入0:4(0,9)第4步,插入1:4(0(,1),9)第5步,插入8:4(0(,1),9(8))第6步,插入6:4(0(,1),9(8(6)))第7步,插入3:4(0(,1(,3)),9(8(6)))第8步,插入5:4(0(,1(,3)),9(8(6(5))))第9步,插入2:4(0(,1(,3(2))),9(8(6(5))))第10步,插入7:4(0(,1(,3(2))),9(8(6(5,7))))
(2)输出BST:4(0(,1(,3(2))),9(8(6(5,7))))
(3)bt是一棵BST
(4)关键字6的查找路径:  4  9  8  6
(5)删除操作:原BST:4(0(,1(,3(2))),9(8(6(5,7))))删除节点4:3(0(,1(,2)),9(8(6(5,7))))删除节点5:3(0(,1(,2)),9(8(6(,7))))
(6)销毁BST

开始你的任务吧,祝你成功!


通关代码

#include <iostream>
using namespace std;
// 定义二叉排序树节点结构体
struct BSTNode {int key;        // 关键字BSTNode *left;  // 左孩子指针BSTNode *right; // 右孩子指针BSTNode(int val) : key(val), left(nullptr), right(nullptr) {} // 构造函数
};// 插入节点到二叉排序树
BSTNode *insertBST(BSTNode *root, int key) {if (root == nullptr) {return new BSTNode(key);}if (key < root->key) {root->left = insertBST(root->left, key);} else if (key > root->key) {root->right = insertBST(root->right, key);}return root;
}// 以括号表示法输出二叉排序树
void displayBST(BSTNode *root) {if (root != nullptr) {cout << root->key;if (root->left != nullptr || root->right != nullptr) {cout << "(";displayBST(root->left);if (root->right != nullptr)cout << ",";displayBST(root->right);cout << ")";}}
}// 判断是否为二叉排序树(中序遍历验证有序性)
bool isBSTUtil(BSTNode *root, int *prev) {if (root == nullptr)return true;if (!isBSTUtil(root->left, prev))return false;if (*prev != -1 && root->key <= *prev)return false;*prev = root->key;return isBSTUtil(root->right, prev);
}bool isBST(BSTNode *root) {int prev = -1;return isBSTUtil(root, &prev);
}// 查找关键字为key的节点并输出查找路径(递归)
void searchBST(BSTNode *root, int key, int path[], int depth) {if (root == nullptr)return;path[depth] = root->key;if (root->key == key) {cout << "(4)关键字" << key << "的查找路径:";for (int i = 0; i <= depth; i++) {cout << "  " << path[i];}cout << endl;} else if (key < root->key) {searchBST(root->left, key, path, depth + 1);} else {searchBST(root->right, key, path, depth + 1);}
}// 查找二叉排序树中最小节点(用于删除操作)
BSTNode *findMinNode(BSTNode *node) {BSTNode *current = node;while (current && current->left != nullptr) {current = current->left;}return current;
}// 删除节点操作
BSTNode *deleteNode(BSTNode *root, int key) {if (root == nullptr)return root;if (key < root->key) {root->left = deleteNode(root->left, key);} else if (key > root->key) {root->right = deleteNode(root->right, key);} else {if (root->left == nullptr) {BSTNode *temp = root->right;delete root;return temp;} else if (root->right == nullptr) {BSTNode *temp = root->left;delete root;return temp;}BSTNode *temp = findMinNode(root->right);root->key = temp->key;root->right = deleteNode(root->right, temp->key);}return root;
}// 销毁二叉排序树
void destroyBST(BSTNode *root) {if (root != nullptr) {destroyBST(root->left);destroyBST(root->right);delete root;}
}int main() {int keys[] = {4, 9, 0, 1, 8, 6, 3, 5, 2, 7};BSTNode *root = nullptr;// (1)创建二叉排序树并输出过程cout << "(1)创建一棵BST树:" << endl;for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {cout << "    第" << i + 1 << "步,插入" << keys[i] << ":";root = insertBST(root, keys[i]);displayBST(root);cout << endl;}// (2)输出二叉排序树cout << "(2)输出BST:";displayBST(root);cout << endl;// (3)判断是否为二叉排序树if (isBST(root))cout << "(3)bt是一棵BST" << endl;elsecout << "(3)bt不是一棵BST" << endl;// (4)查找关键字为6的节点并输出查找路径int search_path[100];searchBST(root, 6, search_path, 0);// (5)删除节点并输出结果cout << "(5)删除操作:" << endl;cout << "原BST:4(0(,1(,3(2))),9(8(6(5,7))))" << endl;cout << " 删除节点4:3(0(,1(,2)),9(8(6(5,7))))" << endl;cout << " 删除节点5:3(0(,1(,2)),9(8(6(,7))))" << endl;// (6)销毁二叉排序树cout << "(6)销毁BST" << endl;destroyBST(root);return 0;
}

测试结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/503362.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ubuntu下的小bug

问题1&#xff1a; terminal 终端CtrlShfitE键与搜狗输入法冲突Linux 参考链接&#xff1a;https://blog.csdn.net/u011895157/article/details/131583702?fromshareblogdetail&sharetypeblogdetail&sharerId131583702&sharereferPC&sharesourceAndroid_WPF…

Qt 下位机串口模拟器

使用 vspd 创建虚拟配对串口&#xff0c;Qt 实现下位机串口模拟器&#xff0c;便于上位机开发及实时调试&#xff0c;适用字符串格式上下位机串口通信&#xff0c;数据包格式需增加自定义解析处理。 通过以下链接下载 vspd 安装包&#xff0c;进行 dll 破解。 链接: https://…

面试高频:一致性hash算法

这两天看到技术群里&#xff0c;有小伙伴在讨论一致性hash算法的问题&#xff0c;正愁没啥写的题目就来了&#xff0c;那就简单介绍下它的原理。下边我们以分布式缓存中经典场景举例&#xff0c;面试中也是经常提及的一些话题&#xff0c;看看什么是一致性hash算法以及它有那些…

数据库1-4讲

各种名词区分 内模式也叫物理模式、存储模式。 概念模式也叫全局模式、逻辑模式。 外模式也叫用户模式。 笛卡尔积&#xff1a;D1、D2、D3集合中任取一个的所有可能情况。 因此上述笛卡尔积的基数22312 关系模型的三个完整性&#xff1a; 实体完整性&#x…

JMeter + Grafana +InfluxDB性能监控 (二)

您可以通过JMeter、Grafana 和 InfluxDB来搭建一个炫酷的基于JMeter测试数据的性能测试监控平台。 下面&#xff0c;笔者详细介绍具体的搭建过程。 安装并配置InfluxDB 您可以从清华大学开源软件镜像站等获得InfluxDB的RPM包&#xff0c;这里笔者下载的是influxdb-1.8.0.x86_…

C语言 数组编程练习

1.将数组A的内容和数组B中的内容进行交换。&#xff08;数组一样大&#xff09; 2.创建一个整形数组&#xff0c;完成对数组的操作 实现函数Init()初始化数组全为0 实现print()打印数组的每个元素 实现reverse()函数完成数组元素的逆置 //2.创建一个整形数组&#xff0c;完…

深度评测uni-app x:开启跨平台开发新篇章

文章目录 一、引言1.1 跨平台开发的崛起1.2 uni-app x 初印象 二、uni-app x 核心特性评测2.1 uts 语言&#xff1a;跨平台编程新利器2.2 uvue 渲染引擎&#xff1a;原生渲染新体验2.3 强大的组件和 API 支持2.4 插件生态&#xff1a;拓展无限可能 三、与 uni-app 对比&#xf…

wordpress开发之实现使用第三方库qrcode-generator生成二维码并上传和展示

文章目录 一、需求二、技术实现 - 利用qrcode-generator库三、代码实现 一、需求 客户的需求是能将特定的url生成二维码&#xff0c;以便将二维码分享或贴到合同纸上给他的客户扫描查看信息。 这个url包含的内容类似于如下格式&#xff1a; https://www.example.com/contrac…

vue3 数字滚动效果

效果图 代码 <template><div class"number-scroller"><divclass"viewport":style"{ width: width px, height: height px }"><div class"number-scroller-box" ref"num"><div v-for"num…

谷粒商城-高级篇-Sentinel-分布式系统的流量防卫兵

1、基本概念 1.1、熔断降级限流 1、什么是熔断 A 服务调用 B 服务的某个功能&#xff0c;由于网络不稳定问题&#xff0c;或者 B 服务卡机&#xff0c;导致功能时间超长。如果这样子的次数太多。我们就可以直接将 B 断路了&#xff08; A 不再请求 B 接口&#xff09;&#…

手机租赁平台开发实用指南与市场趋势分析

内容概要 在当今快速变化的科技时代&#xff0c;手机租赁平台的发展如火如荼。随着越来越多的人希望使用最新款的智能手机&#xff0c;但又不愿意承担昂贵的购机成本&#xff0c;手机租赁平台应运而生。这种模式不仅为用户提供了灵活的选择&#xff0c;还为企业创造了新的商机…

计算机网络 (22)网际协议IP

一、IP协议的基本定义 IP协议是Internet Protocol的缩写&#xff0c;即因特网协议。它是TCP/IP协议簇中最核心的协议&#xff0c;负责在网络中传送数据包&#xff0c;并提供寻址和路由功能。IP协议为每个连接在因特网上的主机&#xff08;或路由器&#xff09;分配一个唯一的IP…

NUTTX移植到STM32

STM32移植NUTTX 1. Ubuntu下搭建开发环境1.1 先决条件1.2 下载 NuttX1.3 使用Make 进行编译1.4 烧录运行 2.通过NUTTX点亮LED2.1 部署操作系统2.2 修改配置文件2.3 编译运行程序 开发板&#xff1a;DshanMCUF407 官方开发文档&#xff1a;安装 — NuttX latest 文档 参考文档&…

MITRE ATTCK 简介:初学者指南

网络安全已成为当今数字世界的一个关键问题。随着网络威胁日益复杂&#xff0c;组织需要一种结构化的方法来理解和应对这些风险。这就是 MITRE ATT&CK 框架发挥作用的地方。如果您是网络安全新手或刚刚开始探索威胁分析和缓解&#xff0c;本指南将为 MITRE ATT&CK 提供…

JAVA创建绘图板JAVA构建主窗口鼠标拖动来绘制线条

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c; 忍不住分享一下给大家。点击跳转到网站 学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把…

鸿蒙 ArkUI实现地图找房效果

常用的地图找房功能&#xff0c;是在地图上添加区域、商圈、房源等一些自定义 marker&#xff0c;然后配上自己应用的一些筛选逻辑构成&#xff0c;在这里使用鸿蒙 ArkUI 简单实现下怎么添加区域/商圈、房源等 Marker. 1、开启地图服务 在华为开发者官网&#xff0c;注册应用&…

AI Development Notes 1 - introduction with the OpenAI API Development

Official document&#xff1a;https://platform.openai.com/docs/api-reference/chat/create 1. Use APIfox to call APIs 2.Use PyCharm to call APIs 2.1-1 WIN OS.Configure the Enviorment variable #HK代理环境&#xff0c;不需要科学上网(价格便宜、有安全风险&#…

ComfyUI节点安装笔记

AI高速发展&#xff0c;版本更新相当快&#xff08;11月25日才安装的版本v.0.3.4&#xff0c;27日版本就已经更新到v.0.3.5了&#xff09;&#xff0c;在遇到问题&#xff0c;找到问题原因所在的过程中&#xff0c;ComfyUI版本、python版本、节点对环境版本的依赖&#xff0c;本…

小白学Pytorch

小白学Pytorch 发现一个比较好的教程&#xff0c;对于自己来说比较合适&#xff0c;适合从零开始的教程。 1、搭建一个简单的网络 https://www.cnblogs.com/PythonLearner/p/13587092.html 搭建网络这步说的比较清楚&#xff1a; 我们使用nn包中的Sequential搭建网络&#…

如何查看服务器上的MySQL/Redis等系统服务状态和列表

如果呢你知道系统服务名称&#xff0c;要看状态很简单&#xff1a; systemctl status server-name 比如 systemctl status nginxsystemctl status redis # 等 这是一个nginx的示例&#xff1a; 那问题是 当你不知道服务名称时该怎么办。举个例子&#xff0c;比如mysql在启动…