【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;
  else
    cout << "(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;
}

测试结果

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TCP与DNS的报文分析

场景拓扑&#xff1a; 核心路由配置&#xff1a; 上&#xff08;DNS&#xff09;&#xff1a;10.1.1.1/24 下(WEB)&#xff1a;20.1.1.1/24 左&#xff08;client&#xff09;&#xff1a;192.168.0.1/24 右(PC3)&#xff1a;192.168.1.1/24Clint2配置&a…

OpenHarmony通过挂载镜像来修改镜像内容,RK3566鸿蒙开发板演示

在测试XTS时会遇到修改产品属性、SElinux权限、等一些内容&#xff0c;修改源码再编译很费时。今天为大家介绍一个便捷的方法&#xff0c;让OpenHarmony通过挂载镜像来修改镜像内容&#xff01;触觉智能Purple Pi OH鸿蒙开发板演示。搭载了瑞芯微RK3566四核处理器&#xff0c;树…

linux ansible部署

ansible部署完后&#xff0c;执行报错 # ansible one -i hosts -m ping dataos193 | FAILED! > {"msg": "Using a SSH password instead of a key is not possible because Host Key checking is enabled and sshpass does not support this. Please add …

【微服务】3、配置管理

微服务配置管理 已掌握的微服务组件及配置管理问题引出 已掌握注册中心、Openfan、远程调用、负载均衡、网关等组件&#xff0c;具备微服务开发能力&#xff0c;但仍存在其他问题待解决。微服务和网关存在大量配置文件&#xff0c;其中包含很多重复配置&#xff0c;如数据库、日…

C# 事件

目录 1、事件模型的5个组成部分2、使用内置委托类型声明事件2.1 EventHandler2.1.1 &#xff1f;2.1.2 this2.1.3 使用匿名函数和lamda表达式2.1.3.1 匿名函数2.1.3.2 lamda表达式 2.1.4 异常处理 2.2 EventHandler<TEventArgs> 3、使用自定义委托类型声明事件3.1 事件的…

php反序列化原生态 ctfshow练习 字符串逃逸

web262 拿着题审计一下 <?php error_reporting(0); class message{public $from;public $msg;public $to;public $tokenuser;public function __construct($f,$m,$t){$this->from $f;$this->msg $m;$this->to $t;} }$f $_GET[f]; $m $_GET[m]; $t $_GET[t…

【C语言程序设计——循环程序设计】利用循环求数值 x 的平方根(头歌实践教学平台习题)【合集】

目录&#x1f60b; 任务描述 相关知识 一、求平方根的迭代公式 1. 原理 2. 代码实现示例 二、绝对值函数fabs() 1. 函数介绍 2. 代码示例 三、循环语句 1. for循环 2. while循环 3. do - while循环 编程要求 测试说明 通关代码 测试结果 任务描述 本关任务&…

使用 Three.js 创建动态粒子效果

今天&#xff0c;带大家使用粒子实现一个粒子飞毯的效果&#xff0c;我们先来看一下效果。 实现 初始化场景 首先创建一个场景&#xff0c;所有 3D 对象都会被添加到这个场景中。 const scene new THREE.Scene();相机和渲染器 配置相机和渲染器来捕捉和显示场景。 相机…

20250103在Ubuntu20.04.5的Android Studio 2024.2.1.12中跑通Hello World

20250103在Ubuntu20.04.5的Android Studio 2024.2.1.12中跑通Hello World 2025/1/3 14:06 百度&#xff1a;android studio helloworld android studio hello world kotlin helloword kotlin 串口 no run configurations added android studio no run configurations added 1、…

c#使用SevenZipSharp实现压缩文件和目录

封装了一个类&#xff0c;方便使用SevenZipSharp&#xff0c;支持加入进度显示事件。 双重加密压缩工具范例&#xff1a; using SevenZip; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.…

Ubuntu 20.04安装gcc

一、安装GCC 1.更新包列表 user596785154:~$ sudo apt update2.安装gcc user596785154:~$ sudo apt install gcc3.验证安装 user596785154:~$ gcc --version二 编译C文件 1.新建workspace文件夹 user596785154:~$ mkdir workspace2.进入workspace文件夹 user596785154:~…

网络协议安全的攻击手法

1.使用SYN Flood泛洪攻击&#xff1a; SYN Flood(半开放攻击)是最经典的ddos攻击之一&#xff0c;他利用了TCP协议的三次握手机制&#xff0c;攻击者通常利用工具或控制僵尸主机向服务器发送海量的变源端口的TCP SYN报文&#xff0c;服务器响应了这些报文后就会生成大量的半连…

晨辉面试抽签和评分管理系统之一:考生信息管理和编排

晨辉面试抽签和评分管理系统&#xff08;下载地址:www.chenhuisoft.cn&#xff09;是公务员招录面试、教师资格考试面试、企业招录面试等各类面试通用的考生编排、考生入场抽签、候考室倒计时管理、面试考官抽签、面试评分记录和成绩核算的面试全流程信息化管理软件。提供了考生…

鸿蒙的APP真机调试以及发布

目录&#xff1a; 1、创建好鸿蒙项目2、创建AGC项目3、实现自动签名3.1、手动方式创建签名文件和密码 4、运行项目5、无线真机调试 1、创建好鸿蒙项目 2、创建AGC项目 &#xff08;1&#xff09;在File->Project Structure->Project->Signing Configs中进行登录。(未…

H7-TOOL固件2.27发布,新增加40多款芯片脱机烧录,含多款车轨芯片,发布LUA API手册,CAN助手增加负载率,错误状态信息检测

H7-TOOL详细介绍&#xff08;含操作手册&#xff09;&#xff1a;H7-TOOL开发工具&#xff0c;1拖4/16脱机烧录&#xff0c;高速DAPLINK&#xff0c;RTOS Trace&#xff0c;CAN/串口助手, 示波器, RTT等&#xff0c;支持WiFi&#xff0c;以太网&#xff0c;高速USB和手持 - H7-…

SpringMVC(一)配置

目录 引入 第一章&#xff1a;Java web的发展历史 一、Model I和Model II 1.Model I开发模式 2.Model II开发模式 二. MVC模式 第二章&#xff1a;SpringMVC的入门案例 搭建SpringMVC的入门程序 1.创建新项目 2.等待加载导入坐标 3.处理xml文件和其他 导入tomcat 运…

Linux驱动开发 gpio_get_value读取输出io的电平返回值一直为0的问题

当时gpio子系统进行读取时返回必定是0 因此&#xff0c;首先必须使用platform驱动来管理gpio和pinctrl子系统&#xff0c;然后如果按照正点原子所教的设备树引脚设置为0x10B0则会导致读取到的电平值为0。 解决方法&#xff1a; 将设备树中的引脚设置为 pinctrl_gpioled: gpio…

uniapp-vue3 实现, 一款带有丝滑动画效果的单选框组件,支持微信小程序、H5等多端

采用 uniapp-vue3 实现, 是一款带有丝滑动画效果的单选框组件&#xff0c;提供点状、条状的动画过渡效果&#xff0c;支持多项自定义配置&#xff0c;适配 web、H5、微信小程序&#xff08;其他平台小程序未测试过&#xff0c;可自行尝试&#xff09; 可到插件市场下载尝试&…

Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s

前言&#xff1a;纯个人记录使用。 搭建 Zero to JupyterHub with Kubernetes 上篇 - Kubernetes 离线二进制部署。搭建 Zero to JupyterHub with Kubernetes 中篇 - Kubernetes 常规使用记录。搭建 Zero to JupyterHub with Kubernetes 下篇 - Jupyterhub on k8s。 官方文档…

倾斜摄影相机在不动产确权登记和权籍调查中的应用

一、项目背景 1.1 项目背景 为贯彻落实中央、国务院关于实施乡村振兴战略、关于“扎实推进房地一体的农村集体建设用地和宅基地使用权确权登记颁证&#xff0c;完善农民闲置宅基地和闲置农房政策&#xff0c;探索宅基地所有权、资格权、使用权‘三权分置’”的要求&#xff0…