c++高阶数据结构 二叉搜索树的实现

news2024/11/17 21:35:26

二叉搜索树

  • 二叉搜索树
    • 二叉搜索树的基本概念
    • 二叉搜索树的查找方法
  • 二叉搜索树的代码实现
    • 二叉搜索树的结点
    • 二叉树的构造函数 析构函数
    • 二叉排序树的插入
    • 二叉树的删除
    • 二叉树的拷贝构造
    • 递归删除版本
  • 完整代码

二叉搜索树

二叉搜索树的基本概念

二叉搜索树的特点:

  1. 左子树都小于根节点,右子树都大于根节点。
  2. 右子树都大于根节点,左子树都小于根节点。

二叉搜索树的查找方法

大于则去左侧,小于则去右侧。

二叉搜索树的代码实现

二叉搜索树的结点

在这里插入图片描述

二叉树的构造函数 析构函数

二叉树的构造函数很简单,对一般二叉排序树。构造方法简单。析构函数需要重点说析构函数,析构的时候需要销毁所有的结点。然后,在释放根结点。
销毁的时候需要后序遍历销毁所有结点。

void destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		destroy(root->left);
		destroy(root->right);
		delete root;
	}

后序遍历才可以,否则删除不干净。

二叉排序树的插入

二叉排序树的插入就是和二叉排序树的查找一致。二叉排序树插入时,大了就去右树,小了就去左树。

bool insert(const k& val)
	{
		
		if (_root == nullptr)//如果根为空则插入
		{
			_root = new Node(val);
			return true;
		}
		Node* cur = _root;
		Node* parent = cur;
		
		while (cur)
		{

			if (cur->value == val)//等于则说明已经有了,插入失败
			{

				return false;
			}
			else if (cur->value < val)
			{
				parent = cur;
				cur = cur->right;
			}
			else
			{
				parent = cur;
				cur = cur->left;
			}
		}
		cur = new Node(val);//创建新节点
		if (parent->value < val)
		{
			parent->right = cur;
		}
		else
		{
			parent->left = cur;
		}
			return true;
	}

二叉树的删除

删除的第一步是查找的删除的位置cur. 我们和插入一样的做法。

  1. 删除叶子
if (cur->right == nullptr && cur->left == nullptr)
				{
					if (cur == parentcur->right)
					{
						parentcur->right = nullptr;
					}
					else
					{
						parentcur->left = nullptr;
					}
					delete cur;
				}
  1. 删除只有左子树
    删除拥有左子树的结点时,将左子树接到该结点原来所在位置即可。

删除左子树为空 注意两种可能:
1 在这里插入图片描述
2 在这里插入图片描述

else if (cur->left == nullptr)
				{
					// 判断他是那个子树
					//链接到父子树后面
					if (cur == _root)
					{
						_root = cur->right;
					}
					else
					{
						if (cur == parentcur->right)
						{
							parentcur->right = cur->right;
						}
						else
						{
							parentcur->left = cur->right;
						}
					}
					
					delete cur;
					break;
				}
  1. 删除只有右子树
    删除只有右子树和删除只有左子树一样。
  2. 删除左右子树都有
    在这里插入图片描述
    交换结点的值 然后转化成删除 只有右孩子的树。
else
				{
					Node* newcurfath = cur;//这里不能空 否则删除头结点会报错。
					Node* newcur = nullptr;
					newcur = cur->right;
					while (newcur->left)//找可以替换的子结点
					{
						newcur = newcur->left;
					}
					cur->value = newcur->value;//交换结点
					if (newcur == newcurfath->right)
					{
						newcurfath->right = newcur->right;
					}
					else
					{
						newcurfath->left = newcur->right;
					}
					

					delete newcur;
				}

二叉树的拷贝构造

二叉树的拷贝构造是需要通过递归,也就是前序遍历。边前序遍历边开辟空间拷贝构造。
在这里插入图片描述
最后 拷贝构造的经典问题,传引用 不能传指针。
在这里插入图片描述

递归删除版本

递归是借助引用。每递归一次,进入一颗子树。恰好引用的就是当前的头结点。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

完整代码

#pragma once
#include<iostream>
#include<string>

using namespace std;
template <class k>
struct BsNode
{	BsNode(const k& val = k())
		:right (nullptr)
		, left (nullptr)
		, value (val)
	{

	}
	typedef BsNode<k> Node;
	Node* right;
	Node* left;
	k value;
};
template <class k>
class BsTree
{
   typedef BsNode<k> Node;

public:
	BsTree()
		:_root(nullptr)
	{
		
	}
	BsTree(BsTree<k>& newroot)
	{
		_root = Copy(newroot._root);
	}
	bool insert(const k& val)
	{
		
		if (_root == nullptr)//如果根为空则插入
		{
			_root = new Node(val);
			return true;
		}
		Node* cur = _root;
		Node* parent = cur;
		
		while (cur)
		{

			if (cur->value == val)//等于则说明已经有了,插入失败
			{

				return false;
			}
			else if (cur->value < val)
			{
				parent = cur;
				cur = cur->right;
			}
			else
			{
				parent = cur;
				cur = cur->left;
			}
		}
		cur = new Node(val);//创建新节点
		if (parent->value < val)
		{
			parent->right = cur;
		}
		else
		{
			parent->left = cur;
		}
			return true;
	}

	bool find(const k& val)
	{
		Node* cur = _root;
		while (cur)
		{
			if (cur->value == val)
			{
				return true;
			}
			else if (cur->value>val)
			{
				cur = cur->right;
			}
			else
			{
				cur = cur->left;
			}
		}
		return false;
	}

	bool Erase(const k& val)
	{
		Node* cur = _root;
		Node* parentcur = _root;
		while (cur)
		{
			if (cur->value == val)
			{
				if (cur->right == nullptr && cur->left == nullptr)
				{
					if (cur == parentcur->right)
					{
						parentcur->right = nullptr;
					}
					else
					{
						parentcur->left = nullptr;
					}
					delete cur;
					break;
				}
				else if (cur->right == nullptr)
				{
					if (cur == _root)
					{
						_root = cur->left;
					}
					else
					{
						if (cur == parentcur->right)
						{
							parentcur->right = cur->left;
						}
						else
						{
							parentcur->left = cur->left;
						}
					}
					
					delete cur;
					break;
				}
				else if (cur->left == nullptr)
				{
					// 判断他是那个子树
					//链接到父子树后面
					if (cur == _root)
					{
						_root = cur->right;
					}
					else
					{
						if (cur == parentcur->right)
						{
							parentcur->right = cur->right;
						}
						else
						{
							parentcur->left = cur->right;
						}
					}
					
					delete cur;
					break;
				}
				else
				{
					Node* newcurfath = cur;
					Node* newcur = nullptr;
					newcur = cur->right;
					while (newcur->left)
					{
						newcur = newcur->left;
					}
					cur->value = newcur->value;
					if (newcur == newcurfath->right)
					{
						newcurfath->right = newcur->right;
					}
					else
					{
						newcurfath->left = newcur->right;
					}
					

					delete newcur;
				}
			}
			else if (cur->value > val)
			{
				parentcur = cur;
				cur = cur->left;
			}
			else
			{
				parentcur = cur;
				cur = cur->right;
			}
		}
		return true;
	}
	void print()
	{
		inorder(_root);
		cout << endl;
	}
	
	bool Eraser(const k& val)
	{
		return _Eraser(_root, val);
		
	}

	~BsTree()
	{
		destroy(_root);
		_root = nullptr;
	}
private:
	bool _Eraser(Node* &root, const k& val)
	{
		if (root == nullptr)
		{
			return false;
		}
		if (root->value > val)
		{
			_Eraser(root->left,val);
		}
		else if (root->value < val)
		{
			_Eraser(root->right,val);
		}
		else
		{
			Node* tmp = root;
			if (root->left == nullptr)
			{
				root = root->right;
			}
			else if (root->right == nullptr)
			{
				root = root->left;
			}
			else
			{

				
				Node* newcur = nullptr;
				newcur = root->right;
				while (newcur->left)
				{
				  	newcur = newcur->left;
				}
				swap(newcur->value,_root->value);
				return _Eraser(root->right, val);
			}
			delete tmp;
			return true;
		}

	}
	void destroy(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		destroy(root->left);
		destroy(root->right);
		delete root;
	}
	void inorder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		inorder(root->left);
		cout << root->value << ' ';
		inorder(root->right);
	}

	Node* Copy(Node* root)
	{
		if (root == nullptr)
		{
			return nullptr;
		}
		Node* Newroot = new Node(root->value);
		Newroot->left = Copy(root->left);
		Newroot->right = Copy(root->right);
		return Newroot;
	}
	Node* _root;
};

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

代码随想录算法训练营第八天

344. 反转字符串 方法&#xff1a; 方法一&#xff1a; 直接用reverse函数 注意&#xff1a; 代码&#xff1a; class Solution { public:void reverseString(vector<char>& s) {return reverse(s.begin(), s.end());} };运行结果&#xff1a; 方法&#xff1…

一份简单的前端开发指南

文章目录 一、HTML1、表格2、常见标签3、行内、块级4、行内块级元素 二、CSS1、三种样式2、链接样式3、浮动4、清除浮动5、伪类&#xff0c;伪元素6、position7、后代选择器8、弹性布局 三、JavaScripts1、null和undefined的区别2、var let const3、原生数据类型4、双等和三等5…

C++入门和基础

目录 文章目录 前言 一、C关键字 二、命名空间 2.1 命名空间的定义 2.2 命名空间的使用 2.3 标准命名空间 三、C输入&输出 四、缺省参数 4.1 缺省参数的概念 4.2 缺省参数的分类 五、函数重载 5.1 函数重载的简介 5.2 函数重载的分类 六、引用 6.1 引用的…

Linux和Windows操作系统在腾讯云幻兽帕鲁服务器上的内存占用情况如何?

Linux和Windows操作系统在腾讯云幻兽帕鲁服务器上的内存占用情况如何&#xff1f; 对于Linux操作系统&#xff0c;有用户分享了个人最佳实践来解决内存问题&#xff0c;包括使用Linux脚本让服务器每天重启一次&#xff0c;以及建议在不需要时尽量减少虚拟内存的使用。此外&…

【React 报错】—Remove untracked files, stash or commit any changes, and try again.

【React 报错】—Remove untracked files, stash or commit any changes, and try again. 在react项目中通过.less文件进行样式定义&#xff0c;先暴露webpack配置文件&#xff0c;执行命令&#xff1a;yarn eject 或 npm run eject&#xff0c;报错如下&#xff1a; 原因是因…

暗黑大气MT苹果CMS MT主题源码-PC版适用于苹果CMS V10

苹果CMS MT主题是一款多功能的主题&#xff0c;适用于苹果CMS V10的暗黑大气风格。 地 址 &#xff1a; runruncode.com/houtai/19704.html 初次使用说明&#xff1a; 在后台设置中&#xff0c;选择MT主题&#xff0c;并在模板目录中填写HTML。 后台地址为&#xff1a;MT主题…

Facebook元宇宙大观:数字化社交的未来愿景

近年来&#xff0c;元宇宙&#xff08;Metaverse&#xff09;概念备受关注&#xff0c;被认为是数字化社交的未来趋势。作为全球领先的社交媒体平台之一&#xff0c;Facebook正积极探索元宇宙的发展路径&#xff0c;构想着一个数字化社交的未来愿景。在本文中&#xff0c;我们将…

ZYNQ--MIG核配置

文章目录 MIG核配置界面多通道AXI读写DDR3MIG核配置界面 Clock Period: DDR3 芯片运行时钟周期,这个参数的范围和 FPGA 的芯片类型以及具体类型的速度等级有关。本实验选择 1250ps,对应 800M,这是本次实验所采用芯片可选的最大频率。注意这个时钟是 MIG IP 核产生,并输出给…

vb.net获取Windows主题颜色、深色模式窗体,实时响应

先上效果图 可直接跳到完整代码 目录 先上效果图 开始教学 响应用户的更改 API讲解 读取深浅模式、主题颜色、十六进制颜色转换 完整代码 如果大家留意资源管理器的“文件”菜单的话就会发现它的底色就是你设置的主题色&#xff0c;在更改Windows颜色模式时&#xff0c;…

maven 包管理平台-05-multi module 多模块

拓展阅读 maven 包管理平台-01-maven 入门介绍 Maven、Gradle、Ant、Ivy、Bazel 和 SBT 的详细对比表格 maven 包管理平台-02-windows 安装配置 mac 安装配置 maven 包管理平台-03-maven project maven 项目的创建入门 maven 包管理平台-04-maven archetype 项目原型 ma…

Zookeeper学习2:原理、常用脚本、选举机制、监听器

文章目录 原理选举机制&#xff08;重点&#xff09;情况1&#xff1a;正常启动集群情况2&#xff1a;集群启动完&#xff0c;中途有机器挂了 监听器客户端向服务端写入数据客户端向服务端Leader节点写入客户端向服务端Follower节点写入 Paxos算法&#xff08;每个节点都可以提…

【力扣白嫖日记】608.树节点

前言 练习sql语句&#xff0c;所有题目来自于力扣&#xff08;https://leetcode.cn/problemset/database/&#xff09;的免费数据库练习题。 今日题目&#xff1a; 175.组合两个表 表&#xff1a;Person 列名类型idintp_idvarchar 树中的每个节点可以是以下三种类型之一&a…

Unity铰链四杆机构设计和运动仿真

一、效果图 设定好各边长度和转速后&#xff0c;点击【设置并启动】&#xff0c;自动生成一个机构模型&#xff0c;并按照原理进行运转 二、铰链四杆机构介绍 机架&#xff1a;A和D是固定位置&#xff0c;叫做机架。 曲柄&#xff1a;B点绕A点旋转&#xff0c;构成曲柄。 连…

poi 设置允许西文在单词中间换行

说明本文是CSDN-问答模块,题主提问。问题描述:poi 设置允许西文在单词中间换行 一、问题描述 poi 设置允许西文在单词中间换行? // 创建一个新的文档XWPFDocument document = new XWPFDocument();// 创建段落XWPFParagraph firstParagraph = document.createParagraph();fir…

自定义类型(结构体、枚举、联合体)内存大小的计算方法

内存对齐 为什么会存在内存对齐&#xff1f; 大部分参考资料是这么说的&#xff1a; 平台原因(移植原因)&#xff1a; 不是所有的硬件平台都能访问任意地址上的任意数据的&#xff1b;某些硬件平台只能在某些地址处取某些特定类型的数据&#xff0c;否则抛出硬件异常。性能原…

Python绘制不同形状词云图

目录 1.基本词云图1.1 导入所需库1.2 准备词汇1.3 配置参数并生成词云图1.4 在Python窗口中显示图片1.5 效果展示1.6 完整代码 2. 不同形状词云图2.1 找到自己所需形状图片2.2 利用PS将图片设置为黑白色2.3 在代码中设置背景2.4 效果展示 1.基本词云图 1.1 导入所需库 import…

设计模式七:责任链模式

文章目录 1、责任链模式2、spring中的责任链模式Spring InterceptorServlet FilterNetty 1、责任链模式 责任链模式为请求创建了一个接收者对象的链&#xff0c;在这种模式下&#xff0c;通常每个节点都包含对另一个节点者的引用。每个节点针对请求&#xff0c;处理自己感兴趣…

备战蓝桥杯---动态规划的一些思想1

话不多说&#xff0c;直接看题&#xff1a; 目录 1.双线程DP 2.正难则反多组DP 3.换个方向思考&#xff1a; 1.双线程DP 可能有人会说直接贪心&#xff1a;先选第1条的最优路径&#xff0c;再选第2条最优路径。 其实我们再选第1条时&#xff0c;我们怎么选会对第2条的路径…

宝塔面板安装各种组件以及部署应用服务

在linux服务器安装宝塔面板 一、从宝塔官网下载exe安装包&#xff0c;安装命令从宝塔官网&#xff08;https://www.bt.cn/&#xff09;获取 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh二、安…

【JGit 】一个完整的使用案例

需求 生成一系列结构相同的项目代码&#xff0c;将这些项目的代码推送至一个指定的 Git 仓库&#xff0c;每个项目独占一个分支。 推送时若仓库不存在&#xff0c;则自动创建仓库。 分析 生成代码使用 Java 程序模拟&#xff0c;每个项目中模拟三个文件。Project.cpp 、Pro…