【C++】二叉搜索树的模拟实现(K,KV树)递归与非递归方式

news/2024/10/18 2:31:29/

文章目录

  • 前言
  • 一、K树
    • 1.结点的定义
    • 2.构造函数
    • 3.拷贝构造函数
    • 4.赋值运算符重载
    • 5.析构函数
    • 6.二叉搜索树的查找(find)
      • 1.非递归
      • 2.递归
    • 7.二叉搜索树的插入(Insert)
      • 1.非递归
      • 2.递归
    • 8.二叉搜素树的删除(Erase)
      • 1.非递归
      • 2.递归
    • 9.中序遍历(InOrder)
  • 二、KV树
  • 二叉搜索树性能


前言

在这里插入图片描述

一、K树

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。

1.结点的定义

template<class K>
struct BSTreeNode
{BSTreeNode<K>* _left;BSTreeNode<K>* _right;K _key;BSTreeNode(const K&key):_left(nullptr),_right(nullptr),_key(key){}
};

2.构造函数

template<class K>
class BSTree {typedef BSTreeNode<K> Node;
public:BSTree() {_root = nullptr;}

3.拷贝构造函数

BSTree(const BSTree<K>& t) {_root = Copy(t._root);}
Node* Copy(Node* root) {if (root == nullptr) {return nullptr;}//递归进行拷贝Node* copyroot = new Node(root->_key);copyroot->_left = Copy(root->_left);copyroot->_right = Copy(root->_right);return copyroot;}

4.赋值运算符重载

BSTree<K>& operator=(BSTree<K> t) {
//先拷贝出t,让_root指向t的位置,进行交换
//后续调用析构函数直接析构t._rootswap(_root, t._root);return *this;}

5.析构函数

~BSTree() {Destroy(_root);}void Destroy(Node*& root) {if (root == nullptr) {return;}Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}

6.二叉搜索树的查找(find)

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

1.非递归

bool Find(const K& key) {Node* cur = _root;while (cur) {if (cur->_key < key) {//当前值比要查找的值小//到右树去查找cur = cur->_right;}else if (cur->_key > key) {cur = cur->_left;}else {//相等,说明找到了return true;}}return false;}

2.递归

bool _FindR(Node*root,const K& key) {if (root == nullptr) {//说明已经找完没找到return false;}if (root->_key < key) {return _FindR(root->_right, key);}else if (root->_key > key) {return _FindR(root->_left, key);}else {return true;}}

7.二叉搜索树的插入(Insert)

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

1.非递归

bool Insert(const K& key) {if (_root == nullptr) {_root = new Node(key);//树为空先建立结点return true;}Node* cur = _root;Node* parent = nullptr;while (cur) {//寻找要插入位置if (cur->_key < key) {parent = cur;cur = cur->_right;}else if (cur->_key > key) {parent = cur;cur = cur->_left;}else {//树中已经有key值不能再插入return false;}}cur = new Node(key);//cur为要插入结点if (parent->_key < key) {//判断cur插在父结点的左数还是右树parent->_right = cur;}else {parent->_left = cur;}return true;//插入成功}

2.递归

在这里插入图片描述

bool InsertR(const K&key) {return _InsertR(_root, key);}bool _InsertR(Node*& root, const K& key) {//这里为结点指针的引用,可以不需要父结点直接修改if (root == nullptr) {root = new Node(key);return true;}if (root->_key < key) {return 	_InsertR(root->_right, key);}else if (root->_key > key) {return _InsertR(root->_left, key);}else {return false;}}

8.二叉搜素树的删除(Erase)

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

在这里插入图片描述

在这里插入图片描述

1.非递归

	bool Erase(const K& key) {Node* parent = nullptr;Node* cur = _root;while (cur) {//寻找要删除结点if (cur->_key < key) {parent = cur;cur = cur->_right;}else if (cur->_key > key) {parent = cur;cur = cur->_left;}else {//找到要删除结点//1.   要删除节点左边为空if (cur->_left == nullptr) {if (cur == _root) {//要删除结点为根节点,则改变根节点位置_root = _root->_right;}else {//判断要删除结点在父结点的左子树还是右子树if (parent->_right == cur) {//在父结点右子树则让其指向删除结点的右子树parent->_right = cur->_right;}else {parent->_left = cur->_right;}}}//2.     要删除节点右边为空else if (cur->_right == nullptr) {if (cur == _root) {//要删除结点为根节点,则改变根节点位置_root = _root->_left;}else {//判断要删除结点在父结点的左子树还是右子树if (parent->_right == cur) {parent->_right = cur->_left;}else {parent->_left = cur->_left;}}}else {//3.要删除结点左右子树都不为空Node* parent = cur;Node* leftMax = cur->_left;//寻找可替代结点,替代过好要满足二叉搜索树的性质//要删除结点左子树的最大值,或者右子树的最小值while (leftMax->_right) {//寻找左子树的最大值parent = leftMax;leftMax = leftMax->_right;}swap(leftMax->_key, cur->_key);//替代结点与被删除结点的值交换//这样leftMax就为要被删除的结点if (parent->_left == leftMax) {//判断leftMax在父结点的左子树还是右子树parent->_left = leftMax->_left;}else {parent->_right = leftMax->_left;}//改变指向cur = leftMax;}delete cur;return true;}	}return false;}

2.递归

bool EraseR(const K&key) {return _EraseR(_root, key);}bool _EraseR(Node*& root, const K& key) {//这里为结点指针的引用,可以不需要父结点直接修改if (root == nullptr) {return false;}if (root->_key < key) {return _Erase(root->_right, key);}else if (root->_key > key) {return _Erase(root->_left, key);}//寻找要删除结点else {Node* del = root;//1. 要删除节点左边为空if (root->_left == nullptr) {root = root->_right;}//2. 要删除节点右边为空else if (root->_right == nullptr) {root = root->_left;}else {//3.要删除结点左右都不为空Node* leftMax = root->_left;while (leftMax->_right) {//寻找替代结点leftMax = leftMax->_right;}swap(root->_key, leftMax->_key);//交换值后,要删除的结点为leftMax,其在root的左子树return _Erase(root->_left, key);}delete del;return true;}}

9.中序遍历(InOrder)

void InOrder() {_InOrder(_root);cout << endl;}
void _InOrder(Node* root) {if (root == nullptr) {return;}_InOrder(root->_left);cout << root->_key << " ";_InOrder(root->_right);}

二、KV树

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对

namespace key_value {template<class K, class V>struct BSTreeNode{BSTreeNode<K, V>* _left;BSTreeNode<K, V>* _right;K _key;V _value;BSTreeNode(const K& key, const V& value):_left(nullptr), _right(nullptr), _key(key), _value(value){}};template<class K, class V>class BSTree {typedef BSTreeNode<K, V> Node;public:BSTree() {_root = nullptr;}BSTree(const BSTree<K, V>& t) {_root = Copy(t._root);}BSTree<K, V>& operator=(BSTree<K, V> t) {swap(_root, t._root);return *this;}~BSTree() {Destroy(_root);}bool InsertR(const K& key, const V& value) {return _InsertR(_root, key, value);}bool EraseR(const K& key) {return _Erase(_root, key);}Node* FindR(const K& key) {return 	_FindR(_root, key);}void InOrder() {_InOrder(_root);cout << endl;}private:Node* Copy(Node* root) {if (root == nullptr) {return nullptr;}Node* copyroot = new Node(root->_key);copyroot->_left = Copy(root->_left);copyroot->_right = Copy(root->_right);return copyroot;}void Destroy(Node*& root) {if (root == nullptr) {return;}Destroy(root->_left);Destroy(root->_right);delete root;root = nullptr;}Node* _FindR(Node* root, const K& key) {if (root == nullptr) {return nullptr;}if (root->_key < key) {return _FindR(root->_right, key);}else if (root->_key > key) {return _FindR(root->_left, key);}else {return root;}}bool _InsertR(Node*& root, const K& key, const V& value) {if (root == nullptr) {root = new Node(key, value);return true;}if (root->_key < key) {return _InsertR(root->_right, key, value);}else if (root->_key > key) {return _InsertR(root->_left, key, value);}else {return false;}}bool _Erase(Node*& root, const K& key) {if (root == nullptr) {return false;}if (root->_key < key) {return _Erase(root->_right, key);}else if (root->_key > key) {return _Erase(root->_left, key);}else {Node* del = root;if (root->_left == nullptr) {root = root->_right;}else if (root->_right == nullptr) {root = root->_left;}else {Node* leftMax = root->_left;while (leftMax->_right) {leftMax = leftMax->_right;}swap(root->_key, leftMax->_key);return _Erase(root->_left, key);}delete del;return true;}}void _InOrder(Node* root){if (root == NULL){return;}_InOrder(root->_left);cout << root->_key << ":" << root->_value << endl;_InOrder(root->_right);}private:Node* _root;};
}

二叉搜索树性能

在这里插入图片描述

最高找高度次O(N)


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

相关文章

Android图形-Vsync机制

目录 引言&#xff1a; 概念&#xff1a; 刷新率&#xff1a; 帧率&#xff1a; 卡顿与丢帧&#xff1a; Vsync的产生&#xff1a; Vsync的分发过程&#xff1a; 引言&#xff1a; 显示的原理就是通过不断刷新屏幕缓冲区的数据&#xff0c;显示器就可以显示出来。 概念…

leetcode19. 删除链表的倒数第 N 个结点

题目&#xff1a;leetcode19. 删除链表的倒数第 N 个结点 描述&#xff1a; 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 思路&#xff1a; 让前面的节点比后面的节点先走n1步&#xff0c;因为从链表的尾节点的下一个节点开始&…

360安全卫士右下角广告弹窗太多怎么彻底关闭?

360安全卫士右下角广告弹窗太多怎么彻底关闭&#xff1f; 1、卸载360安全卫士&#xff0c;选择继续卸载&#xff0c;并点击下一步&#xff1b; 2、选择广告弹窗太多&#xff0c;并点击下一步&#xff1b; 3、然后被告知升级极速版永久去广告&#xff0c;可以点击一键去广告。 …

轻量的工作流引擎:告别低效,创造新高!

伴随着日益激烈的市场竞争&#xff0c;作为新时代的企业&#xff0c;如何在众多同质化竞争中脱颖而出&#xff0c;占有更多的市场份额&#xff0c;实现更大发展&#xff1f;此时此刻就需要拥有不同寻常的头脑&#xff0c;寻找不平常的路径&#xff0c;轻量的工作流引擎是低代码…

Go 语言面试题(二):实现原理

文章目录 Q1 init() 函数是什么时候执行的&#xff1f;Q2 Go 语言的局部变量分配在栈上还是堆上&#xff1f;Q3 2 个 interface 可以比较吗&#xff1f;Q4 两个 nil 可能不相等吗&#xff1f;Q5 简述 Go 语言GC(垃圾回收)的工作原理Q6 函数返回局部变量的指针是否安全&#xff…

【Mysql】修改definer

修改definer 本文介绍如何修改MySQL中的function、procedure、event、view和trigger的definer 修改function、procedure的definer 首先&#xff0c;我们需要登录MySQL命令行界面&#xff0c;然后执行以下命令&#xff1a; select definer from mysql.proc;这个命令会列出所…

恭喜又一白鲸开源成员成为 Apache SeaTunnel PMC Member

个人简介 王海林 白鲸开源研发工程师GitHub ID&#xff1a;hailin0做过性能监控、数据开发平台等&#xff0c;目前聚焦在数据集成同步及其周边生态的研发 问&#xff1a;作为白鲸开源的一员&#xff0c;您为社区做出过哪些贡献&#xff1f;具体方案&#xff08;代码类&#x…

指针的一些笔试题

一&#xff1a; 二&#xff1a; 三&#xff1a; 四&#xff1a; 五&#xff1a; 六 七 八&#xff0c;printf对指针的 --操作是会改变pcc的&#xff0c;要继承&#xff0c;而单纯的数子&#xff0c;是不会改变原有位置的