【C++】---二叉搜索树

【C++】---二叉搜索树

  • 一、二叉搜索树概念
  • 二、二叉搜索树操作(非递归)
    • 1.二叉搜索树的查找 (非递归)
      • (1)查找
      • (2)中序遍历
    • 2.二叉搜索树的插入(非递归)
    • 3.二叉搜索树的删除(非递归)
  • 三、二叉搜索树操作(递归)
    • 1.二叉搜索树的查找(递归)
    • 2.二叉搜索树的插入(递归)
    • 3.二叉搜索树的删除(递归)
  • 四、二叉搜索树的默认成员函数
    • 1.构造
    • 2.拷贝构造
    • 3.赋值运算符重载
    • 4.析构
  • 五、K模型和KV模型搜索树
    • 1.K模型搜索树
    • 2.KV模型搜索树
  • 六、二叉搜索树性能分析

在这里插入图片描述

一、二叉搜索树概念

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

  1. 如果它的左子树不为空,那么左子树上所有节点的值都小于根结点的值。
  2. 如果它的右子树不为空,那么右子树上所有节点的值都大于根节点的值。
  3. 它的左右子树也是二叉搜索树。

在这里插入图片描述

int a[] = {8, 3, 1, 10, 6, 4, 7, 14, 13};

比如说:这个数组都可以将它化为二叉搜索树

在这里插入图片描述

总结:在左子树值比根小,右子树值比根大。 当树走中序遍历时,序列都是有序的

二叉搜索树 的 结构定义:


#include<iostream>
using namespace std;

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

	BSTreeNode(const K& key)
		:_left(nullptr)
		, _right(nullptr)
		, _key(key)
	{

	}
};


template<class K>
class BSTree
{
	typedef BSTreeNode<K> Node;
private:
	Node* _root;
public:

	BSTree()
		:_root(nullptr)
	{

	}
};

二、二叉搜索树操作(非递归)

1.二叉搜索树的查找 (非递归)

利用二分查找的方法,借助我们去二叉搜索树中查找节点。

在这里插入图片描述
在这里插入图片描述
查找的时间复杂度:最坏的情况,就是查找高度(h=logN)次,就可以判断一个值在不在节点里面。

(1)查找

查找的思路:

  1. key比当前结点的值小,往左走!
  2. key比当前结点的值大,往右走!
  3. key==当前结点的值,就找到了!

在这里插入图片描述

// 查找:
	Node* Find(const K& key)
	{
		Node* cur = _root;
		while (cur)
		{
			if (key < cur->_key)
			{
				cur = cur->_left;
			}
			else if (key > cur->_key)
			{
				cur = cur->_right;
			}
			else
			{
				return cur;// 找到了!
			}
		}
		return nullptr;// 遍历完了,都还没找到!
	}

(2)中序遍历

由于根节点_root是私有成员变量,如果在main函数里面来进行中序遍历的话,这就是在类外对私有成员进行访问,这是不合法的!

所以说我们要解决这个问题,可以用这样:
在类的public内的 中序遍历 InOrder 里面 再套一层私有的中序遍历:_InOrder,这样,_InOrder身为私有函数,就可以访问:私有变量_root!

private:
	void _InOrder(Node* root)
	{
		if (root == nullptr)
		{
			return;
		}
		_InOrder(root->_left);
		cout << root->_key << endl;
		_InOrder(root->_right);
	}
public:
	
	// 中序遍历:
	void InOrder() //这个函数 类外可以直接访问!
	{
		_InOrder(_root); // 这个函数,是 私有函数 对 私有成员 的访问!
		cout << endl;
	}

2.二叉搜索树的插入(非递归)

插入节点分两步:

(1)找位置

    ①key比当前节点值大,向左走

    ②key比当前节点值小,向右走

    ③key等于当前节点值,该节点值已经存在,插入失败

(2)插入

    ①key比父亲节点值小就插入父亲左子树

    ②key比父亲节点值大就插入父亲右子树

由于插入后,要将节点链接到树中,因此要定义parent节点,用来链接新节点:

在这里插入图片描述

// 插入:
	bool Insert(const K& key)
	{
		if (_root == nullptr)
		{
			_root = new Node(key);
			return true;
		}

		Node* cur = _root;
		Node* parent = nullptr;
		// (1) 找到插入的位置
		while (cur)
		{
			if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (key > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				return false;// 二叉搜索树不允许数据冗余!
			}
		}

		cur = new Node(key);

		// (2) 判断
		if (key<parent->_key)
		{
			parent->_left = cur;
		}
		else
		{
			parent->_right = cur;
		}
		return true;
	}

3.二叉搜索树的删除(非递归)

非递归删除:

(1)找位置

    ①key比当前节点值大,向左走

    ②key比当前节点值小,向右走

    ③key等于当前节点值,找到了,准备删除

(2)删除,有两种删除方法:非递归和递归

    非递归删除: 

    ①该节点没有孩子,即该节点是叶子节点,删除节点后把父亲指向自己的指针置空

在这里插入图片描述

    ②该节点有一个孩子,就把该节点的孩子节点的链接给该节点的父亲,顶替自己的位置,
    ①可以当成②的特殊情况

在这里插入图片描述

    ③该节点有两个孩子,找比它自己的左孩子大,比它自己的右孩子小的节点替换它
    (也就是拿它的左子树的最大节点或右子树的最小节点替换它),
    替换之后,该节点就只有一个孩子或没有孩子了,就变成①或②了。

在这里插入图片描述

// 删除
	bool erase(const K& key)
	{
		Node* cur = _root;
		Node* parent = nullptr;
		// (1) 找到插入的位置
		while (cur)
		{
			if (key < cur->_key)
			{
				parent = cur;
				cur = cur->_left;
			}
			else if (key > cur->_key)
			{
				parent = cur;
				cur = cur->_right;
			}
			else
			{
				break;
			}
		}
		// 1、2、 (子 代替 父亲的位置)

		// 大前提:如果要删除的节点,left为空
		if (cur->_left == nullptr)
		{
			// 如果要删除根!
			if (cur == _root)
			{
				_root = cur->_right;// 那就让cur的右当根
			}
			// 如果要删除的不是根!
			else
			{
				// 如果要删除的节点cur,在父亲的左边。

				// 因为是替代法,所以说要让 子 的位置代替 父亲 的位置,但是 子 的位置只有_right存在,所以说会把_right的位置放到即将要删除cur的位置。
				if (parent->_left == cur)
				{
					parent->_left = cur->_right;
				}
				else
				{
					parent->_right = cur->_right;
				}
			}

			delete cur;
		}


		// 大前提:如果要删除的节点,right为空
		else if (cur->_right == nullptr)
		{
			if (cur == _root)
			{
				_root = cur->_left;
			}

			else
			{
				// 因为是替代法,所以说要让 子 的位置代替 父亲 的位置,但是 子 的位置只有_left存在,所以说会把_left的位置放到即将要删除cur的位置。
				if (parent->_left == cur)
				{
					parent->_left = cur->_left;
				}
				else
				{
					parent->_right = cur->_left;
				}
			}
			delete cur;
		}

		// 3、要删除的cur不只有一个节点。可能有多个节点,甚至整个指子树
		// 找到要删除节点cur,左子树最大的节点,右子树最小的节点,来代替cur的位置。
		else
		{
			// 要么找cur左子树中的max,要么就找右子树中的min

			// 这里 以 RightMin为例!

			// (1)找到 RightMin (就像找 cur那样)
			Node* RightMin = cur->_right;
			Node* RightMinParent = cur; // 定义 RightMinParent 为了方便后续节点的连接。

			while (RightMin->_left)
			{
				RightMinParent = RightMin;
				RightMin = RightMin->_left;
			}
			// (2)找到了 就交换!
			swap(RightMin->_key, cur->_key);

			// (3) 交换完后 就链接!

			if (RightMinParent->_left == RightMin)
				RightMinParent->_left = cur;
			else
				RightMinParent->_right = cur;
			// 链接完成!

			delete cur;
		}

		return true;
	}

递归删除:

相对于非递归,只需要修改找到了要修改的代码:找到了后不需要管cur到底左为空、右为空、还是左右都不为空

① 找要删除节点的右子树的最小节点并把它的值保存起来

② 删除右子树的最小节点

③ 把要删除的节点值替换成右子树的最小节点值

在这里插入图片描述

                else//左右都不为空,替换法删除
                {
					//找右子树最小节点
					Node* minRight = cur->_right;
					while (minRight->_left)
					{
						minRight = minRight->_left;
					}
 
					//用min保存右子树最小节点的值
					K min = minRight->_key;
 
					//递归调用自己去替换删除节点,一定会走到左为空的情况处理
					this->Erase(min);
 
					//删除完毕替换节点之后,把cur的值替换成min
					cur->_key = min;
				}

三、二叉搜索树操作(递归)

理解了非递归操作以后, 递归操作就很简单了:

#include<iostream>
using namespace std;
 
//树的节点可以支持多种类型
template<class K>
//树节点结构
struct BSTreeNode
{
	BSTreeNode<K>* _left;//左指针
	BSTreeNode<K>* _right;//右指针
	K _key;//值
 
	//构造函数
	BSTreeNode(const K& key)
		:_left(nullptr)
		, _right(nullptr)
		, _key(key)
	{}
};
 
template<class K>
class BStree//树结构
{
	typedef BSTreeNode<K> Node;
public:
	//递归查找
	Node* FindR(const K& key)
	{
		return _FindR(_root, key);
	}
 
	//递归插入
	bool InsertR(const K& key)
	{
		return _InsertR(_root, key);
	}
 
	//递归删除
	bool EraseR(const K& key)
	{
		return _EraseR(_root, key);
	}
private:
	Node* _root;
};

由于_root是私有的,可以把递归子函数查找、插入、删除都定义成私有的

1.二叉搜索树的查找(递归)

private:
    //查找
	Node* _FindR(Node* root, const K& key)
	{
		if (root == nullptr)//没找到
		{
			return nullptr;
		}
 
		if (key < root->_key)//到左子树去找
		{
			FindR(root->_left, key);
		}
		else if (key > root->_key)//到右子树去找
		{
			FindR(root->_right, key);
		}
		else//找到了
		{
			return root;
		}
	}

2.二叉搜索树的插入(递归)

	//插入 加了&,root是_root的别名,修改root就直接修改到上一层调用,不用找父亲
	bool _InsertR(Node*& root, const K& key)
	{
		if (root == nullptr)//找到位置了
		{
			root = new Node(key);
			return true;
		}
		if (key < root->_key)//到左子树去找位置
		{
			_InsertR(root->_left, key);
		}
		else if (key > root->_key)//到右子树去找位置
		{
			_InsertR(root->_right, key);
		}
		else//已存在,无需插入
		{
			return false;
		}
	}

3.二叉搜索树的删除(递归)

递归删除:和二叉树的删除(非递归)一样,找到后的删除也有两种方式,递归和非递归

找到后的非递归删除:

    //插入 加了&,root是_root的别名,修改root就直接修改到上一层调用,不用找父亲	
    bool _EraseR(Node*& root, const K& key)
	{
		if (root == nullptr)//没找到
		{
			return false;
		}
		if (key < root->_key)//到左子树去找
		{
			_EraseR(root->_left, key);
		}
		else if (key > root->_key)//到右子树去找
		{
			_EraseR(root->_right, key);
		}
		else
		{
			//找到了,root就是要删除的节点
			if (root->_left == nullptr)//root左为空
			{
				Node* del = root;
				root = root->_right;
				delete del;
			}
			else if (root->_right == nullptr)//root右为空
			{
				Node* del = root;
				root = root->_left;
				delete del;
			}
			else//root左右都不为空
			{
				//找到右子树最左节点替换
				Node* minParent = root;
				Node* minRight = root->_right;
 
				while (minRight->_left)
				{
					minParent = minRight;
					minRight = minRight->_left;
				}
 
				//保存替换节点的值
				cur->_key = minRight->_key;
 
				//链接
				if (minParent->_left == minRight)
				{
					minParent->_left = minRight->_right;
				}
				else
				{
					minParent->_right = minRight->_right;
				}
 
				//删除
				delete minRight;
			}
			return true;
		}
	}

找到后的递归删除:

			else//root左右都不为空
			{				
                //找右子树最左节点
				Node* minRight = root->_right;
				while (minRight->_left)
				{
					minRight = minRight->_left;
				}
 
				//保存右子树最左节点的值
				K min = minRight->_key;
 
				//使用递归方法删除右子树最左节点
				_Erase(root->_right, min);
			}

四、二叉搜索树的默认成员函数

现在还剩下二叉搜索树的构造、拷贝构造、赋值运算符重载、析构函数。

1.构造

public:
	//构造函数需要将根初始化为空就行了
	BSTree()
		:_root(nullptr)
	{}

2.拷贝构造

拷贝构造利用递归调用子函数不断拷贝节点:

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

在子函数处:

	Node* _copy(Node* root)
	{
		if (root == nullptr)//如果根为空,直接返回
		{
			return;
		}
 
		Node* copyNode = new Node(root->_key);//创建根节点
		copyNode->_left = _copy(root->_left);//递归拷贝左子树节点
		copyNode->_right = _copy(root->_right);//递归拷贝右子树节点
		
		return copyNode;//返回根
	}

3.赋值运算符重载

借助拷贝构造用现代写法写:

	//赋值运算符重载(现代写法)
	BSTree& operator=(const BSTree<K>& t)
	{
		swap(_root,t._root);
		return *this;
	}

4.析构

递归调用子函数去析构

	//析构
	~BSTree()
	{
		_Destroy(_root);
		_root = nullptr;
	}

在子函数处:

	_Destroy(root)
	{
		if (root == nullptr)
		{
			return;
		}
		_Destroy(root->_left);
		_Destroy(root->_right);
		delete root;
	}

五、K模型和KV模型搜索树

1.K模型搜索树

K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:
1、以词库中所有单词集合中的每个单词作为key,构建一棵二叉搜索树
2、在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。

2.KV模型搜索树

KV模型:每一个关键码key,都有与之对应的值Value,即<Key, Value>的键值对。该种方式在现实生活中非常常见:

1、比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文<word, chinese>就构成一种键值对;
2、再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出
现次数就是<word, count>就构成一种键值对。

改造二叉搜索树为KV结构的代码

#pragma once
#include<iostream>
#include<string>
using namespace std;

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

		// pair<K, V> _kv;

		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:
		// logN
		bool Insert(const K& key, const V& value)
		{
			if (_root == nullptr)
			{
				_root = new Node(key, value);
				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, value);
			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 cur;
		}

		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
				{
					// 删除
					// 左为空,父亲指向我的右
					if (cur->_left == nullptr)
					{
						//if(parent == nullptr)
						if (cur == _root)
						{
							_root = cur->_right;
						}
						else
						{
							if (cur == parent->_left)
							{
								parent->_left = cur->_right;
							}
							else
							{
								parent->_right = cur->_right;
							}
						}

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

						delete cur;
					}
					else
					{
						// 左右都不为空,替换法删除
						// 
						// 查找右子树的最左节点替代删除
						Node* rightMinParent = cur;
						Node* rightMin = cur->_right;
						while (rightMin->_left)
						{
							rightMinParent = rightMin;
							rightMin = rightMin->_left;
						}

						swap(cur->_key, rightMin->_key);

						if (rightMinParent->_left == rightMin)
							rightMinParent->_left = rightMin->_right;
						else
							rightMinParent->_right = rightMin->_right;

						delete rightMin;
					}

					return true;
				}
			}

			return false;
		}

		void InOrder()
		{
			_InOrder(_root);
			cout << endl;
		}
	private:
		void _InOrder(Node* root)
		{
			if (root == nullptr)
			{
				return;
			}

			_InOrder(root->_left);
			cout << root->_key << ":" << root->_value << endl;
			_InOrder(root->_right);
		}
	private:
		Node* _root = nullptr;
	};

六、二叉搜索树性能分析

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述


好了,今天的分享就到这里了
如果对你有帮助,记得点赞👍+关注哦!
我的主页还有其他文章,欢迎学习指点。关注我,让我们一起学习,一起成长吧!
在这里插入图片描述

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

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

相关文章

单链表经典算法题理解

目录 1. 前言&#xff1a; 2. 移除链表元素 3. 反转链表 4. 合并两个有序链表 5. 链表的中间节点 6. 环形链表的约瑟夫问题 7. 分割链表 1. 前言&#xff1a; 当我们学习了单链表之后&#xff0c;我能可以尝试的刷一下题了&#xff0c;以下分享一下几道题的解法 2. 移…

【几何】输入0-360度任意的角度,求上面直线与椭圆相切点的坐标计算公式

输入0-360度任意的角度,求上面直线与椭圆相切点的坐标计算公式 使用积分计算 使用到的公式有椭圆公式: x 2 a 2 + y 2 b 2 = 1 \frac{x^2}{a^2}+\frac{y^2}{b^2} = 1 a2x2​+b2y2​=1 平面旋转公式 X r = cos ⁡ θ ∗ ( X s − X O ) − sin ⁡ θ ∗ ( Y s − Y O ) + X …

XDebug配置极简教程,phpstorm实现http请求断点调试

写这篇的文章的初衷:网络上配置XDebug的文章有很多,XDebug也有官方的文档, PhpStorm也有官方的文档,为什么还要写那? 相信不少人,都有一种感觉,虽然教程很多,但是按教程走一遍,自己的确不能正常调试。 问题出在下面几个方面: 1. 对调试过程中,没有一定的认识,因此…

【UML用户指南】-02-UML的14种图

1、结构图 1、类图&#xff08;class diagram&#xff09; 展现了一组类、接口、协作和它们之间的关系。 在面向对象系统的建模中所建立的最常见的图就是类图。类图给出系统的静态设计视图。 包含主动类的类图给出系统的静态进程视图。构件图是类图的变体。 2、对象图&a…

一种基于高德Web API实现沿路画面的实现

概述 本文在mapboxGL框架下&#xff0c;分享一种基于高德Web API实现沿路画面的实现。 实现效果 实现 1. 实现思路 通过点击获取路径的起点和终点&#xff1b;将多次规划路径的结果连成一条线&#xff1b;当鼠标点击回到第一个点的时候结束绘制&#xff1b;绘制结束后将路径…

Tasker+SendSilentMail实现钉钉自动打卡

Tasker 允许用户根据自定义的“配置文件”(Profiles)&#xff0c;在特定的“背景”(Contexts)下&#xff0c;执行指定的“任务”(Tasks)。以下是关于Tasker的详细介绍&#xff1a; 强大的自定义能力&#xff1a;用户可以根据自己的需求&#xff0c;创建各种配置文件和任务&…

【ESP32之旅】ESP32 PlatformIO 固件单独烧录

背景 有时候使用PIO编写的代码需要发给客户去验证&#xff0c;相比较于发送源码直接发送bin文件&#xff0c;更加的安全而且高效。不用担心源码的泄漏&#xff0c;也不用帮客户配置PIO环境。 操作方法 1.编译 首先进行代码编译&#xff0c;如编译成功会在 .pio\build\airm2…

Visual Studio 的调试

目录 引言 一、调试的基本功能 设置断点 启动调试 检查变量 逐步执行代码 调用堆栈 使用即时窗口 二、调试技巧 条件断点 日志断点 数据断点 异常调试 三、调试高级功能 远程调试 多线程调试 内存调试 性能调试 诊断工具 四、调试策略与最佳实践 系统化的…

基于java实现图片中任意封闭区域识别

需求&#xff1a; 在浏览器中给用户呈现一张图片&#xff0c;用户点击图片中的某些标志物&#xff0c;需要系统给出标志物的信息反馈&#xff0c;达到一个交互的作用。 比如下图中&#xff0c;点击某个封闭区域时候&#xff0c;需要告知用户点击的区域名称及图形形状特性等等。…

基于单片机的病牛乳声光报警系统设计

摘 要&#xff1a; 根据奶牛的养殖业应用需求&#xff0c;为快速 、 便捷 、 直接地得到奶牛的健康信息&#xff0c;文章研究了一种基于单片机的病牛乳声光报警系统设计。 利用传感器电路&#xff0c;电压比较电路检测牛奶样品信号&#xff0c;送入单片机 。 单片机对输入的信号…

如何去除input框在复制内容时自动填充的背景颜色

今天在项目开放时遇到了一个问题在输入复制内容时会有一个自带的背景颜色无法去除&#xff1b; 效果图&#xff1a; 修改的核心代码&#xff1a; /* 修改自动填充时的背景颜色 */ input:-internal-autofill-previewed, input:-internal-autofill-selected {-webkit-text-fil…

基于springboot+vue的社区医院管理服务系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

支付功能、支付平台、支持渠道如何测试?

有学员提问&#xff1a;作为一个支付平台&#xff0c;接入了快钱、易宝或直连银行等多家的渠道&#xff0c;内在的产品流程是自己的。业内有什么比较好的测试办法&#xff0c;来测试各渠道及其支持的银行通道呢&#xff1f; 作为产品&#xff0c;我自己办了十几张银行卡方便测…

Kong api网关实战教程

1. kong介绍 Kong是一款基于OpenResty(NginxLua模块)编写的高可用、易扩展的&#xff0c;由Mashape公司开源的API Gateway项目。Kong是基于NGINX和Apache Cassandra或PostgresQL构建的&#xff0c;能据供易于使用的RSTTAP[来操作和配置API管理系统&#xff0c;所以它可以水平扩…

民国漫画杂志《时代漫画》第32期.PDF

时代漫画32.PDF: https://url03.ctfile.com/f/1779803-1248635561-0ae98a?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了&#xff0c;截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

地图下钻,双击返回上一级

介绍&#xff1a; 看了好多地图下钻的案例&#xff0c;要么json文件不全胡&#xff0c;要么返回功能不全胡&#xff0c;有的返回是直接写死&#xff0c;返回到首页&#xff0c;我这个小案例是使用地理小工具的数据&#xff0c;本案例可以逐步一级一级的返回&#xff0c;地图的其…

网络工程基础 不同网段下的设备实现通信

交换机可以实现同一个网段下的不同设备直接通信 路由器可以实现不同的网段下的设备进行通信 路由器查看路由表命令 display ip routing-table 华为路由器配置静态路由命令&#xff1a; ip route-static 目的网络地址 子网掩码 下一跳地址 电脑判断不同网段的ip会把请求转给网…

建设现代智能工业-智能化、数字化、自动化节能减排

建设现代智能工业-智能化节能减排 遵循“一体化”能源管理(Integrated Energy Management)的设计宗旨&#xff0c;集成城市各领域(如工业.交通、建筑等&#xff09;的能源生产和消费信息&#xff0c;面向城市政府、企业、公众三类实体&#xff0c;提供“一体化”的综合能源管理…

解决文件传输难题:如何绕过Gitee的100MB上传限制

引言 在版本控制和代码托管领域&#xff0c;Gitee作为一个流行的平台&#xff0c;为用户提供了便捷的服务。然而&#xff0c;其对单个文件大小设定的100MB限制有时会造成一些不便。 使用云存储服务 推荐理由&#xff1a; 便捷性&#xff1a;多数云存储服务如&#xff1a; Dro…

技术架构设计指南:从需求到实现

技术架构是软件系统的骨架&#xff0c;它决定了系统的性能、可靠性、扩展性等关键特性。本文将介绍技术架构设计的一般步骤和方法。 第一步&#xff1a;需求分析 在设计技术架构之前&#xff0c;首先要对系统需求进行全面深入的分析。这包括功能需求、非功能需求&#xff08;如…