BSTree二叉树讲解

2023-10-30 09:20
文章标签 二叉树 讲解 bstree

本文主要是介绍BSTree二叉树讲解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

二叉搜索树的概念:

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

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

二叉树的运用:(改代码就是KV模型的二叉搜索树)

1. K模型K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到
的值。
        比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树


在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
2. KV模型每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方
式在现实生活中非常常见:
        比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英
文单词与其对应的中文<word, chinese>就构成一种键值对;
        再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
现次数就是<word, count>就构成一种键值对。

二叉树的查找:

        a、从根开始比较,查找,比根大则往右边走查找,比根小则往左边走查找。
        b、最多查找高度次,走到到空,还没找到,这个值不存在。

	Node* _Find(Node* root,const K& key){if (root == nullptr)//遇到空节点就返回{return nullptr;}if (root->_kv.first == key){return root;}else if (root->_kv.first > key){_Find(root->_left, key);}else{_Find(root->_right, key);}}

 二叉搜索树的插入:

插入的具体过程如下:
        a. 树为空,则直接新增节点,赋值给root指针
        b. 树不空,按二叉搜索树性质查找插入位置,插入新节点

	bool _Insert(const pair<K, V>& kv)//这里使用pair——key,value模型 如字典{if (_root == nullptr)//如果该二叉树的树为空 就给个节点然后返回{_root = new Node(kv);return true;}//不为空就进行寻找 找到太该呆的位置 Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}//判断该节点在父节点的左边还是右边if (parent->_kv.first > kv.first){parent->_left = new Node(kv);}else{parent->_right = new Node(kv);}}Node* _root = nullptr;
};

二叉搜索树的删除:

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:
        a. 要删除的结点无孩子结点
        b. 要删除的结点只有左孩子结点
        c. 要删除的结点只有右孩子结点
        d. 要删除的结点有左、右孩子结点
看起来有待删除节点有4中情况,实际情况a可以与情况b或者c合并起来,因此真正的删除过程
如下:
        情况b:删除该结点且使被删除节点的双亲结点指向被删除节点的左孩子结点--直接删除
        情况c:删除该结点且使被删除节点的双亲结点指向被删除结点的右孩子结点--直接删除
        情况d:在它的右子树中寻找中序下的第一个结点(关键码最小),用它的值填补到被删除节点
        中,再来处理该结点的删除问题--替换法删除

	bool _Erase(Node* root, const K& key){Node* parent = nullptr;Node* cur = root;while (cur){if (cur->_kv.first == key)//如果key与要搜索的值相等 就进行删除{if (cur->_left == nullptr)//左子树为空 右子树不为空{//再考虑要删除的节点是他父节点的左子树还是右子树 将该节点接到其父节点上if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;//将该节点进行释放}else if (cur->_right == nullptr)//右子树不存在 左子树存在 同上{if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}else//左右子树都存在 需要寻找一个可以代替该节点值的值 {//在左子树中找最小的值 (就是左子树最左边的那个节点)右节点就找右子树中最大的节点 (就是右子树最右边的那个节点)Node* parent1 = nullptr;Node* tmp = cur;while (tmp->_left)//寻找左节点{parent1 = tmp;tmp = tmp->_left;}swap(&cur->_kv, &tmp->_kv);//找到进行值的交换parent1->_left = tmp->_right;//如果最小的左节点的左子树为空右子树不为空 将右子树接到该节点的父亲上 但是如果右子树为空 也可以将空节点接到其父节点上 不产生影响delete tmp;//释放节点}}else{if (root->_kv.first > key){parent = cur;cur = cur->_left;}else{parent = cur;cur = cur->_right;}}}}

二叉树的遍历:(中序遍历)(将二叉树中key的值按顺序打印)

	void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << " " << root->_kv.second << endl;_InOrder(root->_right);}

以下就是二叉搜索树的完整代码 以及对应的测试用例,可以自行去调用测试。

#include<iostream>
#include<string>
using namespace std;template<class K,class V>
struct BSTreeNode
{typedef BSTreeNode<K, V> Node;BSTreeNode(const pair<K, V>& x):_kv(x), _left(nullptr), _right(nullptr){}pair<K, V> _kv;Node* _left;Node* _right;
};template<class K, class V>
class BSTree
{typedef BSTreeNode<K, V> Node;
public:bool Insert(const K& key, const V& value){pair<K, V> kv(key, value);return _Insert(kv);}Node* Find(const K& key){return _Find(_root,key);}bool Erase(const K& key){return _Erase(_root, key);}void InOrder(){_InOrder(_root);}
private:bool _Erase(Node* root, const K& key){Node* parent = nullptr;Node* cur = root;while (cur){if (cur->_kv.first == key){if (cur->_left == nullptr){if (cur == parent->_left){parent->_left = cur->_right;}else{parent->_right = cur->_right;}delete cur;}else if (cur->_right == nullptr){if (cur == parent->_left){parent->_left = cur->_left;}else{parent->_right = cur->_left;}delete cur;}else{Node* parent1 = nullptr;Node* tmp = cur;while (tmp->_left){parent1 = tmp;tmp = tmp->_left;}swap(&cur->_kv, &tmp->_kv);parent1->_left = tmp->_right;delete tmp;}}else{if (root->_kv.first > key){parent = cur;cur = cur->_left;}else{parent = cur;cur = cur->_right;}}}}void _InOrder(Node* root){if (root == nullptr){return;}_InOrder(root->_left);cout << root->_kv.first << " " << root->_kv.second << endl;_InOrder(root->_right);}Node* _Find(Node* root,const K& key){if (root == nullptr){return nullptr;}if (root->_kv.first == key){return root;}else if (root->_kv.first > key){_Find(root->_left, key);}else{_Find(root->_right, key);}}bool _Insert(const pair<K, V>& kv){if (_root == nullptr){_root = new Node(kv);return true;}Node* parent = nullptr;Node* cur = _root;while (cur){if (cur->_kv.first > kv.first){parent = cur;cur = cur->_left;}else if (cur->_kv.first < kv.first){parent = cur;cur = cur->_right;}else{return false;}}if (parent->_kv.first > kv.first){parent->_left = new Node(kv);}else{parent->_right = new Node(kv);}}Node* _root = nullptr;
};void TestBSTree()
{BSTree<string, string> dict;dict.Insert("insert", "插入");dict.Insert("erase", "删除");dict.Insert("left", "左边");dict.Insert("string", "字符串");string str;while (cin >> str){auto ret = dict.Find(str);if (ret){cout << str << ":" << ret->_kv.second << endl;}else{cout << "单词拼写错误" << endl;}}string strs[] = { "苹果", "西瓜", "苹果", "樱桃", "苹果", "樱桃", "苹果", "樱桃", "苹果" };// 统计水果出现的次BSTree<string, int> countTree;for (auto str : strs){auto ret = countTree.Find(str);if (ret == NULL){countTree.Insert(str, 1);}else{ret->_kv.second++;}}countTree.InOrder();
}

这篇关于BSTree二叉树讲解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/306906

相关文章

SQL Server中行转列方法详细讲解

《SQLServer中行转列方法详细讲解》SQL行转列、列转行可以帮助我们更方便地处理数据,生成需要的报表和结果集,:本文主要介绍SQLServer中行转列方法的相关资料,需要的朋友可以参考下... 目录前言一、为什么需要行转列二、行转列的基本概念三、使用PIVOT运算符进行行转列1.创建示例数据表并插入数

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

VS Code中的Python代码格式化插件示例讲解

《VSCode中的Python代码格式化插件示例讲解》在Java开发过程中,代码的规范性和可读性至关重要,一个团队中如果每个开发者的代码风格各异,会给代码的维护、审查和协作带来极大的困难,这篇文章主... 目录前言如何安装与配置使用建议与技巧如何选择总结前言在 VS Code 中,有几款非常出色的 pyt

Java中实现对象的拷贝案例讲解

《Java中实现对象的拷贝案例讲解》Java对象拷贝分为浅拷贝(复制值及引用地址)和深拷贝(递归复制所有引用对象),常用方法包括Object.clone()、序列化及JSON转换,需处理循环引用问题,... 目录对象的拷贝简介浅拷贝和深拷贝浅拷贝深拷贝深拷贝和循环引用总结对象的拷贝简介对象的拷贝,把一个

Unity新手入门学习殿堂级知识详细讲解(图文)

《Unity新手入门学习殿堂级知识详细讲解(图文)》Unity是一款跨平台游戏引擎,支持2D/3D及VR/AR开发,核心功能模块包括图形、音频、物理等,通过可视化编辑器与脚本扩展实现开发,项目结构含A... 目录入门概述什么是 UnityUnity引擎基础认知编辑器核心操作Unity 编辑器项目模式分类工程

MySQL连表查询之笛卡尔积查询的详细过程讲解

《MySQL连表查询之笛卡尔积查询的详细过程讲解》在使用MySQL或任何关系型数据库进行多表查询时,如果连接条件设置不当,就可能发生所谓的笛卡尔积现象,:本文主要介绍MySQL连表查询之笛卡尔积查... 目录一、笛卡尔积的数学本质二、mysql中的实现机制1. 显式语法2. 隐式语法3. 执行原理(以Nes

RabbitMQ消费端单线程与多线程案例讲解

《RabbitMQ消费端单线程与多线程案例讲解》文章解析RabbitMQ消费端单线程与多线程处理机制,说明concurrency控制消费者数量,max-concurrency控制最大线程数,prefe... 目录 一、基础概念详细解释:举个例子:✅ 单消费者 + 单线程消费❌ 单消费者 + 多线程消费❌ 多

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

Java进程CPU使用率过高排查步骤详细讲解

《Java进程CPU使用率过高排查步骤详细讲解》:本文主要介绍Java进程CPU使用率过高排查的相关资料,针对Java进程CPU使用率高的问题,我们可以遵循以下步骤进行排查和优化,文中通过代码介绍... 目录前言一、初步定位问题1.1 确认进程状态1.2 确定Java进程ID1.3 快速生成线程堆栈二、分析