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

相关文章

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

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

javascript fetch 用法讲解

《javascriptfetch用法讲解》fetch是一个现代化的JavaScriptAPI,用于发送网络请求并获取资源,它是浏览器提供的全局方法,可以替代传统的XMLHttpRequest,这篇... 目录1. 基本语法1.1 语法1.2 示例:简单 GET 请求2. Response 对象3. 配置请求

Java Stream.reduce()方法操作实际案例讲解

《JavaStream.reduce()方法操作实际案例讲解》reduce是JavaStreamAPI中的一个核心操作,用于将流中的元素组合起来产生单个结果,:本文主要介绍JavaStream.... 目录一、reduce的基本概念1. 什么是reduce操作2. reduce方法的三种形式二、reduce

CSS引入方式和选择符的讲解和运用小结

《CSS引入方式和选择符的讲解和运用小结》CSS即层叠样式表,是一种用于描述网页文档(如HTML或XML)外观和格式的样式表语言,它主要用于将网页内容的呈现(外观)和结构(内容)分离,从而实现... 目录一、前言二、css 是什么三、CSS 引入方式1、行内样式2、内部样式表3、链入外部样式表四、CSS 选

Python Transformers库(NLP处理库)案例代码讲解

《PythonTransformers库(NLP处理库)案例代码讲解》本文介绍transformers库的全面讲解,包含基础知识、高级用法、案例代码及学习路径,内容经过组织,适合不同阶段的学习者,对... 目录一、基础知识1. Transformers 库简介2. 安装与环境配置3. 快速上手示例二、核心模

C++ vector的常见用法超详细讲解

《C++vector的常见用法超详细讲解》:本文主要介绍C++vector的常见用法,包括C++中vector容器的定义、初始化方法、访问元素、常用函数及其时间复杂度,通过代码介绍的非常详细,... 目录1、vector的定义2、vector常用初始化方法1、使编程用花括号直接赋值2、使用圆括号赋值3、ve

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快