C++:二叉搜索树模拟实现(KV模型)

C++:二叉搜索树模拟实现(KV模型)

  • 前言
  • 模拟实现KV模型
  • 1. 节点封装
  • 2、前置工作(默认构造、拷贝构造、赋值重载、析构函数等)
  • 2. 数据插入(递归和非递归版本)
  • 3、数据删除(递归和非递归版本)
    • 3.1 查找待删除节点位置
    • 3.2 删除数据及相关节点调整
    • 3.3 完整代码以及递归和非递归版本
  • 四、查找数据
  • 五、中序遍历
  • 六、所有代码

前言

 二叉搜索树又称二叉排序树,他对数据有严格的要求,具体表现在以下几个方面:

  1. 如果一个根节点的左子树不为空,则左子树中所有节点的值都必须小于根节点的值;如果它的右子树不为空,则右子树中所有节点的值都必须大于根节点的值。
  2. 它的左右子树也都必须是一个二叉搜索树,也都必须满足第一条。
  3. 二叉搜索树中的每个节点都是唯一的,不允许重复!!!
    在这里插入图片描述

 二叉搜索树的实际应用主要分为K模型和KV模型。

  1. K模型即Key作为关键码,二叉搜索树中只存储Key一个数据。而关键码则是待搜索的值。比如:我们经常通过软件查找是否存在某个单词,是否拼写正确。
  2. KV模型存储的数据中,每个Key对应一个Value,即键值对<Key, Value>。 我们经常通过Key去查找对应的Val.比如:我们通过英文来查找对应的中文,就是一个最常见的KV场景。

模拟实现KV模型

1. 节点封装

由于是KV模型,我们需要存储Key和Value俩个值。同时二叉搜索树也是二叉树,我们需要它的左右节点。因此节点疯转如下:

template<class K, class V>
struct BSTreeNode
{
	K _key;
	V _value;
	BSTreeNode<K, V>* _left;
	BSTreeNode<K, V>* _right;

	//默认构造函数, 用于后续new创建节点
	BSTreeNode(const K& key, const V& value)
		:_key(key)
		, _value(value)
		, _right(nullptr)
		, _left(nullptr)
	{}
};

2、前置工作(默认构造、拷贝构造、赋值重载、析构函数等)

接下来是KV模型封装的框架,以及默认构造、拷贝构造、赋值重载、析构函数。比较简单,就直接给出代码了哈。

template<class K, class V>
	class BSTree
	{
		typedef BSTreeNode<K, V> Node;//节点重命名
	public:
		//默认构造
		BSTree()
			:_root(nullptr)
		{}

		//拷贝构造
		BSTree(BSTree<K, V>& t)
		{
			_root = Copy(t._root);
		}

		//赋值重载
		BSTree<K, V>& operator=(BSTree<K, V> t)
		{
			swap(_root, t._root);
			return *this;
		}

		//析构函数
		~BSTree()
		{
			Destory(_root);
		}
	private:
		Node* _root = nullptr;
	};
}

2. 数据插入(递归和非递归版本)

首先我们需要查找数据待插入的位置(为了保证插入数据后整体依然是一颗二叉搜索树).。同时查找插入位置时,只有key是有严格要求的,Value只是附带。
即:如果根节点为空,即是待插入数据位置;否则开始查找,如果待插入数据大于根节点往右子树节点走;如果待插入数据小于根节点往左子树节点走。不断循环,直到查找到空节点时,即为数据待插入的位置;如果查找到的大小和待插入数据值相等则返回false(确保二叉搜索树中的每个节点唯一)

【非递归版本】:

bool Insert(const K& key, const V& value)
{
	if (_root == nullptr)//根节点为空
	{
		_root = new Node(key, value);
		return true;
	}

	Node* cur = _root;
	Node* parent = nullptr;//后续插入数据链接时,需要和父节点相连
	while (cur)
	{
		if (cur->_key > key)//待插入数据小于当前节点,往左子树查找
		{
			parent = cur;
			cur = cur->_left;
		}
		else if(cur->_key < key)//待插入数据大于当前节点,往右子树查找
		{
			parent = cur;
			cur = cur->_right;
		}
		else//待插入数据等于当前节点,不允许插入
		{
			return false;
		}
	}

	//链接
	Node* newNode = new Node(key, value); 
	//链接时,我们无法确定插入节点时在父节点的左边还是右边,需要进一步比较
	if (parent->_key > key)
		parent->_left = newNode;
	else
		parent->_right = newNode;
	return true;
}

【递归版本】:

bool InsertR(const K& key, const V& value)
{
	//由于我们查找位置需要从根节点开始查找,所以这里通过另一个函数来传递实现
	return _InsertR(_root, key, value);
}
	
bool _InsertR(Node*& root, const K& key, const V& value)
{
	if (root == nullptr)
	{
		//注意上述我们形参都是引用,所以不用新增Parent节点
		root = new Node(key, value);
		return true;
	}

	if (root->_key > key)//待插入数据小于当前节点,往左子树查找
		return _InsertR(root->_left, key, value);
	else if (root->_key < key)//待插入数据大于当前节点,往右子树查找
		return _InsertR(root->_right, key, value);
	else
		return false;
}

3、数据删除(递归和非递归版本)

3.1 查找待删除节点位置

删除数据,我们首先需要和插入数据一样,先查找到待删除节点。和插入类似就不多说了。

【查找待删除数据】:

bool Erase(const K& key)
{
	if (_root == nullptr)//为空即不存在待删除数据
		return false;

	Node* cur = _root;
	Node* parent = nullptr;
	while (cur)
	{
		if (cur->_key > key)//待删除数据小于当前节点,往左子树查找
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_key < key)//待删除数据大于当前节点,往右子树查找
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{
			//当前位置即为待删除节点,装备删除数据	
			
		}
	}
	return false;//整棵树中不存在待删除数据
}

3.2 删除数据及相关节点调整

插找到待删除数据后,显然如果只是简单将该节点删除,有可能将不满足二叉搜索树的要求,那怎么办呢?
删除数据分为以下三种情况:

  1. 左子树为空

左子树为空主要分为以下情形:右子树为空,左子树不为空;左右子树均为空(省略)。
在这里插入图片描述
 不管上述那种情况,我们发现只需将父节点的下一个节点指向待删除节点的右指针即可。但需要注意的是,如果待删除节点为根节点,它将没有父节点,需要单独处理。

【代码实现】:

if (cur->_left == nullptr)//左子树为空
{
	if (parent == _root)//cur为根节点
	{
		_root = cur->_right;
	}
	else
	{
		if (parent->_key > cur->_key)//待删除节点在父节点左子树中
		{
			parent->_left = cur->_right;
		}
		else//待删除节点在父节点右子树中
		{
			parent->_right = cur->_right;
		}
	}
	delete cur;
}
  1. 右子树为空

右子树为空分为单纯右子树为空和左右子树均为空(省)。具体处理方式和左子树为空类似就不多说了。
在这里插入图片描述
【代码实现】:

//左右子树均不为空,查找右子树最小元素进行交换后删除
if (parent == _root)//cur为根节点
{
		_root = cur->_left;
	}
	else
	{
		if (parent->_key > cur->_key)
		{
			parent->_left = cur->_left;
		}
		else
		{
			parent->_right = cur->_left;
		}
	}
	delete cur;
}
  1. 左右子树均不为空

这种情况我们可以查找左子树最大值或右子树最小值和待删除删除节点进行交换,交换后我们可以转化为上述两种子问题来删除数据。(接下来博主以交换右子树最小值为例)
在这里插入图片描述

Node* subLeft = cur->_right;
Node* parent = cur;
while (subLeft->_left)
{
	parent = cur;
	subLeft = subLeft->_left;
}
//交换
swap(cur->_key, subLeft->_key);
swap(cur->_value, subLeft->_value);
//删除
if (parent->_right = subLeft)
{
	parent->_right = subLeft->_right;
}
else
{
	parent->_left = subLeft->_right;
}
delete subLeft;

3.3 完整代码以及递归和非递归版本

递归思路和非递归差球不多,就不一一分析了,下面直接给出两种实现方式代码。

【非递归版本】:

bool Erase(const K& key)
{
	if (_root == nullptr)
		return false;

	Node* cur = _root;
	Node* parent = nullptr;
	while (cur)
	{
		if (cur->_key > key)
		{
			parent = cur;
			cur = cur->_left;
		}
		else if (cur->_key < key)
		{
			parent = cur;
			cur = cur->_right;
		}
		else
		{//装备删除数据
			if (cur->_left == nullptr)//左子树为空
			{
				if (parent == _root)//cur为根节点
				{
					_root = cur->_right;
				}
				else
				{
					if (parent->_key > cur->_key)
					{
						parent->_left = cur->_right;
					}
					else
					{
						parent->_right = cur->_right;
					}
				}
				delete cur;
			}
			else if (cur->_right == nullptr)//右子树为空
			{
				if (parent == _root)//cur为根节点
				{
					_root = cur->_left;
				}
				else
				{
					if (parent->_key > cur->_key)
					{
						parent->_left = cur->_left;
					}
					else
					{
						parent->_right = cur->_left;
					}
				}
				delete cur;
			}
			else
			{//左右子树均不为空,查找右子树最小元素进行交换后删除
				Node* subLeft = cur->_right;
				Node* parent = cur;
				while (subLeft->_left)
				{
					parent = cur;
					subLeft = subLeft->_left;
				}
				//交换
				swap(cur->_key, subLeft->_key);
				swap(cur->_value, subLeft->_value);
				//删除
				if (parent->_right = subLeft)
				{
					parent->_right = subLeft->_right;
				}
				else
				{
					parent->_left = subLeft->_right;
				}
				delete subLeft;
			}
			return true;
		}
	}
	return false;
}

【递归版本】:

//删除:递归版本
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)//转化成递归子问题,在左子树中删除key
		return _EraseR(root->_left, key);
	else if (root->_key < key)//转化成递归子问题,在右子树中删除key
		return _EraseR(root->_right, key);
	else
	{//删除数据
		if (root->_left == nullptr)
		{
			Node* del = root;
			root = root->_right;
			delete del;
			return true;
		}
		else if (_root->_right == nullptr)
		{
			Node* del = root;
			root = root->_left;
			delete del;
			return true;
		}
		else
		{
			Node* subLeft = root->_right;
			while (subLeft->_left)
			{
				subLeft = subLeft->_left;
			}
			//交换
			swap(root->_key, subLeft->_key);
			swap(root->_value, subLeft->_value);

			return _EraseR(root->_right, key); 
		}

	}
}

四、查找数据

【递归版本】:

//查找:递归版本
Node* FindR(const K& key)
{
	return _FindR(_root, key);
}
Node* _FindR(Node*& root, const K& key)
{
	if (root == nullptr)
		return nullptr;
	if (root->_key > key)
		return _FindR(root->_left, key);
	else if (root->_key < key)
		return _FindR(root->_right, key);
	else
		return root;
}

【非递归版本】:

//查找:非递归版本
Node* Find(const K& key)
{
	Node* cur = _root;
	while (cur)
	{
		if (cur->_key > key)
			cur = cur->_left;
		else if (cur->_key < key)
			cur = cur->_right;
		else
		{//找到了
			return cur;
		}
	}
	return nullptr;
}

五、中序遍历

//中序遍历
void Inorder()
{
	_Inorder(_root);
	cout << endl;
}

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

六、所有代码

gitee:所有代码及测试代码

namespace KeyValue
{
	template<class K, class V>
	struct BSTreeNode
	{
		K _key;
		V _value;
		BSTreeNode<K, V>* _left;
		BSTreeNode<K, V>* _right;

		//默认构造函数
		BSTreeNode(const K& key, const V& value)
			:_key(key)
			, _value(value)
			, _right(nullptr)
			, _left(nullptr)
		{}
	};

	template<class K, class V>
	class BSTree
	{
		typedef BSTreeNode<K, V> Node;
	public:
//
		//默认构造
		BSTree()
			:_root(nullptr)
		{}

		//拷贝构造
		BSTree(BSTree<K, V>& t)
		{
			_root = Copy(t._root);
		}

		//赋值重载
		BSTree<K, V>& operator=(BSTree<K, V> t)
		{
			swap(_root, t._root);
			return *this;
		}

		//析构函数
		~BSTree()
		{
			Destory(_root);
		}
//
		//插入, 非递归版本
		bool Insert(const K& key, const V& value)
		{
			if (_root == nullptr)
			{
				_root = new Node(key, value);
				return true;
			}

			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if(cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{
					return false;
				}
			}

			//链接
			Node* newNode = new Node(key, value); 
			if (parent->_key > key)
				parent->_left = newNode;
			else
				parent->_right = newNode;
			return true;
		}

		// 插入: 递归遍布
		bool InsertR(const K& key, const V& value)
		{
			return _InsertR(_root, key, value);
		}
/
		//查找:非递归版本
		Node* Find(const K& key)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_key > key)
					cur = cur->_left;
				else if (cur->_key < key)
					cur = cur->_right;
				else
				{//找到了
					return cur;
				}
			}
			return nullptr;
		}

		//查找:递归版本
		Node* FindR(const K& key)
		{
			return _FindR(_root, key);
		}
/
		//删除:非递归版本
		bool Erase(const K& key)
		{
			if (_root == nullptr)
				return false;

			Node* cur = _root;
			Node* parent = nullptr;
			while (cur)
			{
				if (cur->_key > key)
				{
					parent = cur;
					cur = cur->_left;
				}
				else if (cur->_key < key)
				{
					parent = cur;
					cur = cur->_right;
				}
				else
				{//装备删除数据
					if (cur->_left == nullptr)//左子树为空
					{
						if (parent == _root)//cur为根节点
						{
							_root = cur->_right;
						}
						else
						{
							if (parent->_key > cur->_key)
							{
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right = cur->_right;
							}
						}
						delete cur;
					}
					else if (cur->_right == nullptr)//右子树为空
					{
						if (parent == _root)//cur为根节点
						{
							_root = cur->_left;
						}
						else
						{
							if (parent->_key > cur->_key)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
						}
						delete cur;
					}
					else
					{//左右子树均不为空,查找右子树最小元素进行交换后删除
						Node* subLeft = cur->_right;
						Node* parent = cur;
						while (subLeft->_left)
						{
							parent = cur;
							subLeft = subLeft->_left;
						}
						//交换
						swap(cur->_key, subLeft->_key);
						swap(cur->_value, subLeft->_value);
						//删除
						if (parent->_right = subLeft)
						{
							parent->_right = subLeft->_right;
						}
						else
						{
							parent->_left = subLeft->_right;
						}
						delete subLeft;
					}
					return true;
				}
			}
			return false;
		}

		//删除:递归版本
		bool EraseR(const K& key)
		{
			return _EraseR(_root, key);
		}
/
		//中序遍历
		void Inorder()
		{
			_Inorder(_root);
			cout << endl;
		}
		void _Inorder(Node* root)
		{
			if (root == nullptr)
				return;
			_Inorder(root->_left);
			cout << root->_key << "->" << root->_value << " " << endl;
			_Inorder(root->_right);
		}

	private:
		Node* Copy(Node*& root)
		{
			if (root == nullptr)
				return nullptr;
			Node* newRoot = new Node(root->_key, root->_value);
			newRoot->_left = Copy(root->_left);
			newRoot->_right = Copy(root->_right);
			return newRoot;
		}

		void Destory(Node*& root)
		{
			if (root == nullptr)
				return;
			Destory(root->_right);
			Destory(root->_left);
			delete root;
			root = nullptr;
		}

		bool _EraseR(Node*& root, const K& key)
		{
			if (root == nullptr)
				return false;
			if (root->_key > key)
				return _EraseR(root->_left, key);
			else if (root->_key < key)
				return _EraseR(root->_right, key);
			else
			{//删除数据
				if (root->_left == nullptr)
				{
					Node* del = root;
					root = root->_right;
					delete del;
					return true;
				}
				else if (_root->_right == nullptr)
				{
					Node* del = root;
					root = root->_left;
					delete del;
					return true;
				}
				else
				{
					Node* subLeft = root->_right;
					while (subLeft->_left)
					{
						subLeft = subLeft->_left;
					}
					//交换
					swap(root->_key, subLeft->_key);
					swap(root->_value, subLeft->_value);

					return _EraseR(root->_right, key); 
				}

			}
		}

		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->_left, key, value);
			else if (root->_key < key)
				return _InsertR(root->_right, key, value);
			else
				return false;
		}

		Node* _FindR(Node*& root, const K& key)
		{
			if (root == nullptr)
				return nullptr;
			if (root->_key > key)
				return _FindR(root->_left, key);
			else if (root->_key < key)
				return _FindR(root->_right, key);
			else
				return root;
		}

		Node* _root = nullptr;
	};
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【芯片设计- RTL 数字逻辑设计入门 15 -- 函数实现数据大小端转换】

文章目录 函数实现数据大小端转换函数语法函数使用的规则Verilog and Testbench综合图VCS 仿真波形 函数实现数据大小端转换 在数字芯片设计中&#xff0c;经常把实现特定功能的模块编写成函数&#xff0c;在需要的时候再在主模块中调用&#xff0c;以提高代码的复用性和提高设…

《MySQL 简易速速上手小册》第6章:MySQL 复制和分布式数据库(2024 最新版)

文章目录 6.1 设置和管理复制6.1.1 基础知识6.1.2 重点案例&#xff1a;使用 Python 设置 MySQL 主从复制6.1.3 拓展案例 1&#xff1a;自动故障转移6.1.4 拓展案例 2&#xff1a;设置双主复制 6.2 复制的类型和策略6.2.1 基础知识6.2.2 重点案例&#xff1a;使用 Python 设置半…

目标检测 | 卷积神经网络(CNN)详细介绍及其原理详解

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。卷积神经网络&#xff08;Convolutional Neural Network&#xff0c;CNN&#xff09;是一种深度学习模型&#xff0c;主要用于图像识别和计算机视觉任务。它的设计灵感来自于生物学中视觉皮层的工作原理。CNN的核心思想是通…

极智一周 | 国产CPU系列汇总、鲲鹏、飞腾、平头哥 And so on

欢迎关注我的公众号 [极智视界]&#xff0c;获取我的更多技术分享 大家好&#xff0c;我是极智视界&#xff0c;带来本周的 [极智一周]&#xff0c;关键词&#xff1a;国产CPU系列汇总、鲲鹏、飞腾、平头哥 And so on。 邀您加入我的知识星球「极智视界」&#xff0c;星球目前…

一分钟了解电脑关机快捷键是什么!

在日常使用电脑的过程中&#xff0c;了解一些基本的快捷键是提高效率的关键之一。其中&#xff0c;电脑关机快捷键是一个方便且迅速的操作&#xff0c;使您可以在不用通过烦琐的菜单操作的情况下&#xff0c;快速关机电脑。在本文中&#xff0c;我们将探讨电脑关机快捷键是什么…

Linux——进程池(管道)

经过了管道的介绍之后&#xff0c;我们可以实现了进程间通信&#xff0c;现在我就来简单介 绍一下管道的应用场景——进程池。1. 引入 在我们的编码过程中&#xff0c;不乏会听到&#xff0c;内存池&#xff0c;进程池&#xff0c;空间配置器等等名词&#xff0c;这些是用来干…

NLP_神经概率语言模型(NPLM)

文章目录 NPLM的起源NPLM的实现1.构建实验语料库2.生成NPLM训练数据3.定义NPLM4.实例化NPLM5.训练NPLM6.用NPLM预测新词 NPLM小结 NPLM的起源 在NPLM之前&#xff0c;传统的语言模型主要依赖于最基本的N-Gram技术&#xff0c;通过统计词汇的共现频率来计算词汇组合的概率。然而…

【Linux】SystemV IPC

进程间通信 一、SystemV 共享内存1. 共享内存原理2. 系统调用接口&#xff08;1&#xff09;创建共享内存&#xff08;2&#xff09;形成 key&#xff08;3&#xff09;测试接口&#xff08;4&#xff09;关联进程&#xff08;5&#xff09;取消关联&#xff08;6&#xff09;释…

5周年狂欢,WeTrade众汇积分商城又送车啦!

各位投资者&#xff1a;新年好啊&#xff01; WeTrade众汇承诺积分商城所有礼品&#xff0c;不论价值大小&#xff0c;送出均为真实有效&#xff0c;不做虚假宣传。 WeTrade众汇继2018年9月28日送出特斯拉Model X后&#xff0c;又一次迎来了第二位在积分商城兑换豪车的客户! …

(全网最全)微型计算机原理与接口技术第六版课后习题答案-周荷琴,冯焕清-第8章中断和可编程中断控制器8259A-中国科学技术大学出版社

含有“AI:”开头的题目的答案是问chat的&#xff0c;看个乐就行&#xff0c;不一定正确 1。 什么叫中断&#xff1f;中断的主要功能是什么&#xff1f; 答:当CPU正在处某件事情的时候,外部发生的某一事件请求CPU迅速去处理,于是,CPU暂时中止当前工作,转去处理所发生的事件,中…

《MySQL 简易速速上手小册》第4章:数据安全性管理(2024 最新版)

文章目录 4.1 用户认证和权限控制4.1.1 基础知识4.1.2 重点案例&#xff1a;使用 Python 管理 MySQL 用户权限4.1.3 拓展案例 4.2 防止 SQL 注入和其他安全威胁4.2.1 基础知识4.2.2 重点案例&#xff1a;使用 Python 和 MySQL 进行安全的数据查询4.2.3 拓展案例 4.3 数据加密和…

算法练习-二叉搜索树中的搜索(思路+流程图+代码)

难度参考 难度&#xff1a;中等 分类&#xff1a;二叉树 难度与分类由我所参与的培训课程提供&#xff0c;但需要注意的是&#xff0c;难度与分类仅供参考。且所在课程未提供测试平台&#xff0c;故实现代码主要为自行测试的那种&#xff0c;以下内容均为个人笔记&#xff0c;旨…

CUDA简介

CPUGPU异构计算 GPU计算并不是指单独的GPU计算&#xff0c;而是指CPUGPU的异构计算。一块单独的GPU是无法独立的完成所有计算任务的&#xff0c;它必须在CPU的调度下才能完成特定的任务。CPU更适合进行逻辑复杂低并行的程序&#xff0c;GPU更适合逻辑简单高并行的任务。这主要…

问题:必须坚持以中国式现代化推进中华民族伟大复兴,既不走封闭僵化的老路,也不走 #媒体#知识分享

问题&#xff1a;必须坚持以中国式现代化推进中华民族伟大复兴&#xff0c;既不走封闭僵化的老路&#xff0c;也不走 A、中国特色社会主义道路 B、改革开放之路 C、改旗易帜的邪路 D、中国式现代化之路 参考答案如图所示

HarmonyOS 鸿蒙 ArkTS 双色旋转动画效果

下载地址&#xff1a; https://download.csdn.net/download/weixin_54226053/88818859 也可以点击顶部的资源下载

【Git】Windows下通过Docker安装GitLab

私有仓库 前言基本思路拉取镜像创建挂载目录创建容器容器启动成功登录仓库设置中文更改密码人员审核配置邮箱 前言 由于某云存在人数限制&#xff0c;这个其实很好理解&#xff0c;毕竟使用的是云服务器&#xff0c;人家也是要交钱的。把代码完全放在别人的服务器上面&#xf…

Qt网络编程-ZMQ的使用

不同主机或者相同主机中不同进程之间可以借助网络通信相互进行数据交互&#xff0c;网络通信实现了进程之间的通信。比如两个进程之间需要借助UDP进行单播通信&#xff0c;则双方需要知道对方的IP和端口&#xff0c;假设两者不在同一主机中&#xff0c;如下示意图&#xff1a; …

C#,十进制展开数(Decimal Expansion Number)的算法与源代码

1 十进制展开数 十进制展开数&#xff08;Decimal Expansion Number&#xff09;的计算公式&#xff1a; DEN n^3 - n - 1 The decimal expansion of a number is its representation in base -10 (i.e., in the decimal system). In this system, each "decimal place…

戴上HUAWEI WATCH GT 4,解锁龙年新玩法

春节将至&#xff0c;华为WATCH GT 4作为一款颜值和实力并存的手表&#xff0c;能为节日增添了不少趣味和便利。无论你是钟情于龙年表盘或定制属于自己的表盘&#xff0c;还是过年用来抢红包或远程操控手机拍全家福等等&#xff0c;它都能成为你的“玩伴”。接下来&#xff0c;…

C++后端开发之Sylar学习三:VSCode连接Ubuntu配置Gitee

C后端开发之Sylar学习三&#xff1a;VSCode连接Ubuntu配置Gitee 为了记录学习的过程&#xff0c;学习Sylar时写的代码统一提交到Gitee仓库中。 Ubuntu配置Gitee 安装git sudo apt-get install -y git配置用户名和邮箱 git config --global user.name 用户名 …
最新文章