【C++进阶】二叉搜索树递归与非递归的模拟实现(附源码)

2023-11-12

一.什么是二叉搜索树

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

 根据二叉搜索树的性质,它的中序遍历结果就是一个升序列


二.二叉搜索树的模拟实现

节点 Node

在实现二叉搜索树之前,要先定义一个节点,成员变量包括左指针(left),右指针(right)和一个值 (key)

template<class K>
struct BSTNode
{
	BSTNode<K>* _left;
	BSTNode<K>* _right;
	K _key;

	BSTNode(const K& key)  //构造函数
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}
};

打印 InOrder

打印二叉搜索树树,就是对树进行中序遍历

这里有个小技巧,可以不用写 Getroot 函数就可以使用到类里面的成员变量:

        就是在函数里再套一个函数

具体看代码实现:

void InOrder()   //函数里面再套一个函数,真正实现中序遍历的是 _InOrder函数
{
	_InOrder(_root);
	cout << endl;
}

void _InOrder(Node* root)
{
	if (root == nullptr)
		return;

	_InOrder(root->_left);
	cout << root->_key << " ";
	_InOrder(root->_right);
}

插入 insert

在插入时,如果要插入的数据(key)已经存在,则返回false,若不存在,则完成插入操作,然后返回true

其实这刚好也完成了去重的操作。

插入操作:

        定义一个parent指针,记录当前节点的父节点,方便最后插入节点时的链接

        定义一个cur指针,用于遍历整个树。

根据二叉搜素树的性质:

        当key小于节点的 _key 时,更新parent,就到树的左边

        当key大于节点的 _key 时,更新parent,就到树的右边

        当cur为空时,跳出循环,进行节点间的链接操作(同样遵循二叉搜索树的性质)

bool Insert(const K& key)
{
	if (_root == nullptr)  //注意树为空的情况
	{
		_root = new Node(key);
		return true;
	}

	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
			return false;
	}

	cur = new Node(key);   
	if (parent->_key<key)   //链接
	{
		parent->_right = cur;
	}
	else
		parent->_left = cur;

	return true;

}

插入的递归实现  insertR

既然要递归,那么肯定要用到根节点,同样使用中序遍历那样的方式,函数里再套一个函数

其实理论还是和非递归的一样,只不过换成了调用函数,但这里有个小窍门,就是我们可以传根节点的引用,这样就不用定义一个父节点指针了,根据引用的特性,引用是一个变量的别名,当我们递归到下一层时,此时传过来的root就是这一层的父节点,直接链接就行了。

bool insertR(const K& key)
{
	return _insertR(_root, key);
}

bool _insertR(Node*& root, const K& key)
{
	if (root == nullptr)
	{
		Node* newroot = new Node(key);
		root = newroot;
		return true;
	}

	if (root->_key < key)
	{
		return _insertR(root->_right, key);
	}
	else if (root->_key > key)
	{
		return _insertR(root->_left, key);
	}
	else
		return false;
}

删除 erase

删除就有点复杂了,它分几种情况:

首先查找元素是否在二叉搜索树中,如果不存在,则返回, 否则要删除的结点可能分下面四种情
况:

        1.要删除的结点无孩子结点
        2. 要删除的结点只有左孩子结点
        3. 要删除的结点只有右孩子结点
        4. 要删除的结点有左、右孩子结点

前三种情况倒好解决,如果待删除的节点只有一个孩子,那么只需要把这个孩子根据二叉搜索树的性质托孤给它的父节点。

很显然,当有两个孩子时,托孤就行不通了,那么我们可不可以重新找一个符合条件的节点来充当父节点 ?

答案当然是可以,这就是替换法

替换法:

        找左子树的最大节点(在最右边),或是右子树的最小节点(在最左边)

代码实现:

bool erase(const K& key)
{
	Node* cur = _root;
	Node* parent = nullptr;
	while (cur)   //先查找待删除节点,没找到则返回false
	{
		if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_key > key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else   //找到了
		{
			if (cur->_left == nullptr)  //有一个孩子,且左子树为空
			{
				if (parent == nullptr)   //如果待删除节点是根节点,那么parent为空
				{
					_root = cur->_right;
					return true;
				}

			    if (parent->_left == cur)
				{
					parent->_left = cur->_right;
				}
				else
					parent->_right = cur->_right;

			}
			else if (cur->_right == nullptr)  //有一个孩子,且右子树为空
			{
				if (parent == nullptr)     //如果待删除节点是根节点,那么parent为空
				{
					_root = cur->_left;
				}

				if (parent->_left == cur)
				{
					parent->_left = cur->_left;
				}
				else
					parent->_right = cur->_left;
		
				}
			else //有两个孩子,替换法,这里是寻找左子树的最大节点
			{
				Node* parent = cur;
				Node* leftmax = cur->_left;
				while (leftmax->_right)   //找左子树最大的
				{
					parent = leftmax;
					leftmax = leftmax->_right;
				}

				std::swap(leftmax->_key, cur->_key);  //交换值
				if (parent->_left == leftmax)
				{
					parent->_left = leftmax->_left;
				}
				else
					parent->_right = leftmax->_left;

				cur = leftmax;
			}

				delete cur;  //删除节点
				return true;
		}

	}

			return false;   //没找到返回false
}

删除的递归实现 eraseR

同样使用函数套函数的方式。同样传root的引用

当有一个孩子或没有孩子的时候,可以直接链接,然后再删除;

当有两个孩子的时候,同样使用替换法,找到左子树的最大节点(或是右子树的最小节点),此时这个最大节点(或是最小节点)一定没有孩子,再递归一次,转换成没有孩子的情况

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 _eraseR(root->_right, key);
	}
	else if (root->_key > key)
	{
		return _eraseR(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;
			}

			std::swap(leftmax->_key, root->_key); 

			return _eraseR(root->_left, key);  //注意这里要传root->left,不能传leftmax,否                
                                               //则链接关系会对不上
		}
		delete del;   //删除节点
		return true;
	}
}

剩下接口

剩下的操作(查找find ,拷贝构造,重载赋值运算符,析构函数)都很简单了,就不一一讲述,都放在源码里了。


三.源码

Binary_Search_Tree.h

template<class K>
struct BSTNode
{
	BSTNode<K>* _left;
	BSTNode<K>* _right;
	K _key;

	BSTNode(const K& key)  //构造函数
		:_left(nullptr)
		,_right(nullptr)
		,_key(key)
	{}
};

template<class K>
class BSTree
{
    typedef BSTNode<K> Node;
public:
    BSTree()  //构造函数
		:_root(nullptr)
	{}
    void InOrder()   //函数里面再套一个函数,真正实现中序遍历的是 _InOrder函数
    {
	    _InOrder(_root);
	    cout << endl;
    }
    bool Insert(const K& key)
    {
	    if (_root == nullptr)  //注意树为空的情况
	    {
		    _root = new Node(key);
		    return true;
	    }

	    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
			    return false;
	    }

	    cur = new Node(key);   
	    if (parent->_key<key)   //链接
	    {
		    parent->_right = cur;
	    }
	    else
		    parent->_left = cur;

	    return true;

    }

    bool insertR(const K& key)   //插入的递归实现
    {
	    return _insertR(_root, key);
    }
    
    bool erase(const K& key)
    {
	    Node* cur = _root;
	    Node* parent = nullptr;
	    while (cur)   //先查找待删除节点,没找到则返回false
	    {
		    if (cur->_key < key)
		    {
		    	parent = cur;
		    	cur = cur->_right;
		    }
		    else if (cur->_key > key)
	    	{
		    	parent = cur;
	       		cur = cur->_left;
		    }
		    else   //找到了
		    {
		       	if (cur->_left == nullptr)  //有一个孩子,且左子树为空
			    {
			    	if (parent == nullptr)   //如果待删除节点是根节点,那么parent为空
			    	{
				    	_root = cur->_right;
				    	return true;
			    	}

			        if (parent->_left == cur)
			    	{
			       		parent->_left = cur->_right;
			    	}
			    	else
					    parent->_right = cur->_right;

			    }
			    else if (cur->_right == nullptr)  //有一个孩子,且右子树为空
			    {
			    	if (parent == nullptr)     //如果待删除节点是根节点,那么parent为空
			    	{
			    		_root = cur->_left;
			    	}

				    if (parent->_left == cur)
				    {
				    	parent->_left = cur->_left;
			    	}
				    else
				    	parent->_right = cur->_left;
		
				}
			    else //有两个孩子,替换法,这里是寻找左子树的最大节点
			    {
			    	Node* parent = cur;
			    	Node* leftmax = cur->_left;
			    	while (leftmax->_right)   //找左子树最大的
			    	{
			    		parent = leftmax;
			    		leftmax = leftmax->_right;
			    	}

			    	std::swap(leftmax->_key, cur->_key);  //交换值
			    	if (parent->_left == leftmax)
			    	{
			    		parent->_left = leftmax->_left;
				    }
			    	else
				    	parent->_right = leftmax->_left;

			    	cur = leftmax;
			    }

			    	delete cur;  //删除节点
				    return true;
		    }

	    }
			return false;   //没找到返回false
    }
    
    bool eraseR(const K& key)   //删除的递归实现
    {
    	return _eraseR(_root, key);
    }

    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;
	}

    bool findR(const K& key)   //查找的递归实现
	{
		return _findR(_root, key);
	}
    ~BSTree()   //析构函数
	{
		destroy(_root);
	}

	BSTree(const BSTree<K>& bst)  //拷贝构造
	{
		_root = copy(bst._root);
	}

	BSTree<K>& operator=(BSTree<K> bst)  //赋值重载
	{
		std::swap(_root, bst._root);

		return *this;
	}
private:
    void _InOrder(Node* root)
    {
	    if (root == nullptr)
	    	return;

	    _InOrder(root->_left);
	    cout << root->_key << " ";
	    _InOrder(root->_right);
    }
    
    bool _insertR(Node*& root, const K& key)
    {
	    if (root == nullptr)
	    {
		    Node* newroot = new Node(key);
		    root = newroot;
		    return true;
	    }

	    if (root->_key < key)
	    {
		    return _insertR(root->_right, key);
	    }
	    else if (root->_key > key)
	    {
		    return _insertR(root->_left, key);
	    }
	    else
		    return false;
    }
    
    bool _eraseR(Node*& root, const K& key)
    {
	    if (root == nullptr)  //没找到
		    return false;
			
	    if (root->_key < key)  //开始寻找待删除节点
	    {
		    return _eraseR(root->_right, key);
    	}
	    else if (root->_key > key)
	    {
	    	return _eraseR(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;
			    }

			    std::swap(leftmax->_key, root->_key); 

			 return _eraseR(root->_left, key);  //注意这里要传root->left,不能传leftmax,否                
                                               //则链接关系会对不上
		    }
		    delete del;   //删除节点
		    return true;
	    }
    }

    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;
	}
	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;
	}
    
    void destroy(Node* root)  //后序删除
	{
		if (root == nullptr)
			return;
		destroy(root->_left);
		destroy(root->_right);
		delete root;
		root = nullptr;
	}
private:
    Node* _root;
};

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【C++进阶】二叉搜索树递归与非递归的模拟实现(附源码) 的相关文章

  • WCF RIA 服务 - 加载多个实体

    我正在寻找一种模式来解决以下问题 我认为这很常见 我正在使用 WCF RIA 服务在初始加载时将多个实体返回给客户端 我希望两个实体异步加载 以免锁定 UI 并且我想利用 RIA 服务来执行此操作 我的解决方案如下 似乎有效 这种方法会遇到
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 用于检查类是否具有运算符/成员的 C++ 类型特征[重复]

    这个问题在这里已经有答案了 可能的重复 是否可以编写一个 C 模板来检查函数是否存在 https stackoverflow com questions 257288 is it possible to write a c template
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 将 VSIX 功能添加到 C# 类库

    我有一个现有的单文件生成器 位于 C 类库中 如何将 VSIX 项目级功能添加到此项目 最终目标是编译我的类库项目并获得 VSIX 我实际上是在回答我自己的问题 这与Visual Studio 2017 中的单文件生成器更改 https s
  • C#中如何移动PictureBox?

    我已经使用此代码来移动图片框pictureBox MouseMove event pictureBox Location new System Drawing Point e Location 但是当我尝试执行时 图片框闪烁并且无法识别确切
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 使用 Bearer Token 访问 IdentityServer4 上受保护的 API

    我试图寻找此问题的解决方案 但尚未找到正确的搜索文本 我的问题是 如何配置我的 IdentityServer 以便它也可以接受 授权带有 BearerTokens 的 Api 请求 我已经配置并运行了 IdentityServer4 我还在
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 如何序列化/反序列化自定义数据集

    我有一个 winforms 应用程序 它使用强类型的自定义数据集来保存数据进行处理 它由数据库中的数据填充 我有一个用户控件 它接受任何自定义数据集并在数据网格中显示内容 这用于测试和调试 为了使控件可重用 我将自定义数据集视为普通的 Sy
  • 垃圾收集器是否在单独的进程中运行?

    垃圾收集器是否在单独的进程中启动 例如 如果我们尝试测量某段代码所花费的进程时间 并且在此期间垃圾收集器开始收集 它会在新进程上启动还是在同一进程中启动 它的工作原理如下吗 Code Process 1 gt Garbage Collect
  • 什么时候虚拟继承是一个好的设计? [复制]

    这个问题在这里已经有答案了 EDIT3 请务必在回答之前清楚地了解我要问的内容 有 EDIT2 和很多评论 有 或曾经 有很多答案清楚地表明了对问题的误解 我知道这也是我的错 对此感到抱歉 嗨 我查看了有关虚拟继承的问题 class B p
  • 覆盖子类中的字段或属性

    我有一个抽象基类 我想声明一个字段或属性 该字段或属性在从该父类继承的每个类中具有不同的值 我想在基类中定义它 以便我可以在基类方法中引用它 例如覆盖 ToString 来表示 此对象的类型为 property field 我有三种方法可以
  • 如何使用 C# / .Net 将文件列表从 AWS S3 下载到我的设备?

    我希望下载存储在 S3 中的多个图像 但目前如果我只能下载一个就足够了 我有对象路径的信息 当我运行以下代码时 出现此错误 遇到错误 消息 读取对象时 访问被拒绝 我首先做一个亚马逊S3客户端基于我的密钥和访问配置的对象连接到服务器 然后创
  • WPF/C# 将自定义对象列表数据绑定到列表框?

    我在将自定义对象列表的数据绑定到ListBox in WPF 这是自定义对象 public class FileItem public string Name get set public string Path get set 这是列表
  • 如何从两个不同的项目中获取文件夹的相对路径

    我有两个项目和一个共享库 用于从此文件夹加载图像 C MainProject Project1 Images 项目1的文件夹 C MainProject Project1 Files Bin x86 Debug 其中有project1 ex
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • C# - OutOfMemoryException 在 JSON 文件上保存列表

    我正在尝试保存压力图的流数据 基本上我有一个压力矩阵定义为 double pressureMatrix new double e Data GetLength 0 e Data GetLength 1 基本上 我得到了其中之一pressur

随机推荐

  • 刷脸支付以人脸为密码的支付方式蔚然成风

    在移动支付高速发展的现在 人们的每一次支付行为都与移动支付息息相关 尤其在中国 移动支付的使用率已经远远超出现金支付 人们对现金不再产生依赖 刷脸支付诞生后 人们对手机也不再产生依赖 因为出行仅靠刷脸即可 我国的移动支付水平在全国都处于领先
  • Springboot 多模块集成mybatis提示:Invalid bound statement (not found)

    1 第一步 检查提示错误信息接口namespace 文件是否对应 MyBatis 文件Mapper 接口定义与Mapper xml 文件定义一致 2 整体项目结构截图如下 从项目结构来看 包含两个子模块包含MyBatis 的mapper 文
  • Element之el-switch上显示文字

    如果我们想要在Element组件库中的switch开关组件上显示文字该怎么做 1 Html部分
  • pclint html报告,PC-lint 9 + 中文手册

    实例简介 PCLINT是一种代码检查工具 还包括中文文档 实例截图 核心代码 Pc Lint9 pclint autorun inf DOS ins choose16 exe choose exe install exe lint exe
  • ACE_Message_Block例子

    include ace OS h include ace Message Block h include ace FILE IO h include
  • 【Absible学习】Ansible常用模块---包管理模块

    yum repository模块 yum repository模块可以管理远程主机上的yum仓库 模块参数 参数 说明 name 必须参数 用于指定要操作的唯一的仓库ID 也就是 repo 配置文件中每个仓库对应的 中括号 内的仓库ID b
  • 深度学习--手写数字识别<一>

    手写字符识别数据集THE MNIST DATABASE of handwritten digits http yann lecun com exdb mnist 其中训练集60000例 测试集10000例 加载数据 1 读取数据 usr b
  • 博客营销分析:博客营销的优势+方法技巧+成功案例介绍

    博客营销分析 博客营销的优势 方法技巧 成功案例介绍 一 博客营销是什么 博客营销的定义 首先 先为大家介绍博客的定义 博客是一个可以发布文字 链接 图片 视频的网站 是实现信息分享与交流的平台 而博客营销是博主通过博客内容向网站用户传递信
  • [整理]MySQL8-安装、启动、卸载、初始密码、忘记密码(CentOS,Ubuntu,Widows)

    系统和MySQL更新换代都很快 我用到时会顺手整理在这里 内容没什么技术含量 也不保障内容的全和新 每次遇到问题网上搜索一下很容易找到解决方法的 我工作电脑用Widows Ubuntu WSL 服务器用CentOS 所以三个系统都安装过 C
  • 【Python】字典内容写入json文件

    Python中有序字典和无序字典 一键多值字典 Python将字典内容写入json文件 1 无序字典 目前了解三种 在Python中直接默认的是无序字典 这种不会按照你插入的顺序排序 即使你对字典排序后 返回的也是一个list变量 而不是字
  • echarts的图表双击事件、单击某块、滚轮放大缩小

    echarts的图表双击事件 dblclick
  • 华为机试:HJ2 计算某字符出现次数

    描述 写出一个程序 接受一个由字母 数字和空格组成的字符串 和一个字符 然后输出输入字符串中该字符的出现次数 不区分大小写字母 数据范围 1 le n le 1000 1 n 1000 输入描述 第一行输入一个由字母和数字以及空格组成的字符
  • Android 源码分析 - 系统 - Settings

    core 源代码 core java android provider Settings java 定义一系列配置项名称 索引 常量 SettingsProvider apk 源代码位于 frameworks base packages S
  • 【Vuex入门】——(四)Mutation

    一 Mutation的作用 更改 Vuex 的store 中的状态的唯一方法是提交 mutation Vuex 中的 mutation 非常类似于事件 每个 mutation 都有一个字符串的 事件类型 type 和 一个 回调函数 han
  • Python语言程序设计 习题6

    一 选择题 1 下列Python数据中其元素可以改变的是 A A 列表 B 元组 C 字符串 D 数组 2 表达式 2 in 1 2 3 4 的值是 D A Yes B No C True D False print 2 in 1 2 3
  • python是什么意思中文、好学吗-零基础学python难吗?好学吗?

    Python是一种什么语言 Python是一种计算机程序设计语言 你可能已经听说过很多种流行的编程语言 比如非常难学的C语言 非常流行的Java语言 适合初学者的Basic语言 适合网页编程的JavaScript语言等 Python是他们其
  • 如何使用下标遍历二维数组

    点击打开链接 int my 2d array 10 10 假定数组my 2d array 已经预先被填充了数据 int i j 遍历这个数组 for i 0 i lt 10 i 向下遍历各行 for j 0 j lt 10 j 穿越各列 p
  • Python:Unused import statement 解决方法

    Python 学习 21052501 1 Unused import statement 解决方法 Pycharm file 菜单下有Invalidate caches Restart菜单栏 点击清除缓存重新启动Pycharm即可 2 In
  • 反思深度学习与传统计算机视觉的关系

    来源 算法与数学之美 某种程度上 深度学习最大的优势就是自动创建没有人会想到的特性能力 如今 深度学习在众多领域都有一席之地 尤其是在计算机视觉领域 尽管许多人都为之深深着迷 然而 深网就相当于一个黑盒子 我们大多数人 甚至是该领域接受过培
  • 【C++进阶】二叉搜索树递归与非递归的模拟实现(附源码)

    一 什么是二叉搜索树 二叉搜索树又称二叉排序树 它或者是一棵空树 或者是具有以下性质的二叉树 根据二叉搜索树的性质 它的中序遍历结果就是一个升序列 二 二叉搜索树的模拟实现 节点 Node 在实现二叉搜索树之前 要先定义一个节点 成员变量包
Powered by Hwhale