【遍历二叉树】---先,中,后,层序遍历 及 先序建立整树

news2024/11/18 5:38:57

0.二叉树结点的链式存储结构

#include<stdio.h>
#include<stdlib.h>

typedef char TElemType;//树中元素基本类型为char类型

#define bool int
#define true 1
#define false 0

//二叉树结点链式存储结构(二叉链表)
typedef struct BiNode
{
	TElemType data;//数据域
	struct BiNode* lchild, * rchild;//左,右孩子指针
}BiNode,*BiTree;
//BiNode:用来定义结点类型
//BiTree:用来定义树类型

1.遍历的相关特性

  • 遍历定义------- 顺着某一条搜索路径巡访二叉树中的结点,使得每个结点均被访问一次,而且仅被访问一次(又称周游)。
  • “访问”:可以是对结点作各种处理,如:输出结点的信息修改结点的数据值等,但要求这种访问不破坏原来的数据结构
  • 遍历目的:得到树中所有结点的一个线性排列
  • 遍历用途:它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心

2.遍历方法

2.1方法概览

在这里插入图片描述
假设:

  • L:遍历子树
  • D:访问根结点
  • R:遍历子树
  • 则遍历整个二叉树的方案共有6种:

在这里插入图片描述

  • 规定先左后右,则只有前三种情况:

在这里插入图片描述

  • 算法描述如下:
    在这里插入图片描述
    由二叉树的递归定义可知,遍历左子树和遍历右子树可如同遍历二又树一样“递归”进行

2.2先序遍历二叉树----DLR

2.2.1方法详解:根左右

在这里插入图片描述
核心子树为空时,结束操作;子树不为空,重复先序遍历的过程遍历子树

2.2.2手写遍历顺序实例分析:

  • (1)较简单的例子
    在这里插入图片描述
  • (2)较复杂的例子
    在这里插入图片描述

在这里插入图片描述

2.2.3先序递归遍历算法

  • 简单示例的分析:
    在这里插入图片描述
    在这里插入图片描述
  • 实例在程序中运行的过程
    在这里插入图片描述
  • 算法步骤:
    注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool PreOrderTraverse(BiTree T)

(1)返回条件:子树为空,则返回true;
(2)访问根结点
(3)递归遍历左子树
(4)递归遍历右子树

//1.先序遍历二叉树(根左右)
//注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool PreOrderTraverse(BiTree T)
{
	//[1]返回条件:子树为空,则返回true;
	if (T == NULL)
	return true;

	//[2]访问根结点
	printf("%c", T->data);

	//[3]递归遍历左子树
	PreOrderTraverse(T->lchild);

	//[4]递归遍历右子树
	PreOrderTraverse(T->rchild);
}

2.3中序遍历二叉树----LDR

2.3.1方法详解:左根右

在这里插入图片描述

2.3.2手写遍历顺序实例分析:

  • (1)较简单的例子
    在这里插入图片描述

  • (2)较复杂的例子
    在这里插入图片描述
    在这里插入图片描述

2.3.3中序递归遍历算法

  • 简单示例的分析:
    在这里插入图片描述
    在这里插入图片描述
  • 算法步骤:
bool InOrderTraverse(BiTree T)

注意:传入指向根结点的一级指针,因为遍历并不改变数据结构

(1)返回条件:子树为空,则返回true;;
(2)递归遍历左子树
(3)访问根结点
(4)递归遍历右子树

//2.中序遍历二叉树(左根右)
//注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool InOrderTraverse(BiTree T)
{
	//[1]返回条件:子树为空,则返回true;
	if (T == NULL)
	return true;

	//[2]递归遍历左子树
	InOrderTraverse(T->lchild);

	//[3]访问根结点
	printf("%c", T->data);

	
	//[4]递归遍历右子树
	InOrderTraverse(T->rchild);
}

2.4后序遍历二叉树----LRD

2.4.1方法详解:左右根

在这里插入图片描述

2.4.2手写遍历顺序实例分析:

  • (1)较简单的例子
    在这里插入图片描述

  • (2)较复杂的例子
    在这里插入图片描述
    在这里插入图片描述

2.3.3后序递归遍历算法

  • 简单示例的分析:
    在这里插入图片描述

在这里插入图片描述

  • 算法步骤:
bool PostOrderTraverse(BiTree T)

注意:传入指向根结点的一级指针,因为遍历并不改变数据结构

(1)返回条件:子树为空,则返回true;;
(2)递归遍历左子树
(3)递归遍历右子树
(4)访问根结点

//3.后序遍历二叉树(左右根)
//注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool PostOrderTraverse(BiTree T)
{
	//[1]返回条件:子树为空,则返回true;
	if (T == NULL)
		return true;

	//[2]递归遍历左子树
	PostOrderTraverse(T->lchild);

	//[3]递归遍历右子树
	PostOrderTraverse(T->rchild);

	//[4]访问根结点
	printf("%c", T->data);
}

2.5运算式树的实例:

在这里插入图片描述

可以自己练习一下

2.6遍历算法的分析

  • (1)如果去掉输出语句,从递归的角度看,三种算法是完全相同的,或说这三种算法的访问路径是相同的,只是访问结点的时机不同
    在这里插入图片描述
    在这里插入图片描述
  • (2)算法的效率分析
  • 时间效率: O(n) 每个结点只访问一次
  • 空间效率: O(n) 栈占用的最大辅助空间

2.7由遍历序列确定二叉树(核心先后定根,中分左右

2.7.1遍历二叉树的特点

  • 若二叉树中各结点的值均不相同,则二叉树结点的先序序列、中序序列、后序序列都是唯一的。
  • 由二叉树的先序序列和中序序列,或由二叉树的后序序列和中序序列可以确定唯一一棵二叉树

2.7.2已知先序和中序序列求二叉树

在这里插入图片描述
回顾先序特点:根左右
回顾中序特点:左根右
实例分析
在这里插入图片描述
(1)

  • 先序根左右,故A为根
  • 中序左根右,故CDBFE为左子树;---------------IHGJ为右子树
    ------即先序中的BCDEF序列---------即先序中的GHIJ序列
    在这里插入图片描述

(2)

  • 先序根左右,故左子树中B为根;右子树中G为根
  • 中序左根右
    -B为根:---- CD为左子树;---------------FE为右子树
    即先序中的CD序列---------即先序中的EF序列
  • G为根:------IH为左子树;---------------J为右子树
    即先序中的HI序列---------即先序中的J序列
    在这里插入图片描述
    (3)
  • 先序根左右,故左子树中C为根,E为根;右子树中H为根,J为叶子结点
  • 中序左根右
    -C为根:---- D为右子树
    由中序中的CD序列根右得到
  • E为根:------F为左子树
    由中序中的FE序列左根得到
  • H为根:------I为左子树
    由中序中的IH序列左根得到

在这里插入图片描述
通过以上三步得到对应的二叉树

2.6.3已知后序和中序序列求二叉树

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

(1)

  • 后序左右根,故A为根
  • 中序左根右,故BDCE为左子树;---------------FHG为右子树
    ------即后序中的DECB序列---------即先序中的HGF序列
    在这里插入图片描述

(2)

  • 后序左右根,故左子树中B为根;右子树中F为根
  • 中序左根右
  • B为根:----------------DCE为右子树
    ----------即后序中的DEC序列
  • F为根:---------------HG为右子树
    ---------即后序中的HG序列
    在这里插入图片描述

(3)

  • 后序左右根,故左子树中C为根;右子树中G为根
  • 中序左根右
  • C为根:---- D为左叶子结点,E为右叶子节点
    由中序中的DCE序列左根右得到
  • G为根:------H为左叶子结点
    由中序中的HG序列左根得到
    在这里插入图片描述

2.7层序遍历二叉树----(从上往下,从左往右,逐层遍历)

2.7.1遍历特点

对于一颗二叉树,从根结点开始,按从上到下、从左到右的顺序访问每一个结点 且 每一个结点仅仅访问一次。
比如:
在这里插入图片描述
这颗二叉树的层序遍历结果为 abfcdgeh

2.7.2算法的设计思路

在这里插入图片描述
依旧是上述图例,分析此算法的执行过程:

  • (1)根结点指针入队
    在这里插入图片描述
  • (2)根结点指针出队,入队根结点的左右孩子指针bf
    在这里插入图片描述
    在这里插入图片描述
  • (3)b结点指针出队,入队b结点的左右孩子指针cd
    在这里插入图片描述
    在这里插入图片描述
  • (4)f结点指针出队,入队f结点的左孩子指针g,其右孩子指针不存在
    在这里插入图片描述
    在这里插入图片描述
  • (5)c结点指针出队,c结点的左右孩子指针不存在
    在这里插入图片描述
    在这里插入图片描述
  • (6)d结点指针出队,入队d结点的左孩子指针g,其右孩子指针不存在
    在这里插入图片描述
    在这里插入图片描述
  • (7)e结点指针出队,入队d结点的右孩子指针,其右孩子指针不存在

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

  • (8)h结点指针出队,h结点的左右孩子指针不存在
    在这里插入图片描述
    在这里插入图片描述
  • (9)此时队列为空,层序遍历结束
bool LevelOrder(BiNode* b)

注意:传入二叉树的根结点指针

//{4} 二叉树的层序遍历
// 注意:传入二叉树的根结点指针
bool LevelOrder(BiNode* b)
{
	//[1]创建并初始化一个队列
	queue qu;
	Initqueue(&qu);

	//[2]将根结点指针入队
	Enqueue(&qu, b);

	//[3]队不空时循环
	while (!queueEmpty(&qu))
	{
		//<1>从队列中出列一个结点*e,访问并输出它
		ElemType e;//这里的的e是用来接收队头元素的
		//队列中所有元素都是指向树结点的指针
		Dequeue(&qu, &e);
		printf("%c", e->data); // 输出当前结点的值
	    
	    //<2>若它有左孩子结点,将左孩子结点进队:
		if (e->lchild != NULL)
		{
			Enqueue(&qu, e->lchild);
		}

		//<3>若它有右孩子结点,将右孩子结点进队。
		if (e->rchild != NULL)
		{
			Enqueue(&qu, e->rchild);
		}
	}
	return true;
}

完整代码即实现如下:

//用循环顺序队列实现二叉树的层序遍历
#include <stdio.h>
#include <stdlib.h>
#include<stdbool.h>
//{1}先实现循环顺序队列的构造
//(少用一个空间)
#define MAXSIZE 100//队列最大容量


//----------------------------------------------------------
typedef char TElemType;//二叉树中的结点存储char类型的数据

//{2}二叉树的结构实现
typedef struct BiNode
{
	TElemType data;//数据域
	struct BiNode* lchild, * rchild;//左,右孩子指针
}BiNode, * BiTree;
//-----------------------------------------------------------

typedef BiTree ElemType;//构造出来的队列用来存储指向树结点的指针

typedef struct queue
{
	ElemType* data;
	int front;
	int rear;
}queue;

//[1]初始化队列
bool Initqueue(queue *q)
{
	q->data =(ElemType*)malloc(sizeof(ElemType) * MAXSIZE);

	if (!q)
	{
		return false;
	}

	q->front = q->rear = 0;
	return true;
}


//[2]入队操作
bool Enqueue(queue* q,ElemType e)
{
	if ((q->rear + 1) % MAXSIZE == q->front)
	{
		return false;//队满
	}

	q->data[q->rear] = e;
	q->rear = (q->rear + 1) % MAXSIZE;
	return true;
}


//[3]出队操作
bool Dequeue(queue* q, ElemType* e)
{
	if (q->rear == q->front)
	{
		return false;//队空
	}

	*e = q->data[q->front];

	q->front = (q->front + 1) % MAXSIZE;
	return true;
}

//[4]判断队空
bool queueEmpty(queue* q)
{
	if (q->front == q->rear)
	{
		return true;
	}
	return false;
}





//{3}先序创建二叉树
bool CreateBiTree(BiTree* T)
{
	//[1]定义临时变量ch,用来存储每次输入的字符
	TElemType ch;
	scanf_s("%c", &ch);

	//[2]若输入为#,则建立空结点,并返回
	if (ch == '#')
	{
		(*T) = NULL;
	}
	//易错点1:输入空结点时,(*T) = NULL操作之后 应直接返回上一层,故if-else 语句块不能省略

	//[2]否则创建结点,并按先序遍历序列递归建立其左右孩子结点
	else
	{
		//<1>开辟子根结点空间(第一个结点为根结点)
		(*T) = (BiNode*)malloc(sizeof(BiNode));

		if (!(*T))
		{
			printf("内存分配失败!\n");
			exit(-1);//程序错误,退出程序
		}

		//<2>将当前字符 存入 当前根结点
		(*T)->data = ch;
		//<3>构造左子树
		CreateBiTree(&((*T)->lchild));
		//<4>构造右子树
		CreateBiTree(&((*T)->rchild));
		//易错点2:传入的应该是 左右孩子指针的地址,而不是 左右孩子指针本身。因为要修改左右孩子指针的值(指向创建的新结点)

	}
	return true;
}



//{4} 二叉树的层序遍历
// 注意:传入二叉树的根结点指针
bool LevelOrder(BiNode* b)
{
	//[1]创建并初始化一个队列
	queue qu;
	Initqueue(&qu);

	//[2]将根结点指针入队
	Enqueue(&qu, b);

	//[3]队不空时循环
	while (!queueEmpty(&qu))
	{
		//<1>从队列中出列一个结点指针(e),访问并输出它指向的树结点的值
		ElemType e;
		Dequeue(&qu, &e);
		printf("%c", e->data); // 输出当前结点的值
	    
	    //<2>若它有左孩子结点,将左孩子结点进队:
		if (e->lchild != NULL)
		{
			Enqueue(&qu, e->lchild);
		}

		//<3>若它有右孩子结点,将右孩子结点进队。
		if (e->rchild != NULL)
		{
			Enqueue(&qu, e->rchild);
		}
	}
	return true;
}





int main()
{
	BiTree T;
	CreateBiTree(&T);
	printf("层序遍历序列如下:");
	LevelOrder(T);
	printf("\n");
	return 0;
	return 0;
}

在这里插入图片描述
以模拟队列的二叉树实例为例:
先序建立二叉树应输入:abc##de###fg#h###
层序遍历二叉树的结果应为:abfcdgeh

2.8先序建立二叉树

按先序遍历序列建立二叉树的二叉链表(DRL)

2.8.1算法思路

  • (1)从键盘输入二叉树的结点信息,建立二又树的存储结构
  • (2)在建立二叉树的过程中按照二叉树先序方式建立

2.8.2二叉树序列的正确建立

  • (1)我们知道,对于一颗二叉树,我们至少要知道两个序列:
    前序和中序 或者 后序和中序才能确定唯一的二叉树
    在这里插入图片描述
    显然这个先序序列的二叉树是不唯一的,如下图:
    在这里插入图片描述
    在这里插入图片描述
    那为了建立一颗唯一的二叉树,我们应该怎么办呢?
    方法就是:从二叉树中每个结点的空指针中引出一个虚结点
    这里我们使用“#”来表示
    如下图:
    在这里插入图片描述
    在这里插入图片描述
    此时根据补充出来的虚结点的不同,这样两颗二叉树的序列就完全不一样了

  • (2)所以对于下图这样的二叉树,在先序建立二叉树时,用户应输入的序列是:

在这里插入图片描述

在这里插入图片描述
分析如下:
在这里插入图片描述

2.8.3实例建立过程详解

在这里插入图片描述

(1)输入A,不是#,建立根结点
在这里插入图片描述
(2)通过左孩子指针,输入B,不是#,建立根结点
在这里插入图片描述
(3)通过左孩子指针,输入C,不是#,建立根结点
在这里插入图片描述
(4)(5)
通过左孩子指针,输入#,返回上一层
通过右孩子指针,输入#,返回上一层
在这里插入图片描述
(6)刚才返回到第二层,通过右孩子指针,输入D,不是#,建立根结点
在这里插入图片描述
(7)通过左孩子指针,输入E,不是#,建立根结点
在这里插入图片描述
(8)(9)(10)(11)
通过左孩子指针,输入#,返回上一层
通过右孩子指针,输入G,不是#,建立根结点
通过左孩子指针,输入#,返回上一层
通过右孩子指针,输入#,返回上一层(此时回到了第四层)

返回第三层
在这里插入图片描述
(12)(13)(14)
通过右孩子指针,输入F,不是#,建立根结点
通过左孩子指针,输入#,返回上一层
通过右孩子指针,输入#,返回上一层(此时回到了第三层)

返回第二层
返回第一层
在这里插入图片描述
(15)通过右孩子指针,输入#,返回上一层(此时整树建立完毕,返回主函数)
在这里插入图片描述

2.8.4先序建立二叉树的算法分析:

bool CreateBiTree(BiTree *T)

注意1:传入指向二叉结点指针的二级指针,因为在建立二叉链表时需要 改变指针指向的内容
注意2:在递归建立二叉树时,需要判断是否为空结点,即输入字符为#表示空结点
易错点1:输入空结点时,(*T) = NULL操作之后 应直接返回上一层,故if-else 语句块不能省略
易错点2:传入的应该是 左右孩子指针的地址,而不是 左右孩子指针本身。因为要修改左右孩子指针的值(指向创建的新结点)

(1)定义临时变量ch,用来存储每次输入的字符
(2)若输入为#,则建立空结点,并返回
(3)否则创建结点,并按先序遍历序列递归建立其左右孩子结点
<1>开辟子根结点空间(第一个结点为根结点)
<2>将当前字符 存入 当前根结点
<3>构造左子树
<4>构造右子树

//5.先序建立二叉树
//注意1:传入指向二叉结点指针的二级指针,因为在建立二叉链表时需要 改变指针指向的内容
//注意2:在递归建立二叉树时,需要判断是否为空结点,即输入字符为#表示空结点
bool CreateBiTree(BiTree *T)
{
	//[1]定义临时变量ch,用来存储每次输入的字符
	TElemType ch;
	scanf_s("%c",&ch);

	//[2]若输入为#,则建立空结点,并返回
	if (ch == '#')
	{
		(*T) = NULL;
	}
	//易错点1:输入空结点时,(*T) = NULL操作之后 应直接返回上一层,故if-else 语句块不能省略

	//[2]否则创建结点,并按先序遍历序列递归建立其左右孩子结点
	else
	{
		//<1>开辟子根结点空间(第一个结点为根结点)
		(*T) = (BiNode*)malloc(sizeof(BiNode));

		if (!(*T))
		{
			printf("内存分配失败!\n");
			exit(-1);//程序错误,退出程序
		}

		//<2>将当前字符 存入 当前根结点
		(*T)->data = ch;
		//<3>构造左子树
		CreateBiTree(&((*T)->lchild));
		//<4>构造右子树
		CreateBiTree(&((*T)->rchild));
		//易错点2:传入的应该是 左右孩子指针的地址,而不是 左右孩子指针本身。因为要修改左右孩子指针的值(指向创建的新结点)

	}
	return true;
}

2.9先 中 后序遍历+先序建立整树完整代码如下:

输入实例:
在这里插入图片描述
在这里插入图片描述

#include<stdio.h>
#include<stdlib.h>

typedef char TElemType;//树中元素基本类型为char类型

#define bool int
#define true 1
#define false 0

//二叉树结点链式存储结构(二叉链表)
typedef struct BiNode
{
	TElemType data;//数据域
	struct BiNode* lchild, * rchild;//左,右孩子指针
}BiNode,*BiTree;
//BiNode:用来定义结点类型
//BiTree:用来定义树类型


二叉树结点链式存储结构(三叉链表)
//typedef struct TriTNode
//{
//	TElemType data;//数据域
//	struct TriNode* lchild, * parent,* rchild;//左孩子,双亲,右孩子指针
//}TirNode, * TirTree;
TirNode:用来定义结点类型
TirTree:用来定义树类型


//1.先序遍历二叉树(根左右)
//注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool PreOrderTraverse(BiTree T)
{
	//[1]返回条件:子树为空,则返回true;
	if (T == NULL)
	return true;

	//[2]访问根结点
	printf("%c", T->data);

	//[3]递归遍历左子树
	PreOrderTraverse(T->lchild);

	//[4]递归遍历右子树
	PreOrderTraverse(T->rchild);
}


//2.中序遍历二叉树(左根右)
//注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool InOrderTraverse(BiTree T)
{
	//[1]返回条件:子树为空,则返回true;
	if (T == NULL)
	return true;

	//[2]递归遍历左子树
	InOrderTraverse(T->lchild);

	//[3]访问根结点
	printf("%c", T->data);

	
	//[4]递归遍历右子树
	InOrderTraverse(T->rchild);
}


//3.后序遍历二叉树(左右根)
//注意:传入指向根结点的一级指针,因为遍历并不改变数据结构
bool PostOrderTraverse(BiTree T)
{
	//[1]返回条件:子树为空,则返回true;
	if (T == NULL)
	return true;

	//[2]递归遍历左子树
	PostOrderTraverse(T->lchild);

	//[3]递归遍历右子树
	PostOrderTraverse(T->rchild);

	//[4]访问根结点
	printf("%c", T->data);
}

//5.先序建立二叉树
//注意1:传入指向二叉结点指针的二级指针,因为在建立二叉链表时需要 改变指针指向的内容
//注意2:在递归建立二叉树时,需要判断是否为空结点,即输入字符为#表示空结点
bool CreateBiTree(BiTree *T)
{
	//[1]定义临时变量ch,用来存储每次输入的字符
	TElemType ch;
	scanf_s("%c",&ch);

	//[2]若输入为#,则建立空结点,并返回
	if (ch == '#')
	{
		(*T) = NULL;
	}
	//易错点1:输入空结点时,(*T) = NULL操作之后 应直接返回上一层,故if-else 语句块不能省略

	//[2]否则创建结点,并按先序遍历序列递归建立其左右孩子结点
	else
	{
		//<1>开辟子根结点空间(第一个结点为根结点)
		(*T) = (BiNode*)malloc(sizeof(BiNode));

		if (!(*T))
		{
			printf("内存分配失败!\n");
			exit(-1);//程序错误,退出程序
		}

		//<2>将当前字符 存入 当前根结点
		(*T)->data = ch;
		//<3>构造左子树
		CreateBiTree(&((*T)->lchild));
		//<4>构造右子树
		CreateBiTree(&((*T)->rchild));
		//易错点2:传入的应该是 左右孩子指针的地址,而不是 左右孩子指针本身。因为要修改左右孩子指针的值(指向创建的新结点)

	}
	return true;
}

int main()
{
	BiTree T;
	CreateBiTree(&T);
	printf("先序遍历序列如下:");
	PreOrderTraverse(T);
	printf("\n");
	printf("中序遍历序列如下:");
	InOrderTraverse(T);
	printf("\n");
	printf("后序遍历序列如下:");
	PostOrderTraverse(T);
	printf("\n");
	return 0;
}

在这里插入图片描述

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

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

相关文章

java项目之基于springboot的贸易行业crm系统(源码+文档)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的基于springboot的贸易行业crm系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于sp…

GNSS多路径误差提取CMC和MPC

基本概念 伪距和载波相位观测值的多径误差并不相同&#xff0c;多径误差一般1-5米&#xff0c;最高可达10-20米。PPP利用伪距辅助模糊度固定&#xff0c;伪距质量不高多路径误差太大&#xff0c;会导致模糊度固定错。载波相位的多径误差小于四分之一波长。由于载波相位的多径误…

抢占AI营销新红利!枢纽云揭秘企业转型背后的成功路径

搜索作为用户获取信息的关键途径&#xff0c;正在经历一场具有划时代意义的变革&#xff0c;不断影响着用户的搜索行为习惯&#xff0c;还为品牌营销以及企业的数字化转型提供了良好契机。 从传统搜索到内容生态&#xff1a;品牌展现的新舞台 传统搜索引擎曾是互联网世界的绝对…

MQTT 协议概述

目录 一、概述二、协议模型1、组成部分2、客户端3、服务器 三、MATT 通信过程1、连接服务器2、订阅主题3、发布消息4、取消订阅5、断开连接 四、MQTT 数据包结构1、MQTT 固定头2、MQTT 可变头3. Payload消息体 五、示例演示 一、概述 MQTT&#xff08;Message Queuing Telemet…

乔拓云模板助力,微信小程序快速上线无需愁备案

想要快速打造并上线自己的微信小程序吗&#xff1f;乔拓云平台是您的不二之选&#xff01;无需担心复杂的备案流程&#xff0c;乔拓云提供免费服务&#xff0c;远程协助您轻松完成微信小程序的备案工作。 只需简单几步&#xff0c;您的小程序就能闪亮登场&#xff1a;首先&…

常见加密算法——哈希算法(MD)

文章目录 发现宝藏1.加密算法简介1.1 加密算法分类1.2 应用场景1.3 哈希算法的特点 2. 哈希算法的分类2.1 加密哈希算法2.2 非加密哈希算法2.3 其他常见哈希算法 3. MD53.1 MD5 简介3.2 MD5 Java 代码示例&#xff08;未加盐&#xff09;3.2 MD5 Python 代码示例&#xff08;未…

DroidBot: A Lightweight UI-Guided Test InputGenerator for Android论文学习

DroidBot就是之前用过的那个自动截图程序。那我很熟悉了&#xff0c;快速读完这篇论文。 brain默认使用深度优先探索&#xff0c;当然用户也可以使用自己的方法。 这玩意支持各种输入&#xff08;点击&#xff0c;滑动&#xff0c;输入文本&#xff09; 可以看到它会分辨当前页…

【Linux】探索进程控制奥秘,解锁高效实战技巧

目录 1.进程创建 1.1字符串常量为什么不可以修改&#xff1f; 1.2代码段和数据段到底是什么&#xff1f; 1.3.fork函数初识 1.4.fork函数返回值 1.5.写时拷贝&#xff1a; 1.6写时拷贝按需进行的原理&#xff08;与页表的权限有关&#xff09; 1.7.fork常规用法 2.进程…

跟着iMeta学做图 | 冲击图展示菌群随盐度的变化

本文代码已经上传至https://github.com/iMetaScience/iMetaPlot如果你使用本代码&#xff0c;请引用&#xff1a;Changchao Li. 2023. Destabilized microbial networks with distinct performances of abundant and rare biospheres in maintaining networks under increasing…

gen_server补充基础学习

学习gen_server的回调结构 gen_server:start_link(Name, Mod, InitArgs, Opts)这个调用是所有事物的起点。它 会创建一个名为Name的通用服务器&#xff0c;回调模块是Mod&#xff0c;Opts则控制通用服务器的行为。在这里可以指定消息记录、函数调试和其他行为。通用服务器通过…

基于QGIS 3.16.0 的OSM路网矢量范围裁剪实战-以湖南省为例

目录 前言 一、相关数据介绍 1、OMS路网数据 2、路网数据 3、路网图层属性 二、按省域范围进行路网裁剪 1、裁剪范围制定 2、空间裁剪 3、裁剪结果 三、总结 前言 改革开放特别是党的十八大以来&#xff0c;我国公路发展取得了举世瞩目的成就。国家高速公路网由“7 射…

ATECLOUD平台相比传统ATE测试有哪些独特的优势?

随着科技的飞速发展&#xff0c;在电子测量行业&#xff0c;自动化测试也逐渐取代了传统手动&#xff0c;市场上的大多数测试企业近几年都在进行自动化转型&#xff0c;而伴随着测试行业自动化、智能化的趋势&#xff0c;各类自动化测试系统也发展迅速&#xff0c;在众多ATE自动…

一种模式包含引流和复购 让你的私域电商平台腾飞!

在当今的商业环境中&#xff0c;一种名为“循环购”的创新商业模式正悄然兴起&#xff0c;它打破了传统消费观念&#xff0c;让“消费1000送2000&#xff0c;每日领钱&#xff0c;轻松提现”不再是遥不可及的梦想。很多人可能会问&#xff0c;这究竟是商家的慷慨解囊&#xff0…

多模态大模型-MiniCPM-V

1. 简介 本文主要探索如何在性能和效果之间的权衡&#xff0c;希望能在合适的性能下&#xff0c;模型效果有大幅的提升。主要贡献点有&#xff1a; 通过模型结构&#xff0c;数据&#xff0c;训练策略等优化&#xff0c;让MiniCPM-Lllama3-V 2.5[1]在OpenCompass评测上超过了…

03:手动可变电阻

可变电阻 1、电位器2、变阻器/数字电位器2.1&#xff1a;变阻器2.2&#xff1a;数字电位器 3、电位器锥度4、寄生电感/电容 1、电位器 如上图所示&#xff1a;将可变的电阻作为分压器&#xff0c;那么这种可变的电阻就是电位器。例如&#xff1a;将L1连接负极&#xff0c;L3连接…

SQLMAP windows10 安装记录

1.Windows系统下安装Sqlmap&#xff0c;需要安装python环境 python下载和安装 官方下载 https://www.python.org/downloads 建议直接下载安装版&#xff1a;installer 最后到这个界面正常是成功了&#xff0c;但也要校验一下 进入windows 命令窗口 正常输入你安装的python 版本…

OpenHarmony(鸿蒙南向开发)——轻量系统芯片移植指南(二)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ OpenHarmony&#xff08;鸿蒙南向开发&#xff09;——轻量系统芯片移植指南(一) Op…

数据库与表的操作

目录 1. 库的操作 1.1创建数据库案例 1.2字符集和校验规则 1.2.1查看系统默认字符集以及校验规则 1.2.2 查看数据库支持的字符集 1.2.3查看数据库支持的字符集校验规则 1.2.4校验规则对数据库的影响 1.3.1查看数据库 1.3.2显示创建语句 1.3.3修改数据库 1.3.4 数据…

将一句英文颠倒输出

例如&#xff1a; 输入&#xff1a;s “i am from beijing" 输出&#xff1a;”beijing form am i“ #include <stdio.h> #include <string.h>//i am form nanjing //ginjnan mrof ma i //nanjing form am i//逆序算法(首尾互换) void Reserve(char *s,in…

windows 创建新用户,并分配到指定组

右击电脑 -> 点击管理 在右边右击&#xff0c;选择新用户&#xff0c;输入相关信息创建 创建用户后&#xff0c;选择用户&#xff0c;右击&#xff0c;选择属性&#xff0c;添加 点击高级 点击立即查找&#xff0c;可以搜索出所有可用的组&#xff0c;为其选择即可