数据结构和算法(5):二叉树

news2024/11/25 16:18:51

向量允许通过下标或秩,在常数的时间内找到目标对象;然而,一旦需要对这类结构进行修改,那么无论是插入还是删除,都需要耗费线性的时间。
列表允许借助引用或位置对象,在常数的时间内插入或删除元素;但是为了找出居于特定次序的元素,却不得不花费线性的时间,对整个结构进行遍历查找。
树将二者优势结合起来,可以视为 List<List> 或者 List^2

从图论的角度看,树等价于连通无环图。因此与一般的图相同,树也由一组顶点以及联接与其间的若干条边组成。在计算机科学中,往往还会在此基础上,再指定某一特定顶点,并称之为。在指定根节点之后,也称之为有根树。此时,从程序实现的角度,更多地将顶点称作节点

节点之间均有路径,称作连通团
不含环路,称作无环图

任一节点与根之间存在唯一路径。

沿每个节点 v 到根 r 的唯一通路所经过边的数目,称作 v深度。约定根节点的深度depth(r) = 0,故属于第 0 层。
在这里插入图片描述
任一节点v在通往树根沿途所经过的每个节点都是其祖先v是它们的后代。特别地,v 的祖先/后代包括其本身,而 v 本身以外的祖先/后代称作真祖先/真后代。
节点v历代祖先的层次,自下而上以1为单位逐层递减;在每一层次上,v的祖先至多一个。特别地,若节点uv的祖先且恰好比v高出一层,则称uv的父亲,vu的孩子。
v的孩子总数,称作其度数,记作deg(v)。无孩子的节点称作叶节点,包括根在内的其余节点皆为内部节点。
v所有的后代及其之间的联边称作子树,记作subtree(v)。在不致歧义时,往往不再严格区分节点(v)及以之为根的子树(subtree(v))。

T中所有节点深度的最大值称作该树的高度,记作height(T)树的高度总是由其中某一叶节点的深度确定的。
任一节点v所对应子树subtree(v)的高度,亦称作该节点的高度,记作height(v)。特别地,全树的高度亦即其根节点r的高度,height(T) = height(r)

术语:
根节点(Root): 树的顶部节点,没有父节点,是树的起点。
子节点(Child): 根节点下面的节点,每个子节点都有一个父节点。
父节点(Parent): 每个节点都有一个父节点,除了根节点。
叶子节点(Leaf): 没有子节点的节点称为叶子节点。
内部节点(Internal Node): 有子节点的节点称为内部节点。
边(Edge): 连接节点的线段。
路径(Path): 从一个节点到另一个节点的连续边构成的序列。
层级(Level): 根节点位于第一层,每个子节点的层级比其父节点高一层。
高度(Height): 树的高度是树中任何节点到其最远叶子节点的最长路径的长度。
子树(Subtree): 子树是树中的一部分,它本身也是一棵树,包括一个节点以及其所有后代节点。

表示

节点功能
root()根节点
parent()父节点
firstChild()长子
nextSibling()兄弟
insert(i,e)e 作为第 i 个孩子插入
remove(i)删除第 i 个孩子(及其后代)
traverse()遍历

在这里插入图片描述

树的长子兄弟表示法(Child-Sibling Representation)是一种用于表示树结构的方法,也称为左子右兄弟表示法(Left Child Right Sibling Representation)。这种表示法的主要思想是通过两个指针来表示每个节点的孩子和兄弟关系,从而构建树结构。

在长子兄弟表示法中,每个节点有两个指针:

长子指针(Child Pointer): 指向该节点的最左边的孩子节点。
兄弟指针(Sibling Pointer): 指向该节点的右兄弟节点。

使用长子兄弟表示法,可以有效地表示一棵多叉树,其中每个节点可以有任意数量的孩子节点。这种表示法的一个优点是它可以节省内存空间,因为每个节点只需要两个指针。

二叉树

二叉树(Binary Tree): 每个节点最多有两个子节点的树。
深度为 k k k 的节点,至多 2 k 2^k 2k 个。
n n n 个节点、高度为 h h h 的二叉树中 h < n < 2 n + 1 h<n<2^{n+1} h<n<2n+1
1) n = h + 1 n = h+1 n=h+1时,退化成一条单链;
2) n = 2 h + 1 − 1 n = 2^{h+1} -1 n=2h+11时,即所谓满二叉树

描述多叉树:二叉树是多叉树的特例,但在有根且有序时,其描述能力却足以覆盖后者。

实现

BinNode 模板类

template <typename T> struct BinNode;
template <typename T> using BinNodePosi = BinNode<T>*; //节点位置

template <typename T> struct BinNode { //二叉树节点模板类
// 成员(为简化描述起见统一开放,读者可根据需要进一步封装)
	T data; //数值
	BinNodePosi<T> parent, lc, rc; //父节点及左、右孩子
	Rank height; //高度(通用)
	Rank npl; //Null Path Length(左式堆,也可直接用height代替)
	RBColor color; //颜色(红黑树)
// 构造函数
	BinNode() : parent(NULL), lc(NULL), rc(NULL), height(0), npl(1), color(RB_RED) {}
	BinNode(T e, BinNodePosi<T> p = NULL, BinNodePosi<T> lc = NULL,
		            BinNodePosi<T> rc = NULL, int h = 0, int l = 1, RBColor c = RB_RED)
		: data(e), parent(p), lc(lc), rc(rc), height(h), npl(l), color(c) {}
	// 操作接口
	Rank size(); //统计当前节点后代总数,亦即以其为根的子树的规模
	BinNodePosi<T> insertAsLC(T const&); //作为当前节点的左孩子插入新节点
	BinNodePosi<T> insertAsRC(T const&); //作为当前节点的右孩子插入新节点
	BinNodePosi<T> succ(); //取当前节点的直接后继
	template <typename VST> void travLevel(VST&); //子树层次遍历
	template <typename VST> void travPre(VST&); //子树先序遍历
	template <typename VST> void travIn(VST&); //子树中序遍历
	template <typename VST> void travPost(VST&); //子树后序遍历
// 比较器、判等器(各列其一,其余自行补充)
	bool operator< (BinNode const& bn) { return data < bn.data; } //小于
	bool operator== (BinNode const& bn) { return data == bn.data; } //等于
};

BinNode 接口

template <typename T> BinNodePosi<T> BinNode<T>::insertAsLC( T const& e )
   { return lc = new BinNode( e, this ); } //将e作为当前节点的左孩子插入二叉树

template <typename T> BinNodePosi<T> BinNode<T>::insertAsRC( T const& e )
   { return rc = new BinNode( e, this ); } //将e作为当前节点的右孩子插入二叉树
   
template <typename T> Rank BinNode<T>::size() { //统计当前节点后代总数,即以其为根的子树规模
   Rank s = 1; //计入本身
   if ( lc ) s += lc->size(); //递归计入左子树规模
   if ( rc ) s += rc->size(); //递归计入右子树规模
   return s;
}

孩子接入都可以在 O ( 1 ) \mathcal O(1) O(1)时间内完成,而获取 size() 需要遍历,因此需要时间为 O ( n ) \mathcal O(n) O(n)

BinTree 模板类

#include "BinNode.h" //引入二叉树节点类
template <typename T> class BinTree { //二叉树模板类
protected:
	Rank _size; BinNodePosi<T> _root; //规模、根节点
	virtual Rank updateHeight(BinNodePosi<T> x); //更新节点x的高度
	void updateHeightAbove(BinNodePosi<T> x); //更新节点x及其祖先的高度
public:
	BinTree() : _size(0), _root(NULL) {} //构造函数
	~BinTree() { if (0 < _size) remove(_root); } //析构函数
	Rank size() const { return _size; } //规模
	bool empty() const { return !_root; } //判空
	BinNodePosi<T> root() const { return _root; } //树根
	BinNodePosi<T> insert(T const&); //插入根节点
	BinNodePosi<T> insert(T const&, BinNodePosi<T>); //插入左孩子
	BinNodePosi<T> insert(BinNodePosi<T>, T const&); //插入右孩子
	BinNodePosi<T> attach(BinTree<T>*&, BinNodePosi<T>); //接入左子树
	BinNodePosi<T> attach(BinNodePosi<T>, BinTree<T>*&); //接入右子树
	Rank remove(BinNodePosi<T>); //子树删除
	BinTree<T>* secede(BinNodePosi<T>); //子树分离
	template < typename VST> //操作器
	void travLevel(VST & visit) { if (_root) _root->travLevel(visit); } //层次遍历
	template < typename VST> //操作器
	void travPre(VST & visit) { if (_root) _root->travPre(visit); } //先序遍历
	template < typename VST> //操作器
	void travIn(VST & visit) { if (_root) _root->travIn(visit); } //中序遍历
	template < typename VST> //操作器
	void travPost(VST & visit) { if (_root) _root->travPost(visit); } //后序遍历
	bool operator<(BinTree<T> const& t) //比较器(其余自行补充)
		    { return _root && t._root && lt(_root, t._root); }
	bool operator==(BinTree<T> const& t) //判等器
		    { return _root && t._root && (_root == t._root); }
}; //BinTree

高度更新

二叉树任一节点的高度,都等于其孩子节点的最大高度加一。

节点自身很难发现后代的变化,因此采用另一处理策略:一旦有节点加入或离开二叉树,则更新其所有祖先的高度

在每一节点v处,只需读出其左、右孩子的高度并取二者之间的大者,再计入当前节点本身,就得到了v的新高度。通常,接下来还需要从v出发沿parent指针逆行向上,依次更新各代祖先的高度记录。

template <typename T> Rank BinTree<T>::updateHeight( BinNodePosi<T> x ) //更新节点x高度
   { return x->height = 1 + max( stature( x->lc ), stature( x->rc ) ); } //具体规则,因树而异

template <typename T> void BinTree<T>::updateHeightAbove( BinNodePosi<T> x ) //更新高度
   { while ( x ) { updateHeight( x ); x = x->parent; } } //从x出发,覆盖历代祖先。可优化

更新每一节点本身的高度,只需执行两次getHeight()操作、两次加法以及两次取最大操作,不过常数时间,故updateHeight()算法总体运行时间也是O(depth(v) + 1),其中depth(v)为节点v的深度。

节点插入

template <typename T> BinNodePosi<T> BinTree<T>::insert( T const& e )
   { _size = 1; return _root = new BinNode<T>( e ); } //将e当作根节点插入空的二叉树

template <typename T> BinNodePosi<T> BinTree<T>::insert( T const& e, BinNodePosi<T> x )
   { _size++; x->insertAsLC( e ); updateHeightAbove( x ); return x->lc; } // e插入为x的左孩子

template <typename T> BinNodePosi<T> BinTree<T>::insert( BinNodePosi<T> x, T const& e )
   { _size++; x->insertAsRC( e ); updateHeightAbove( x ); return x->rc; } // e插入为x的右孩子

若二叉树T中某节点x的右孩子为空,则可为其添加一个右孩子。可调用x->insertAsRC()接口,将二者按照父子关系相互联接,同时通 过updateHeightAbove()接口更新x所有祖先的高度,并更新全树规模。左侧节点的插入过程与此相仿,可对称地调用insertAsLC()完成。

先序遍历

遍历: 按照某种次序访问树中各节点,每个节点被访问恰好一次。
在这里插入图片描述

二叉树遍历的全局次序由局部次序规则确定。
按惯例左孩子优先于右孩子,故若将节点及其孩子分别记作V、L和R,则如图所示,局部访问的次序有VLR、LVR和LRV三种选择。根据节点V在其中的访问次序,这三种策略也相应地分别称作先序遍历、中序遍历和后序遍历。

template <typename T, typename VST> //元素类型、操作器
void travPre_R ( BinNodePosi(T) x, VST& visit ) { //二叉树先序遍历算法(逑弻版)
	if ( !x ) return;
	visit ( x->data );
	travPre_R ( x->lc, visit );
	travPre_R ( x->rc, visit );
}//T(n)=O(n)

在这里插入图片描述

迭代实现(1)

使用辅助栈的特性实现

template <typename T, typename VST> //元素类型、操作器
void travPre_I1( BinNodePosi<T> x, VST& visit ) { //二叉树先序遍历算法(迭代版#1)
   Stack<BinNodePosi<T>> S; //辅助栈
   if ( x ) S.push( x ); //根节点入栈
   while ( !S.empty() ) { //在栈变空之前反复循环
      x = S.pop(); visit( x->data ); //弹出并访问当前节点,其非空孩子的入栈次序为先右后左
      if ( HasRChild( *x ) ) S.push( x->rc );//右孩子先入后出
      if ( HasLChild( *x ) ) S.push( x->lc );//左孩子后入先出
   }
}

迭代实现(2)

//从当前节点出发,沿左分支不断深入,直至没有左分支的节点;沿途节点遇到后立即访问
template<typename T,typename VST>	//分摊O(1)
static void visitAlongLeftBranch(BinNodePosi(T) x,VST & visit,Stack<BinNodePosi(T)>& S){
	while(x){	//反复地
		visit(x->data);	//访问当前节点
		S.push(x->rChild);	//右孩子(右子树)入栈(将来逆序出栈)
		x=x->lChild;	//沿左侧链下行
	}	//只有右孩子,NULL可能入栈
}

在这里插入图片描述
先序遍历序列可分解为两段:沿最左侧通路自顶而下访问的各节点,以及自底而上遍历的对应右子树。

template <typename T, typename VST> //元素类型、操作器
void travPre_I2 ( BinNodePosi(T) x, VST& visit ) { //二叉树先序遍历算法(迭代版#2)
	Stack<BinNodePosi(T)> S; //辅助栈
	while ( true ) {
		visitAlongLeftBranch ( x, visit, S ); //从当前节点出发,逐批讵问
		if ( S.empty() ) break; //直到栈空
		x = S.pop(); //弹出下一批的起点
	}
}

使用了一个辅助栈,逆序记录最左侧通路上的节点,以便确定其对应右子树自底而上的遍历次序

中序遍历

在这里插入图片描述
按照中序遍历规则,为遍历非空的(子)树x,将依次递归遍历其左子树、访问节点x、递归遍历其右子树

template <typename T, typename VST> //元素类型、操作器
	void travIn_R ( BinNodePosi(T) x, VST& visit ) { //二叉树中序遍历算法(递归版)
	if ( !x ) return;
	travIn_R ( x->lc, visit );
	visit ( x->data );
	travIn_R ( x->rc, visit );
}//O(n)

在这里插入图片描述
从根出发沿左分支下行,直至最深的节点

template <typename T> //从当前节点出发,沿左分支不断深入,直至没有左分支的节点
static void goAlongLeftBranch ( BinNodePosi(T) x, Stack<BinNodePosi(T)>& S ) {
	while ( x ) { S.push ( x ); x = x->lc; } //当前节点入栈后随即向左侧分支深入,迭代直到无左孩子
}

template <typename T, typename VST> //元素类型、操作器
void travIn_I1 ( BinNodePosi(T) x, VST& visit ) { //二叉树中序遍历算法(迭代版#1)
	Stack<BinNodePosi(T)> S; //辅助栈
	while ( true ) {
		goAlongLeftBranch ( x, S ); //从当前节点出发,逐批入栈
		if ( S.empty() ) break; //直至所有节点处理完毕
		x = S.pop(); visit ( x->data ); //弹出栈顶节点并访问之
		x = x->rc; //转向右子树(可能为空)
	}
}

在全树及其中每一棵子树的根节点处,该算法首先调用函数goAlongLeftBranch(),沿最左侧通路自顶而下抵达末端节点 L d L_d Ld 。在此过程中,利用辅助栈逆序地记录和保存沿途经过的各个节点,以便确定自底而上各段遍历子序列最终在宏观上的拼接次序。

后序遍历

在这里插入图片描述
与先序与中序遍历类似地,自底而上地沿着该通路,整个后序遍历序列也可分解为若干个片段。每一片段,分别起始于通路上的一个节点,并包括三步:访问当前节点,遍历以其右兄弟(若存在)为根的子树,以及向上回溯至其父节点(若存在)并转入下一片段

template <typename T, typename VST> //元素类型、操作器
void travPost_R ( BinNodePosi(T) x, VST& visit ) { //二叉树后序遍历算法(逑弻版)
	if ( !x ) return;
	travPost_R ( x->lc, visit );
	travPost_R ( x->rc, visit );
	visit ( x->data );
}

在这里插入图片描述

template <typename T> //在以S栈顶节点为根的子树中,找到最高左侧可见叶节点
static void gotoHLVFL ( Stack<BinNodePosi(T)>& S ) { //沿途所遇节点依次入栈
	while ( BinNodePosi(T) x = S.top() ) //自顶而下,反复检查当前节点(即栈顶)
		if ( HasLChild ( *x ) ) { //尽可能向左
			if ( HasRChild ( *x ) ) S.push ( x->rc ); //若有右孩子,优先入栈
			S.push ( x->lc ); //然后才转至左孩子
		} 
		else //实不得已
			S.push ( x->rc ); //才向右
	S.pop(); //迒回乀前,弹出栈顶癿空节点
}

template <typename T, typename VST>
void travPost_I ( BinNodePosi(T) x, VST& visit ) { //二叉树的后序遍历(迭代版)
	Stack<BinNodePosi(T)> S; //辅助栈
	if ( x ) S.push ( x ); //根节点入栈
	while ( !S.empty() ) {
		if ( S.top() != x->parent ) //若栈顶非当前节点之父(则必为其右兄),此时需
			gotoHLVFL ( S ); //在以其右兄为根的子树中,找刡HLVFL(相当于递归深入其中)
x = S.pop(); visit ( x->data ); //弹出栈顶(即前一节点之后继),并访问问之
}
}

可见,在每一棵(子)树的根节点,该算法都首先定位对应的HLVFL节点。同时在此过程中,依然利用辅助栈逆序地保存沿途所经各节点,以确定遍历序列各个片段在宏观上的拼接次序。

层次遍历

在这里插入图片描述
迭代式层次遍历则需要使用与栈对称的队列结构

template <typename T> template <typename VST> //元素类型、操作器
void BinNode<T>::travLevel ( VST& visit ) { //二叉树层次遍历算法
	Queue<BinNodePosi(T)> Q; //辅助队列
	Q.enqueue ( this ); //根节点入队
	while ( !Q.empty() ) { //在队列再次变空之前,反复迭代
		BinNodePosi(T) x = Q.dequeue(); visit ( x->data ); //取出队首节点幵讵问之
		if ( HasLChild ( *x ) ) Q.enqueue ( x->lc ); //左孩子入队
		if ( HasRChild ( *x ) ) Q.enqueue ( x->rc ); //右孩子入队
	}
}

Huffman 树

Prefix-free code:不同字符的编码互不为前缀,故不致歧义。
Huffman树(也称为霍夫曼树)是一种用于数据压缩的二叉树,通常用于编码和解码数据。
Huffman树的主要思想是使用不等长的编码来表示不等概率的字符或符号,以便更频繁出现的字符使用较短的编码,从而实现数据压缩。

Huffman树的构建过程通常包括以下步骤:
1)统计每个字符或符号在数据中出现的频率,然后将它们作为叶子节点构建初始的一棵二叉树。每个叶子节点的权重等于字符的频率。
2)创建一个优先队列(通常使用最小堆或最小优先队列),并将所有的叶子节点插入到队列中,根据权重进行排序。
3)从优先队列中取出权重最小的两个节点,合并它们,然后将合并后的节点插入回队列中。合并后的节点的权重等于两个子节点的权重之和。
4)重复步骤3,直到队列中只剩下一个节点,这个节点就是Huffman树的根节点。
5)构建完整的Huffman树后,为每个字符或符号分配一个唯一的编码,编码规则是:从根节点出发,左子树路径标记为0,右子树路径标记为1,直到到达叶子节点。这样,每个字符都有一个不同长度的二进制编码。

Huffman树的一个关键特性是,具有较高频率的字符拥有较短的编码,而较低频率的字符拥有较长的编码。这种编码方式可以有效地减小数据的存储或传输空间,因为常用字符的编码较短,不常用字符的编码较长。

若考虑出现频率,完全二叉树或满树未必最优。
若考虑字符各自的出现频率,则可将带权平均编码长度取作编码树 T 的叶节点带权平均深度(weighted average leaf
depth): w a l d ( T ) = ∑ x ∈ ∑ p ( x ) ⋅ ∣ r p s ( x ) ∣ wald(T) = \sum_{x\in \sum}p(x)\cdot |rps(x)| wald(T)=xp(x)rps(x)

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

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

相关文章

去除pdf/word的水印艺术字

对于pdf中的水印如果无法去除水印&#xff0c;则先另存为word&#xff0c;然后再按下面办法处理即可&#xff1a; 查看宏&#xff0c;创建&#xff1a;删除艺术字 添加内容&#xff1a; Sub 删除艺术字()Dim sh As ShapeFor Each sh In ActiveDocument.ShapesIf sh.Type msoT…

用ASE制作地表积水效果

unity引擎制作实时刷下雨地面效果 大家好&#xff0c;我是阿赵。   之前在Unity引擎做了几种不同的效果&#xff0c;比如视差偏移、下雨效果、顶点颜色工具等。这一篇文章&#xff0c;将会把这几个效果合并在一起&#xff0c;做出一个混合积水地表的效果。这个几个shader的基…

基于elelemt-ui封装一个表单

子组件 searchForm <template><el-formref"form":model"value":rules"rules":label-width"labelWidth":inline"inline"><el-form-itemv-for"field in fields":key"field.slot":label&q…

JMeter基础 —— 使用Badboy录制JMeter脚本!

1、使用Badboy录制JMeter脚本 打开Badboy工具开始进行脚本录制&#xff1a; &#xff08;1&#xff09;当我们打开Badboy工具时&#xff0c;默认就进入录制状态。 如下图&#xff1a; 当然我们也可以点击录制按钮进行切换。 &#xff08;2&#xff09;在地址栏中输入被测地…

excel单元格多行文本的excel 提取 公式

excel单元格多行文本的excel 提取 公式 第一行&#xff1a; TRIM(MID(SUBSTITUTE(A$1,CHAR(10),REPT(" ",160)),ROW(A1)*160-159,160)) 第9行&#xff1a; TRIM(MID(SUBSTITUTE(A$1,CHAR(10),REPT(" ",160)),ROW(A9)*160-159,160)) Excel如何提取某一单元…

GRU实现时间序列预测(PyTorch版)

&#x1f4a5;项目专栏&#xff1a;【深度学习时间序列预测案例】零基础入门经典深度学习时间序列预测项目实战&#xff08;附代码数据集原理介绍&#xff09; 文章目录 前言一、基于PyTorch搭建GRU模型实现风速时间序列预测二、时序数据集的制作三、数据归一化四、数据集加载器…

Multi Query Attention Group Query Attention

Multi Query Attention(MQA)在2019年就被提出来了&#xff0c;用于推理加速&#xff0c;但在当时并没有受到很多关注&#xff0c;毕竟一张2080就能跑Bert-base了。随着LLM的大火&#xff0c;MQA所带来的收益得以放大。 思路 Multi Query Attention(MQA)跟Multi Head Attention…

win10 自带虚拟机软件 虚拟CentOS系统

win10 下使用需要虚拟一个系统&#xff0c;不需要额外安装VMware、Virtual box等软件。使用win10 自带虚拟机软件即可 步骤1 确保启动Hyper-V 功能启用 控制面板 -> 程序 -> 启用或关闭Windows功能 步骤 2 创建虚拟机 2.1 打开Typer-V 2.2 创建虚拟机 2.2.1 操作 -&g…

什么是数据湖?数据湖的概念及发展历程

随着云计算、社交媒体、物联网、短视频等新一代互联网技术的快速发展&#xff0c;数据的数量和复杂性不断增加。许多企业和组织已经积累了大量的各种类型的数据&#xff0c;对于如何存储和管理这些海量数据&#xff0c;以及如何高效地分析和利用这些数据&#xff0c;是每个组织…

数字IC设计笔试面试经典题(1-10)

1 基础知识 1.1 锁存器的结构 锁存器即Latch &#xff0c;数电中称之为电平触发的D触发器&#xff0c;也是D型锁存器&#xff0c;有电平触发器SR触发器改进得到&#xff0c;其工作特点是电平是有效电平&#xff08;高电平或者低电平&#xff09;期间&#xff0c;才接受信号并…

Vue中实现全景房看图3D

示例代码 安装photo-sphere-viewer yarn add -D photo-sphere-viewer 组件引入插件 import { Viewer } from photo-sphere-viewer; import photo-sphere-viewer/dist/photo-sphere-viewer.css; // 引入样式 import MarkersPlugin from photo-sphere-viewer/dist/plugins/marker…

一文读懂LCD、OLED、LED屏的区别以及透明液晶屏原理

参考文章科普&#xff5c;一文读懂LCD、LED和OLED 的区别 - 知乎 参考文章透明液晶显示屏的原理&#xff1f; - 知乎 一、LCD LCD是英文Liquid Crystal Display 的简称&#xff0c;指的是液晶显示屏。 主要想介绍下LCD透明屏方案&#xff1a; 所谓LCD透明屏&#xff0c;并…

Postman接口调用api

1.选择类型&#xff0c;输入URL 2.选择Basic Type 3.选择格式类型 文件类型 4.Send发送请求&#xff0c;获得返回

澄海区图书馆《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著

澄海区图书馆《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著

蛤蟆先生去看心理医生笔记

自我状态 儿童自我状态&#xff1a;行为和感受像个孩子。由童年残留的遗迹搭建而成&#xff0c;包含小时候体验的所有情感&#xff08;儿童的基本情感&#xff09;和随后演变的行为模式。 行为和感受像个孩子。由童年残留的遗迹搭建而成&#xff0c;包含小时候体验的所有情感…

【SpringMVC】JSR303与拦截器的使用

文章目录 一、JSR3031.1 JSR303是什么1.2 JSR 303的好处包括1.3 常用注解1.4 实例1.4.1 导入JSR303依赖1.4.2 规则配置1.4.3 编写校验方法1.4.4 编写前端 二、拦截器2.1 拦截器是什么2.2 拦截器与过滤器的区别2.3.应用场景2.4 快速入门2.5.拦截器链2.6 登录拦截权限案例2.6.1 L…

视频监控系统/视频云存储EasyCVR接入国标GB28181设备无法播放设备录像,是什么原因?

安防视频监控平台EasyCVR支持将部署在监控现场的前端设备进行统一集中接入&#xff0c;可兼容多协议、多类型设备&#xff0c;管理员可选择任意一路或多路视频实时观看&#xff0c;视频画面支持单画面、多画面显示&#xff0c;视频窗口数量有1、4、9、16个可选&#xff0c;还能…

第四章 Linux网络编程

ARP 协议 ARP 协议&#xff08;Address Resolution Protocol&#xff09;通过 IP 地址查找对应的 MAC 地址。 当一个主机需要发送数据给另一个主机时&#xff0c;它首先会检查本地的 ARP 缓存表&#xff08;ARP cache&#xff09;中是否存在目标主机的 MAC 地址。如果存在&…

【VS插件】VS code上的Remote - SSH

【VS插件】VS code上的Remote - SSH 目录 【VS插件】VS code上的Remote - SSH获得Linux服务器或者Linux系统的IP地址下载插件远程登录注意如果Linux虚拟机系统无法连接成功可能是没有开启ssh服务优势 作者&#xff1a;爱写代码的刚子 时间&#xff1a;2023.9.12 前言&#xff1…

社群团购是简单的商业模式,把握红利,冲刺双11

其实&#xff0c;不管微商、社群团购、直播带货、内容电商、视频号&#xff0c;小红书电商……都只是卖货的渠道&#xff0c;新渠道 社群团购让销售变得更加专业和简单&#xff0c;货源方负责产品的生产、渠道方负责销售。好好卖货&#xff0c;卖好货&#xff01; 是分工合作&a…