c++:(map和set的底层简单版本,红黑树和AVL树的基础) 二叉搜索树(BST)底层和模拟实现

文章目录

  • 二叉搜索树的概念
  • 二叉搜索树的操作
    • 二叉搜索树的查找find
  • 二叉搜索树的模拟实现
    • 构造节点
    • insert
    • find
    • erase(细节巨多,面试可能会考)
      • a.叶子节点
      • b.有一个孩子
        • 左孩子
        • 右孩子
      • c.有两个孩子
        • 注意:
      • erase代码
    • 中序遍历
  • 二叉搜索树的应用
    • k模型
      • k模型模拟实现的总代码
    • k-value模型
      • k-value模型模拟实现的总代码
  • 二叉搜索树的不足
  • AVL树和红黑树的出现
  • 总结


二叉搜索树的概念

二叉搜索树,它的左子树的值比根的值小,右子树的值比根的值大
在这里插入图片描述
比如这一树,根节点的值8比左子树所有节点都大,比右子树的所有节点都小.

二叉搜索树的操作

二叉搜索树的查找find

因为二叉树有以上特性,所有使得它在搜索方面有极大的优势.
比如我们要找值为7的节点在不在
1.我们从根节点开始找,因为7<根节点的值8,所有根节点在左子树
在这里插入图片描述
2.现在根节点的值为3<7,所有在3的右子树中
在这里插入图片描述
3.现在根节点的值为6<7,所有在6的右子树中,刚好右子树的节点为7.
在这里插入图片描述
二叉搜索树最多寻找高度次,如果走到空还没有找到,说明这个值不存在

二叉搜索树的模拟实现

构造节点

	template<class K>
	struct BSTreeNode
	{
		typedef BSTreeNode<K> Node;
		Node* _left;
		Node* _right;
		K _val;

		BSTreeNode(const K& val)
			:_left(nullptr)
			, _right(nullptr)
			, _val(val)
		{}
	};

_val里面存节点的值

insert

bool insert(const K& val)
{
	//a.树为空,直接构造新节点赋值给根节点
	if (_root == nullptr)
	{
		_root = new Node(val);
		return true;
	}
	Node* parent = nullptr;
	Node* cur = _root;
	//找到空的节点进行插入
	while (cur)
	{
		if (cur->_val < val)
		{
			parent = cur;
			cur = cur->_right;
		}
		else if (cur->_val > val)
		{
			parent = cur;
			cur = cur->_left;
		}
		// 二叉搜索树默认不允许重复
		else
		{
			return false;
		}
	}
	cur = new Node(val);
	if (parent->_val < val)
	{
		parent->_right = cur;
	}
	else
	{
		parent->_left = cur;
	}
	return true;
}

插入有两种情况
a.树为空,直接构造新节点赋值给根节点
b.树不为空,按照二叉树的性质找到应该插入的空位置插入.

注意:
在b情况下,要找到新节点的位置,也要找到该节点的父亲节点,这样才能进行链接

假设要插入0节点,不光要找到0节点应该放的位置,还要找到0节点的父亲1,将他们链接起来
在这里插入图片描述

find

bool find(const K& val)
{
	Node* cur = _root;
	while (cur)
	{
		if (cur->_val < val)
		{
			cur = cur->_right;
		}
		else if (cur->_val > val)
		{
			cur = cur->_left;
		}
		else
		{
			return true;
		}
	}
	return false;
}

按照二叉搜索树的概念,比根大的往右走,比根小的往左走.
找到返回true,找不到返回false

erase(细节巨多,面试可能会考)

erase里面的细节很多,要细品.

删除的节点有多种可能

a.叶子节点

在这里插入图片描述

比如这棵树我们要删除4节点,就只需要找到4节点和它的父亲节点6,让父亲节点6指向空,再删除4节点.

b.有一个孩子

特殊情况
要删除的是根节点,此时要更新新的根节点10.
在这里插入图片描述

if (_root == cur)
{
	_root = cur->_right;
	delete cur;
}
左孩子

右为空,父亲指向我的左
有一个左孩子,说明右子树为空.
此时要让父亲指向3的左边,此时不清楚是父亲的左边还是父亲的右边指向1节点

父亲的左指向我的左

父亲的右指向我的左
在这里插入图片描述
代码实现

if (cur->_right == nullptr)
{
	//删除头节点
	if (_root == cur)
	{
		_root = cur->_left;
		delete cur;
	}
	else
	{
		if (parent->_right == cur)
			parent->_right = cur->_left;
		else
			parent->_left = cur->_left;
		delete cur;

	}
}
右孩子

左为空, 父亲指向我的右

//左为空, 父亲指向我的右
else if (cur->_left == nullptr)
{
	//删除头节点
	if (_root == cur)
	{
		_root = cur->_right;
		delete cur;
	}
	else
	{
		if (parent->_right == cur)
			parent->_right = cur->_right;
		else
			parent->_left = cur->_right;
		delete cur;
	}
}

右孩子的判断和左孩子类似,方向反过来而已.

c.有两个孩子

在这里插入图片描述
找到左边的最大值或者右边的最小值,与目标值进行替换.
这里以右边的最小值为例.

我们寻找右边的最小值时,同时要找它的父亲节点,因为要对它的父亲节点进行修改.
找到右边的最小值为4,将4覆盖到cur上面,再删除right_min这个节点.
在这里插入图片描述

注意:

因为是寻找右子树的最小值,所以这个最小值理论上应该没有左子树.
如果有左子树,说明有更小的值.但是可能会有右子树.
所有要让right_min_parent左节点指向right_min的右节点.
这只是理论上,实际里面还有一个大坑
在这里插入图片描述
如果我们要删除的节点:cur和right_min_parent 指向同一个地方时,此时应该让right_min_parent 的右节点指向right_min的右节点.

//有两个孩子:找到左边的最大值或者右边的最小值,与目标值进行替换
					//让这个右最小节点的父亲的左边指向右最小的右边,因为它此时最多只有右孩子
else
{
	Node* right_min_parent = cur;
	Node* right_min = cur->_right;
	while (right_min->_left)
	{
		right_min_parent = right_min;
		right_min = right_min->_left;
	}
	cur->_val = right_min->_val;
	//右最小节点,有坑,是连续存放的有序值
	if (cur->_right == right_min)
		right_min_parent->_right = right_min->_right;
	else
		right_min_parent->_left = right_min->_right;
	delete right_min;
}

erase代码

bool erase(const K& val)
		{
			Node* parent = _root;
			Node* cur = _root;
			//找到要删除的目标值
			while (cur)
			{
				if (cur->_val < val)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_val > val)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//只有一个孩子/叶子节点:让父亲节点指向子节点的右(nullptr)
					//右为空,父亲指向我的左
					if (cur->_right == nullptr)
					{
						//删除头节点
						if (_root == cur)
						{
							_root = cur->_left;
							delete cur;
						}
						else
						{
							if (parent->_right == cur)
								parent->_right = cur->_left;
							else
								parent->_left = cur->_left;
							delete cur;

						}
					}
					//左为空, 父亲指向我的右
					else if (cur->_left == nullptr)
					{
						//删除头节点
						if (_root == cur)
						{
							_root = cur->_right;
							delete cur;
						}
						else
						{
							if (parent->_right == cur)
								parent->_right = cur->_right;
							else
								parent->_left = cur->_right;
							delete cur;
						}
					}
					//有两个孩子:找到左边的最大值或者右边的最小值,与目标值进行替换
					//让这个右最小节点的父亲的左边指向右最小的右边,因为它此时最多只有右孩子
					else
					{
						Node* right_min_parent = cur;
						Node* right_min = cur->_right;
						while (right_min->_left)
						{
							right_min_parent = right_min;
							right_min = right_min->_left;
						}
						cur->_val = right_min->_val;
						//右最小节点,有坑,是连续存放的有序值
						if (cur->_right == right_min)
							right_min_parent->_right = right_min->_right;
						else
							right_min_parent->_left = right_min->_right;
						delete right_min;
					}
					return true;
				}
			}
			return false;
		}

中序遍历

		void MidOrder()
		{
			_MidOrder(_root);
			cout << endl;
		}
	private:
		void _MidOrder(const Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_MidOrder(root->_left);
			std::cout << root->_val << " ";
			_MidOrder(root->_right);
		}

首先,中序的搜索方式是左子树 根 右子树.按照这个顺序就能有序的取出搜索二叉树里面的值了

为什么会有两个函数?
因为函数的形参没有this指针,没法调用_root根节点,我们需要另外一个函数来传_root根节点

二叉搜索树的应用

k模型

k模型跟我们上面实现的一样,只存储一个值
比如:我们可以用这个功能查找到我们英文作文里面的拼写错误的单词.
我们可以把词库里面所有的英语单词丢进这个二叉搜索树,再遍历整个作文,检查每个单词是否存在,不存在就报错.

k模型模拟实现的总代码

namespace shh1
{
	template<class K>
	struct BSTreeNode
	{
		typedef BSTreeNode<K> Node;
		Node* _left;
		Node* _right;
		K _val;

		BSTreeNode(const K& val)
			:_left(nullptr)
			, _right(nullptr)
			, _val(val)
		{}
	};

	//k模型
	template<class K>
	class BSTree
	{
		typedef BSTreeNode<K> Node;
	public:
		bool insert(const K& val)
		{
			if (_root == nullptr)
			{
				_root = new Node(val);
				return true;
			}
			Node* parent = nullptr;
			Node* cur = _root;
			//找到空的节点进行插入
			while (cur)
			{
				if (cur->_val < val)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_val > val)
				{
					parent = cur;
					cur = cur->_left;
				}
				// 二叉搜索树默认不允许重复
				else
				{
					return false;
				}
			}
			cur = new Node(val);
			if (parent->_val < val)
			{
				parent->_right = cur;
			}
			else
			{
				parent->_left = cur;
			}
			return true;
		}

		bool erase(const K& val)
		{
			Node* parent = _root;
			Node* cur = _root;
			//找到要删除的目标值
			while (cur)
			{
				if (cur->_val < val)
				{
					parent = cur;
					cur = cur->_right;
				}
				else if (cur->_val > val)
				{
					parent = cur;
					cur = cur->_left;
				}
				else
				{
					//只有一个孩子/叶子节点:让父亲节点指向子节点的右(nullptr)
					//右为空,父亲指向我的左
					if (cur->_right == nullptr)
					{
						//删除头节点
						if (_root == cur)
						{
							_root = cur->_left;
							delete cur;
						}
						else
						{
							if (parent->_right == cur)
								parent->_right = cur->_left;
							else
								parent->_left = cur->_left;
							delete cur;

						}
					}
					//左为空, 父亲指向我的右
					else if (cur->_left == nullptr)
					{
						//删除头节点
						if (_root == cur)
						{
							_root = cur->_right;
							delete cur;
						}
						else
						{
							if (parent->_right == cur)
								parent->_right = cur->_right;
							else
								parent->_left = cur->_right;
							delete cur;
						}
					}
					//有两个孩子:找到左边的最大值或者右边的最小值,与目标值进行替换
					//让这个右最小节点的父亲的左边指向右最小的右边,因为它此时最多只有右孩子
					else
					{
						Node* right_min_parent = cur;
						Node* right_min = cur->_right;
						while (right_min->_left)
						{
							right_min_parent = right_min;
							right_min = right_min->_left;
						}
						cur->_val = right_min->_val;
						//右最小节点,有坑,是连续存放的有序值
						if (cur->_right == right_min)
							right_min_parent->_right = right_min->_right;
						else
							right_min_parent->_left = right_min->_right;
						delete right_min;
					}
					return true;
				}
			}
			return false;
		}

		bool find(const K& val)
		{
			Node* cur = _root;
			while (cur)
			{
				if (cur->_val < val)
				{
					cur = cur->_right;
				}
				else if (cur->_val > val)
				{
					cur = cur->_left;
				}
				else
				{
					return true;
				}
			}
			return false;
		}

		void MidOrder()
		{
			_MidOrder(_root);
			cout << endl;
		}
	private:
		void _MidOrder(const Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_MidOrder(root->_left);
			std::cout << root->_val << " ";
			_MidOrder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};
	void BST_Test1()
	{
		int a[] = { 6,5,1,4,7,2,3,8,9,11,55,68,-1 };
		BSTree<int> t;
		for (auto e : a)
		{
			t.insert(e);
		}
		t.MidOrder();
	}

	void BST_Test2()
	{
		int a[] = { 8 };
		BSTree<int> t;
		for (auto e : a)
		{
			t.insert(e);
		}
		t.MidOrder();

		for (auto e : a)
		{
			t.erase(e);
			t.MidOrder();
		}
	}
}

k-value模型

每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。
这个在我们日常生活很常见,比如词典的翻译,我们在key里面存英语单词,value里面存相对应的中文翻译.
我们就可以通过输入英文单词得到其对应的中文翻译.

下面稍作演示:

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->_val << endl;
			}
			else
			{
				cout << "单词拼写错误" << endl;
			}
		}
	}

在这里插入图片描述

k-value模型模拟实现的总代码

k-value模型的代码和上面的key模型类似,我们只需要要添加新节点的时候再加一个值就行.

namespace shh2
{
	template<class K, class V>
	struct BSTreeNode
	{
		typedef BSTreeNode<K, V> Node;
		Node* _left;
		Node* _right;
		K _key;
		V _val;

		BSTreeNode(const K& key, const V& val)
			:_left(nullptr)
			, _right(nullptr)
			, _key(key)
			, _val(val)
		{}
	};

	template<class K, class V>
	class BSTree
	{
		typedef BSTreeNode<K, V> Node;
		Node* _root = nullptr;
	public:
		bool Insert(const K& key, const V& val)
		{
			//头节点
			if (_root == nullptr)
			{
				_root = new Node(key, val);
				return true;
			}

			Node* parent = _root;
			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, val);
			if (parent->_key < key)
				parent->_right = cur;
			else
				parent->_left = cur;
			return true;
		}

		Node* 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 cur;
				}
			}
			return nullptr;
		}
		bool Erase(const K& key)
		{
			Node* parent = _root;
			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
				{
					//叶子节点和只有一个孩子的一起处理
					//左为空,父亲的左/右指向我的右
				   	if (cur->_left == nullptr)
				   	{
				   		// 如果为根节点
				   		if (cur == _root)
				   		{
				   			_root = cur->_right;
				   			delete cur;
				   		}
				   		else
				   		{
				   			if (cur == parent->_left)
				   			{
				   				parent->_left = cur->_right;
				   			}
				   			else
				   			{
				   				parent->_right = cur->_right;
				   			}
				   			delete cur;
				   		}
				   	}
					//右为空,父亲的左/右指向我的左
					else if (cur->_right == nullptr)
					{
						// 如果为根节点
						if (cur == _root)
						{
								_root = cur->_left;
								delete cur;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_left;
							}
							else
							{
								parent->_right = cur->_left;
							}
							delete cur;
						}
					}
					//两个孩子 找到cur左子树的最大值替换
					else
					{
						Node* left_max_parent = cur;
						Node* left_max = cur->_left;
						while (left_max->_right)
						{
							left_max_parent = left_max;
							left_max = left_max->_right;
						}
						swap(cur->_key, left_max->_key);
						if (left_max_parent->_left = left_max)
							left_max_parent->_left = left_max->_left;
						else
							left_max_parent->_right = left_max->_left;
						delete left_max;
					}
				   	return true;
				}
		 
			}
		}
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}
			_InOrder(root->_left);
			cout << root->_key << ":" << root->_val << endl;
			_InOrder(root->_right);
		}
		void InOrder()
		{
			_InOrder(_root);
		}
	};

	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->_val << endl;
			}
			else
			{
				cout << "单词拼写错误" << endl;
			}
		}
	}
};

二叉搜索树的不足

当二叉搜索树有序存入了一段值
在这里插入图片描述
这棵树会退化成单叉树,因为插入,查找和删除的时间复杂度都是高度次,
所以在这种情况下插入,查找和删除的时间复杂度会接近于N.搜索二叉树也就失去了它的优势.

AVL树和红黑树的出现

怎么解决这个问题呢,就要用到AVL和红黑树了.
在插入的时候,AVL树会查看树的高度是否平衡,
左子树和右子树的高度差不超过1.超过1会让树的几个节点之间发生旋转,最终这棵树会变成这样.

在这里插入图片描述
我们平时调用的容器map和set底层就是用AVL树和红黑树生成的.

总结

二叉搜索树的插入和查找不难,但是它的删除细节很多,分类很细,一不留神容易掉坑里面,面试也经常会考.大家如果不懂的话,要多看几遍.

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

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

相关文章

Python语言基础学习(上)

目录 一、常量和表达式 二、变量和类型 2.1 认识变量 2.2 定义变量 2.3 变量类型 1、整数 int 2、浮点数&#xff08;小数&#xff09;float 3、字符串 str 4、布尔类型 2.4 类型转换 三、注释 3.1 单行注释 3.2 文档注释&#xff08;或者多行注释&#xff09; …

Java解决垂直鉴权问题(对垂直权限进行校验)

Java解决垂直鉴权问题&#xff08;对垂直权限进行校验&#xff09; 文章目录 Java解决垂直鉴权问题&#xff08;对垂直权限进行校验&#xff09;前言一、垂直鉴权是什么&#xff1f;二、实现过程1.新建接口权限菜单映射表2.项目初始化时加载接口菜单映射关系3.自定义过滤器拦截…

【LLM 论文】Chain-of-Verification:通过验证链来减少 LLM 幻觉

论文&#xff1a;Chain-of-Verification Reduces Hallucination in Large Language Models ⭐⭐⭐ arXiv:2309.11495 论文速读 LLM 由于不可避免地会产生幻觉&#xff0c;现有的研究主要鼓励 LLM 在产生 response 之前生成内部思想的推理链&#xff0c;或者通过 self-critique…

使用leafletjs实现地图洋流、风场气象6要素地图标注、等值面图

前期实现的功能由于数据失效无法显示效果&#xff0c;今天重新对接一个数据源进行展示&#xff0c;实现效果如下图&#xff1a; 访问地址&#xff1a;可视化三维 GIS 特效 - 沉浸式视觉体验呈现令人惊叹的三维 GIS 特效&#xff0c;提供沉浸式视觉体验。https://www.wheart.cn/…

HTTP有哪些失败原因?怎么处理?

在我们日常的网络活动中&#xff0c;http协议是不可或缺的&#xff0c;它负责在互联网上传输数据。然而&#xff0c;在使用HTTP协议进行数据传输时&#xff0c;我们可能会遇到一些失败的情况。这些失败的原因多种多样&#xff0c;包括但不限于服务器问题、网络问题、客户端问题…

RobbitMQ基本消息队列的消息发送过程

RabbitMQ: One broker to queue them all | RabbitMQ RabbitMQ官网 SpringAmqp的官方地址&#xff1a;Spring AMQP 代码示例:对着代码看应该能看明白 publisher:消息发送者的代码示例 package cn.itcast.mq.helloworld;import com.rabbitmq.client.Channel; import com.rabb…

Agent AI智能体的未来:无限可能

文章目录 终结者智能体正反影响自我意识开放心态 终结者 还记得那场人类与天网之间的史诗般的战斗吗&#xff1f;-- 《终结者》系列电影。 《终结者》系列电影是一部标志性的科幻动作系列&#xff0c;以紧张刺激的情节、令人难忘的角色和开创性的视觉效果而闻名。 电影探讨了…

中国地形可调节高度-UE5-UE4

2000坐标系&#xff0c;可进行高度调整。 支持版本4.21-5.4版本 下载位置&#xff1a;https://mbd.pub/o/bread/ZpWZm5Zs

数据库基础语法二

一、数据库 1、登陆数据库 2、创建数据库zoo 3、修改数据库zoo字符集为gbk 4、选择当前数据库为zoo 5、查看创建数据库zoo信息 6、删除数据库zoo mysql -uroot -p #登陆数据库 create database zoo; #创建数据库zoo alter database zoo character set gbk collate gbk_…

rbac权限和多级请假设计的流程演示和前端页面实现

登录账号&#xff1a;t6普通用户 t7部门经理 m8总经理 密码都为&#xff1a;test 多级请假&#xff1a;7级及以下申请请假需要部门经理审核&#xff0c;若是请假时长超过72小时&#xff0c;则需要总经理审核&#xff0c;7级申请请将需要总经理审核&#xff0c;总经理请假自动审…

kubernetes删除命名空间下所有资源

kubernetes强制删除命名空间下所有资源 在 Kubernetes 中&#xff0c;当一个命名空间处于 Terminating 状态但不会完成删除过程时&#xff0c;通常是因为内部资源没有被正确清理。要强制删除这个命名空间及其所有资源&#xff0c;你可以采取以下步骤&#xff1a; 1. 确认命名空…

Linux应用(四)——系统IO函数

本节学习linux系统中常见的IO函数&#xff0c;讲解及其基本用法&#xff1b; 一、 open/close函数 open函数作用:系统调用open函数&#xff0c;打开指定路径的文件&#xff1b; int open(const char *pathname, int flags&#xff09;&#xff1b;打开一个存在的文件&#xff1…

OpenNJet,够轻更强云原生应用引擎

前言&#xff1a; 在正式介绍OpenNJet之前&#xff0c;我们先来看看它的技术架构&#xff0c;如下图所示&#xff0c;OpenNJet正是NGINX的Pro版&#xff0c;在100%兼容NGINX基础上&#xff0c;新增了动态配置加载、主动式健康检测、集群高可用、声明式API等多种强大功能。 NGIN…

第十一讲:指针(3)

第十一讲&#xff1a;指针&#xff08;3&#xff09; 1.字符指针变量1.1存储一个字符1.2存储一个字符串1.3一个有趣的面试题 2.数组指针变量2.1什么是数组指针变量2.2数组指针变量的初始化 3.二维数组传参的本质4.函数指针变量4.1介绍函数指针变量4.2 两段有趣的代码4.2.1代码1…

华为 Huawei 交换机 配置 Dot1q 终结子接口实现同设备 VLAN 间通信示例

组网需求 企业的不同部门拥有相同的业务&#xff0c;如上网、 VoIP 等业务&#xff0c;且各个部门中的用户位于不同的网段。目前存在不同的部门中相同的业务所属的VLAN 不相同&#xff0c;现需要实现不同VLAN中的用户相互通信。 如 图 7-7 所示&#xff0c;部门 1 和部门 2 中…

机器学习的一些知识点分享

下面数据集中&#xff0c;第2个样本的第4个属性的值是&#xff08; &#xff09;。 A 52 B 男 C 50 D 49 本题得分&#xff1a; 2分 正确答案&#xff1a; D 2.单选题 (2分) 10-折交叉验证是把数据集分成&#xff08; &#xff09;个子集&#xff0c;将其中&#xff…

好景盒式磁带随声听

少年时代柜子里翻出来的磁带录音机电路板 两颗芯片&#xff0c;FM芯片&#xff0c;电机驱动 CD9088CBD6650

第十三届蓝桥杯决赛(国赛)真题 Java C 组【原卷】

文章目录 发现宝藏试题 A: 斐波那契与 7试题 B: 小蓝做实验试题 C: 取模试题 D: 内存空间试题 E \mathrm{E} E : 斐波那契数组试题 F: 最大公约数试题 G: 交通信号试题 I: 打折试题 J: 宝石收集 发现宝藏 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#x…

VM虚假机联网(无代码,超简单)NAT模式

1、左边顶上编辑里面最下面找到虚拟网络编辑器2.启用管理员特权3.重新创建一个NAT模式的网络&#xff08;名称随便一个&#xff09; 4.打开这两个设置里面的东西进行拍照并记住IP区间和网关&#xff0c;等下要用&#xff1b; 5.打开虚拟机&#xff0c;右上角&#xff0c;下标点…

sql注入中的替换技巧。

目录 1&#xff1a;注释的替换 2&#xff1a;空格替换 3&#xff1a;大小写混合绕过及双写绕过 4&#xff1a;等号的绕过 5&#xff1a;单双引号的绕过 1&#xff1a;注释的替换 注释在sql注入中非常重要&#xff0c;因为会使用它来闭合我们注入的sql语句。 当以get方式提…