[C++]二叉搜索树

news/2024/12/27 2:19:45/

一、定义

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

二、插入insert

对于二叉搜索树的插入操作,我们将需要插入的key值与当前结点(初始结点是root结点)比较,若小于该结点的值,则往左子树走;若大于该结点的值,则往右子树走。走到空结点的时候,那么这个位置就是这个key值的归宿。

template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* left;BSTreeNode<K, V>* right;K _key;V _value;
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:BSTree(){_root = nullptr;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node;_root->_key = key;_root->_value = value;_root->left = nullptr;_root->right = nullptr;}else{Node* cur = _root;Node* parent = _root;while (cur){if (key < cur->_key){parent = cur;cur = cur->left;}else if (key > cur->_key){parent = cur;cur = cur->right;}}cur = new Node;cur->left = nullptr;cur->right = nullptr;cur->_key = key;cur->_value = value;if (key < parent->_key){parent->left = cur;}else{parent->right = cur;}}return true;}
private:Node* _root = nullptr;
};

三、查找操作find

对于二叉搜索树的查找操作,我们将需要查找的key值与当前结点(初始结点是root结点)比较,若小于该结点的值,则往左子树走;若大于该结点的值,则往右子树走。

若走到空,则说明没有这个值,返回空指针。若找到该值,则返回该值的结点。

	Node* Find(const K& key){Node* cur = _root;while (cur){if (key < cur->_key){cur = cur->left;}else if (key > cur->_key){cur = cur->right;}else{return cur;}}return nullptr;}

四、删除操作

	bool Erase(const K& key){Node* cur = _root;Node* parent = _root;while (cur){//若key小于当前结点的值,则往左子树走if (key < cur->_key){parent = cur;cur = cur->left;}//若key大于当前结点的值,则往右子树走else if (key > cur->_key){parent = cur;cur = cur->right;}//若key值与当前结点的值相等,则说明该结点就是需要删除的else{//该结点左右子树皆为空的情况if (cur->left == nullptr && cur->right == nullptr){//直接删除if (key < parent->_key){parent->left = nullptr;}if (key > parent->_key){parent->right = nullptr;}delete cur;}//该结点左子树为空的情况else if (cur->left == nullptr){//将该结点的左子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->right;elseparent->right = cur->right;delete cur;}//该结点右子树为空的情况else if (cur->right == nullptr){//将该结点的右子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->left;elseparent->right = cur->left;delete cur;}//左右子树皆不为空//该情况下,我们需要找到左子树的最大结点/右子树的最小结点//然后将需要删除的结点的值和找到的最大结点/最小结点的值交换//此时我们只需要删除交换之后值为需要删除的数值的结点//这里以与左子树的最大结点交换为例else{//del是之后需要删除的结点Node* del = cur->left;//tmp是需要删除的结点的父结点Node* tmp = del;//找到左子树的最大结点,记录为del,此时tmp为del的父结点while (del->right){tmp = del;del = del->right;}//交换key值swap(cur->_key, del->_key);//如即将被删除的结点有左子树,则将其链接到tmp上if (del->left){tmp->right = del->left;}//否则直接将tmp指向即将被删除的结点的指针置空else{tmp->right = nullptr;}//删除交换key值后的结点delete del;}return true;}}return false;}

五、中序遍历InOrder

使用中序遍历二叉搜索树时,我们得到的是一个递增序列。

	void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->left);cout << root->_key << ' ';_InOrder(root->right);}void InOrder(){_InOrder(_root);cout << endl;}

六、完整代码

#include<iostream>
#include<string>template<class K, class V>
struct BSTreeNode
{BSTreeNode<K, V>* left;BSTreeNode<K, V>* right;K _key;V _value;
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:BSTree(){_root = nullptr;}bool Insert(const K& key, const V& value){if (_root == nullptr){_root = new Node;_root->_key = key;_root->_value = value;_root->left = nullptr;_root->right = nullptr;}else{Node* cur = _root;Node* parent = _root;while (cur){if (key < cur->_key){parent = cur;cur = cur->left;}else if (key > cur->_key){parent = cur;cur = cur->right;}}cur = new Node;cur->left = nullptr;cur->right = nullptr;cur->_key = key;cur->_value = value;if (key < parent->_key){parent->left = cur;}else{parent->right = cur;}}return true;}Node* Find(const K& key){Node* cur = _root;while (cur){if (key < cur->_key){cur = cur->left;}else if (key > cur->_key){cur = cur->right;}else{return cur;}}return nullptr;}bool Erase(const K& key){Node* cur = _root;Node* parent = _root;while (cur){//若key小于当前结点的值,则往左子树走if (key < cur->_key){parent = cur;cur = cur->left;}//若key大于当前结点的值,则往右子树走else if (key > cur->_key){parent = cur;cur = cur->right;}//若key值与当前结点的值相等,则说明该结点就是需要删除的else{//该结点左右子树皆为空的情况if (cur->left == nullptr && cur->right == nullptr){//直接删除if (key < parent->_key){parent->left = nullptr;}if (key > parent->_key){parent->right = nullptr;}delete cur;}//该结点左子树为空的情况else if (cur->left == nullptr){//将该结点的左子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->right;elseparent->right = cur->right;delete cur;}//该结点右子树为空的情况else if (cur->right == nullptr){//将该结点的右子树链接到该结点的父结点的子树上,然后删除该结点if (key < parent->_key)parent->left = cur->left;elseparent->right = cur->left;delete cur;}//左右子树皆不为空//该情况下,我们需要找到左子树的最大结点/右子树的最小结点//然后将需要删除的结点的值和找到的最大结点/最小结点的值交换//此时我们只需要删除交换之后值为需要删除的数值的结点//这里以与左子树的最大结点交换为例else{//del是之后需要删除的结点Node* del = cur->left;//tmp是需要删除的结点的父结点Node* tmp = del;//找到左子树的最大结点,记录为del,此时tmp为del的父结点while (del->right){tmp = del;del = del->right;}//交换key值swap(cur->_key, del->_key);//如即将被删除的结点有左子树,则将其链接到tmp上if (del->left){tmp->right = del->left;}//否则直接将tmp指向即将被删除的结点的指针置空else{tmp->right = nullptr;}//删除交换key值后的结点delete del;}return true;}}return false;}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->left);cout << root->_key << ' ';_InOrder(root->right);}void InOrder(){_InOrder(_root);cout << endl;}private:Node* _root = nullptr;
};


http://www.ppmy.cn/news/1354940.html

相关文章

九、OpenCV自带colormap

项目功能实现&#xff1a;每隔1500ms轮流自动播放不同风格图像显示&#xff0c;按下Esc键退出 按照之前的博文结构来&#xff0c;这里就不在赘述了 一、头文件 colormap.h #pragma once #include<opencv2/opencv.hpp> using namespace cv;class ColorMap { public:vo…

jsp课程教学管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 课程教学管理系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0…

挑战杯 YOLOv7 目标检测网络解读

文章目录 0 前言1 yolov7的整体结构2 关键点 - backbone关键点 - head3 训练4 使用效果5 最后 0 前言 世界变化太快&#xff0c;YOLOv6还没用熟YOLOv7就来了&#xff0c;如果有同学的毕设项目想用上最新的技术&#xff0c;不妨看看学长的这篇文章&#xff0c;学长带大家简单的…

Linux目录操作类命令 less | grep | ln | chattr | 清除日志内容

less 用来浏览超过一页的文件 用 / 可用来查找关键字 q键退出 cat -n 3.txt | less行号显示grep 文本处理工具&#xff0c;以行为单位找关键字 ls -l /boot | grep ^l grep 关键字 文件名 grep runlevel /etc/inittab 参数 -i忽略大小写 -n显示行号 -v排除关键字&#xff0…

PTA | Wifi密码

下面是微博上流传的一张照片&#xff1a;“各位亲爱的同学们&#xff0c;鉴于大家有时需要使用 wifi&#xff0c;又怕耽误亲们的学习&#xff0c;现将 wifi 密码设置为下列数学题答案&#xff1a;A-1&#xff1b;B-2&#xff1b;C-3&#xff1b;D-4&#xff1b;请同学们自己作答…

前端性能优化的策略和技术手段总结

前端性能优化是提高用户体验和网站运行效率的重要环节。以下是一些常见的策略和技术手段&#xff0c;用于优化前端性能&#xff1a; 1. 优化资源加载 - 合并资源&#xff1a;将多个文件合并为一个文件&#xff0c;减少HTTP请求次数。 - 压缩资源&#xff1a;压缩CSS、J…

[java基础揉碎] 作用域

局部变量与全局变量: 作用域的细节:

用结构体数组,完成宠物信息登记管理。

管理宠物的名字&#xff0c;品种&#xff0c;年龄。 实现功能如下: 1.插入宠物信息 2.遍历宠物信息 #include <stdio.h> #define N 100 typedef struct chongwu { char name[20]; char pingz[10]; int age; }cw; void intset_cw(cw *ptr,int *pnum) { printf("请…