二叉树及其相关题目相关的功能的实现

news2024/11/28 10:32:03

       前言:前面我们简单提及了二叉树的相关初级知识和顺序实现二叉树的相关操作详解,并且由完全二叉树延伸到了堆的相关知识,具体详见二叉树初阶和堆的详解,今天,我们展开二叉树的相关 的链式实现操作和经常考察的二叉树的相关问题,争取一次搞定二叉树的基础问题。

 

目录

1.二叉树的链式实现

1.1二叉树的三种遍历方式

1.2 二叉树创建的两种方式

 1.2.1 已知先序(后序)+中序遍历序列

          递归建树原理解释

          代码实现:

1.2.2 根据带空节点的任意一个遍历序列数组来建树

1.3 二叉树的部分功能的实现

1.3.1 层序遍历实现(BFS)

1.3.2 求二叉树的节点个数,叶子个数和高度

1.3.3 求二叉树第k层节点的个数

1.3.4 查找二叉树中数值域等于x的节点并返回

1.3.5 判断是否完全二叉树

1.4 完整代码

2.金句频道


1.二叉树的链式实现

      二叉树常见的创建方式可以分为两种,一种是直接通过带空节点的先序中序后序遍历中的任何一个序列创建出来,另一种则是较为常用的不带空节点的,这种就需要先序+中序或者后序+中序的组合才能确定和创建这棵二叉树,上面两种方式都与二叉树的三种遍历(先、中、后序)遍历有关,为此我们要先来了解什么是先序中序和后序遍历。

1.1二叉树的三种遍历方式

1. 前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。
2. 中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)。
3. 后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后。

比如,我这里有这样一棵二叉树:

三种遍历方式,都是从根节点出发的,只是访问和输出的规则以及顺序不一致:

       对于先序遍历来说,从根节点A出发,我们每走到一棵子树,都会先将它的根节点输出,然后再分别递归其左右子树,然后再做相同的操作,直到递归结束,得到的输出序列就是先序遍历序列。

        对于中序遍历来说,还是从根节点开始遍历,但是根节点是在每一棵树的左子树“彻底”遍历完之后再输出,然后再是右子树的输出。

 对于后序遍历亦是同理,只是根在左右子树都遍历完之后输出.

       为了更好的帮助理解,我们现在直接给出三种遍历的函数实现,并在接下来采用递归调用函数栈帧的方式来帮助我们更好的理解,因为三种遍历过程思路上是一致的,一通百通,所以这里我们只是以中序遍历为例。(关于函数栈帧的相关知识,可以移步函数栈帧的创建与销毁)

//先序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

	printf("%c ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}
//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->data);
}

我们还是选取上面的给出的样例,如下的二叉树:

 

1.2 二叉树创建的两种方式

 1.2.1 已知先序(后序)+中序遍历序列

递归建树原理解释

 代码实现:

//以样例为例的先中后序数组
Elemtype pre[] = { 'A','B','D','C','E','G','F' };//Elemtype看做char类型就好
Elemtype in[] = { 'D','B','A','E','G','C','F' };
Elemtype pos[] = { 'D','B','G','E','F','C','A'};

//根据先序和中序序列确定一棵唯一的树
void CreatTreewithpreandin(BTNode*& root, int prel, int prer,int inl, int inr)
{
	int rootidx = -1;
	if (prel <= prer && inl <= inr)
	{

		//开始寻找该子树的根节点在中序序列中的位置
		for (int i = inl; i <= inr; i++)
		{
			if (in[i] == pre[prel])//先序遍历中的对应的子树区间内的第一个节点是根节点
			{
				rootidx = i;
				break;
			}
		}
		root = BuyNode(pre[prel]);
		//求出该子树的左子树的长度
		int len = rootidx - inl;
		//递归创建左右子树
		CreatTreewithpreandin(root->left, prel + 1, prel + len, inl, rootidx - 1);
		CreatTreewithpreandin(root->right, prel + len + 1, prer, rootidx + 1, inr);
	}
	
}
//根据后序和中序序列确定一棵唯一的树
void CreatTreewithposandin(BTNode*& root,int posl, int posr, int inl, int inr)
{
	int rootidx = -1;
	if (posl <= posr && inl <= inr)
	{

		//开始寻找该子树的根节点在中序序列中的位置
		for (int i = inl; i <= inr; i++)
		{
			if (in[i] == pos[posr])//后序序列的子树区间内的最后一个节点是根节点
			{
				rootidx = i;
				break;
			}
		}
		root = BuyNode(pos[posr]);
		//求出该子树的左子树的长度
		int len = rootidx - inl;
		//递归创建左右子树
		CreatTreewithposandin(root->left, posl, posl+len-1,inl,rootidx-1);
		CreatTreewithposandin(root->right, posl + len,posr-1, rootidx + 1, inr);
	}
}

1.2.2 根据带空节点的任意一个遍历序列数组来建树

       前面说我们无法根据仅有先中后序遍历中的其中之一的数组来建树,为什么这里就可以了呢?那是因为先中后序遍历只知其一,我们无法确定二叉树的孩子结构,也就是说,一个节点到底是父节点的左孩子还是右孩子我们无法确定,因为不论是左孩子还是右孩子,在遍历中得出的结果很有可能是一致的,这也就导致了我们无法唯一的确定一棵二叉树。但是,对,但是,如果存在空节点和其他节点构成完整的子树结构,简而言之,就是假设一个树没有左孩子,那么在创建时就会将该位置补上一个特殊的符号来表示空节点,这样就可以构成完整的二叉树结构。

我们给出一个例子,比如说有一个先序数组为 "ABD##E#H##CF##G##",其中‘#’就表示空节点,


// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(Elemtype* src, int n, int* idx)//其中idx传入的是数组的当前遍历位置的下标,因为值传递会因为函数栈帧的销毁而失去效果,所以此处改为传址调用,src是前序遍历数组
{
	if (*idx >= n || src[*idx] == '#')
	{
		(*idx)++;
		return NULL;
	}

	BTNode* cur = (BTNode*)malloc(sizeof(BTNode));
	cur->data = src[*idx];
	(*idx)++;

	cur->left = BinaryTreeCreate(src, n, idx);//传地址,地址上存储的是当前遍历到的数组的下标
	cur->right = BinaryTreeCreate(src, n, idx);

	return cur;
}

1.3 二叉树的部分功能的实现

1.3.1 层序遍历实现(BFS)

       这部分我使用了C++的queue来实现,之前我们实现过的模拟队列也可以实现,只是过程稍加繁琐,层序遍历就是按二叉树的高度遍历,从根节点开始,逐层往下遍历,我们可以使用队列,在逐层访问时将根节点的左右孩子入队,当父节点层遍历完毕时,队首元素就是下一层的遍历顺序。

//层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	//迭代法利用队列进行宽度优先遍历(C++STL)
	queue<BTNode*> mp;
	if (!root)
		return;
	mp.push(root);
	while (!mp.empty())
	{
		BTNode* temp = mp.front();
		printf("%c ", temp->data);
		mp.pop();
		if (temp->left)
			mp.push(temp->left);
		if (temp->right)
			mp.push(temp->right);
	}
}    

1.3.2 求二叉树的节点个数,叶子个数和高度

 这部分就老生常谈了,但凡会递归的,这些都不是问题啦,那我就直接......,嘿嘿~~

// 二叉树结点个数
int BTreeSize(BTNode* root)
{

	return root == NULL ? 0 : BTreeSize(root->left)
		+ BTreeSize(root->right) + 1;
}

// 求叶子节点的个数
int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	if (root->left == NULL
		&& root->right == NULL)
	{
		return 1;
	}

	return BTreeLeafSize(root->left)
		+ BTreeLeafSize(root->right);
}

//二叉树的高度
int BTreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = BTreeHeight(root->left);
	int rightHeight = BTreeHeight(root->right);//注意这种保存值的方式更加高效,可以画递归图证明

	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

1.3.3 求二叉树第k层节点的个数

       还是递归,求解第k层的节点,假设k=3,在二叉树有第三层的条件下,我们在递归遍历的过程中,每次进入一个父节点的孩子节点遍历时,k就减1,当k到1时就到了第k层,开始计数即可。

// 二叉树第k层结点个数
int BTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);

	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return BTreeLevelKSize(root->left, k - 1)
		+ BTreeLevelKSize(root->right, k - 1);
}

1.3.4 查找二叉树中数值域等于x的节点并返回

       这个函数一定要画个递归逻辑图,否则很有可能调到坑里去,如果我们在递归遍历的某个节点返回的话,并不是直接结束函数返回值,而是返回的该函数的上一层调用,所以,我们在递归调用左右子树时,需要判断返回。

//二叉树查找节点值为x的节点
BTNode* BinaryTreeFind(BTNode* root, Elemtype x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* left= BinaryTreeFind(root->left, x);//遍历完左子树看left的返回值
	if (left)
		return left;
	return  BinaryTreeFind(root->right, x);//如果程序执行到了这一步,就说明有x也一定在右子树里,或者没有就可以直接返回NULL

}

1.3.5 判断是否完全二叉树

这个问题就要考虑一会了,我们先来想想完全二叉树是什么概念来着?

完全二叉树是一种特殊的二叉树结构,它具有以下两个特点:

1. 满二叉树:除了叶子节点,每个节点都有两个子节点,且所有叶子节点都在同一层级上

2. 节点分布均匀:在最后一层的节点如果不满,则只有在最后一层的右侧可以出现缺少的节点,其余各层节点都是满的,且最后一层节点必须按照从左到右的顺序排列。

       对完全二叉树最重要的定义就是叶子节点只能出现在最下层和次下层,所以我们想到可以使用队列辅助进行层次遍历——从上到下遍历所有层,每层从左到右,只有次下层和最下层才有叶子节点,其他层出现叶子节点就意味着不是完全二叉树。

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	if (root == NULL)
		return true;//空树一定是完全二叉树
	queue<BTNode*> mp;
	bool flag = false;
	mp.push(root);
	while (!mp.empty())
	{
		int sz = mp.size();
		for (int i = 0; i < sz; i++)
		{
			BTNode* temp = mp.front();
			mp.pop();
			if (temp->left != NULL)
			{
				mp.push(temp->left);
				if (flag)//表示已经是完全二叉树的叶子节点了(该处存在空节点,所以应该是最后了)
					return false;
			}
			else
			{
				//如果遇到了空节点,那么flag=true表示到了满足完全二叉树的最后的节点
				flag = true;
			}
			if (temp->right != NULL)
			{
				mp.push(temp->right);
				if (flag)//表示已经是完全二叉树的叶子节点了(该处存在空节点,所以应该是最后了)
					return false;
			}
			else
			{
				//如果遇到了空节点,那么flag=true表示到了满足完全二叉树的最后的节点
				flag = true;
			}

		}
	}
	return true;
}

1.4 完整代码

#include <bits/stdc++.h>
using namespace std;
typedef char Elemtype;

typedef struct node {
	Elemtype data;
	struct node* left;
	struct node* right;
}BTNode;

//先中后序数组
Elemtype pre[] = { 'A','B','D','C','E','G','F' };
Elemtype in[] = { 'D','B','A','E','G','C','F' };
Elemtype pos[] = { 'D','B','G','E','F','C','A'};
Elemtype pre2[] = { 'A','B','D','#','#','E','#','H','#','#','C','F','#','#','G','#','#' };
//创建新节点
BTNode* BuyNode(Elemtype x)
{
	BTNode* node = (BTNode*)malloc(sizeof(BTNode));
	if (node == NULL)
	{
		perror("malloc fail");
		return NULL;
	}

	node->data = x;
	node->left = NULL;
	node->right = NULL;

	return node;
}
//我们也可以根据带空节点的先序后序中序数组中的任意一个数组来确定一棵唯一的二叉树(这里以先序数组为例,‘N'表示此处为空)
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(Elemtype* src, int n, int* idx)
{
	if (*idx >= n || src[*idx] == '#')
	{
		(*idx)++;
		return NULL;
	}

	BTNode* cur = (BTNode*)malloc(sizeof(BTNode));
	cur->data = src[*idx];
	(*idx)++;

	cur->left = BinaryTreeCreate(src, n, idx);//传地址,地址上存储的是当前遍历到的数组的下标
	cur->right = BinaryTreeCreate(src, n, idx);

	return cur;
}

//根据先序和中序序列确定一棵唯一的树
void CreatTreewithpreandin(BTNode*& root, int prel, int prer,int inl, int inr)
{
	int rootidx = -1;
	if (prel <= prer && inl <= inr)
	{

		//开始寻找该子树的根节点在中序序列中的位置
		for (int i = inl; i <= inr; i++)
		{
			if (in[i] == pre[prel])//先序遍历中的对应的子树区间内的第一个节点是根节点
			{
				rootidx = i;
				break;
			}
		}
		root = BuyNode(pre[prel]);
		//求出该子树的左子树的长度
		int len = rootidx - inl;
		//递归创建左右子树
		CreatTreewithpreandin(root->left, prel + 1, prel + len, inl, rootidx - 1);
		CreatTreewithpreandin(root->right, prel + len + 1, prer, rootidx + 1, inr);
	}
	
}
//根据后序和中序序列确定一棵唯一的树
void CreatTreewithposandin(BTNode*& root,int posl, int posr, int inl, int inr)
{
	int rootidx = -1;
	if (posl <= posr && inl <= inr)
	{

		//开始寻找该子树的根节点在中序序列中的位置
		for (int i = inl; i <= inr; i++)
		{
			if (in[i] == pos[posr])//后序序列的子树区间内的最后一个节点是根节点
			{
				rootidx = i;
				break;
			}
		}
		root = BuyNode(pos[posr]);
		//求出该子树的左子树的长度
		int len = rootidx - inl;
		//递归创建左右子树
		CreatTreewithposandin(root->left, posl, posl+len-1,inl,rootidx-1);
		CreatTreewithposandin(root->right, posl + len,posr-1, rootidx + 1, inr);
	}
}

//先序遍历
void PrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

	printf("%c ", root->data);
	PrevOrder(root->left);
	PrevOrder(root->right);
}
//中序遍历
void InOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

	InOrder(root->left);
	printf("%c ", root->data);
	InOrder(root->right);
}
//后序遍历
void PostOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("NULL ");
		return;
	}

	PostOrder(root->left);
	PostOrder(root->right);
	printf("%c ", root->data);
}

//层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	//迭代法利用队列进行宽度优先遍历(C++STL)
	queue<BTNode*> mp;
	if (!root)
		return;
	mp.push(root);
	while (!mp.empty())
	{
		BTNode* temp = mp.front();
		printf("%c ", temp->data);
		mp.pop();
		if (temp->left)
			mp.push(temp->left);
		if (temp->right)
			mp.push(temp->right);
	}
}    
// 二叉树结点个数
int BTreeSize(BTNode* root)
{

	return root == NULL ? 0 : BTreeSize(root->left)
		+ BTreeSize(root->right) + 1;
}

// 求叶子节点的个数
int BTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}

	if (root->left == NULL
		&& root->right == NULL)
	{
		return 1;
	}

	return BTreeLeafSize(root->left)
		+ BTreeLeafSize(root->right);
}

//二叉树的高度
int BTreeHeight(BTNode* root)
{
	if (root == NULL)
		return 0;

	int leftHeight = BTreeHeight(root->left);
	int rightHeight = BTreeHeight(root->right);

	return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1;
}

// 二叉树第k层结点个数
int BTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);

	if (root == NULL)
		return 0;

	if (k == 1)
		return 1;

	return BTreeLevelKSize(root->left, k - 1)
		+ BTreeLevelKSize(root->right, k - 1);
}

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	if (root == NULL)
		return true;//空树一定是完全二叉树
	queue<BTNode*> mp;
	bool flag = false;
	mp.push(root);
	while (!mp.empty())
	{
		int sz = mp.size();
		for (int i = 0; i < sz; i++)
		{
			BTNode* temp = mp.front();
			mp.pop();
			if (temp->left != NULL)
			{
				mp.push(temp->left);
				if (flag)//表示已经是完全二叉树的叶子节点了(该处存在空节点,所以应该是最后了)
					return false;
			}
			else
			{
				//如果遇到了空节点,那么flag=true表示到了满足完全二叉树的最后的节点
				flag = true;
			}
			if (temp->right != NULL)
			{
				mp.push(temp->right);
				if (flag)//表示已经是完全二叉树的叶子节点了(该处存在空节点,所以应该是最后了)
					return false;
			}
			else
			{
				//如果遇到了空节点,那么flag=true表示到了满足完全二叉树的最后的节点
				flag = true;
			}

		}
	}
	return true;
}

//二叉树查找节点值为x的节点
BTNode* BinaryTreeFind(BTNode* root, Elemtype x)
{
	if (root == NULL)
		return NULL;
	if (root->data == x)
		return root;
	BTNode* left= BinaryTreeFind(root->left, x);//遍历完左子树看left的返回值
	if (left)
		return left;
	return  BinaryTreeFind(root->right, x);//如果程序执行到了这一步,就说明有x也一定在右子树里,或者没有就可以直接返回NULL

}
//二叉树的销毁
void BinaryTreeDestory(BTNode*& root)//引用可以用二级指针代替
{
	if (root)
	{
		BinaryTreeDestory(root->left);
		BinaryTreeDestory(root->right);
		free(root);
		root = NULL;
	}
}
int main()
{
	BTNode* root=NULL;
	//根据先序和中序建树
	/*CreatTreewithpreandin(root, 0, 6, 0, 6);
	printf("后序遍历序列为:->\n");
	PostOrder(root);*/

	//根据后序和中序建树
	/*CreatTreewithposandin(root, 0, 6, 0, 6);
	printf("先序遍历序列为:->\n");
	PrevOrder(root);*/

	//根据带空节点的先序序列建树
	int idx = 0;
	root=BinaryTreeCreate(pre2,17,&idx);
	printf("先序遍历序列为:->\n");
	PrevOrder(root);
	printf("\n层序遍历序列为:->\n");
	BinaryTreeLevelOrder(root);
	
	return 0;
}

2.金句频道

       你就应该满脑子都是前途,不用在意别人的看法,不再害怕别人讨厌自己,不在畏手畏脚忧心忡忡,也不会在睡前反复回忆白天的行为,是否会让对方产生误解。要么努力往上爬,要么永远烂在底层里,这就是现实,没有可以依靠的人,那就自己拼命地努力。

 

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

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

相关文章

2023 华为 Datacom-HCIE 真题题库 07--含解析

多项选择题 1.[试题编号&#xff1a;190187] &#xff08;多选题&#xff09;如图所示的拓扑采用了VXLAN分布式网关&#xff0c;SW1上的VBDIF10配置了&#xff1a;arp-proxy local enable命令&#xff0c;则以下描述中正确的有哪些项&#xff1f; A、SW1收到PC1发往PC2的报文&…

【搭建私人图床】使用LightPicture开源搭建图片管理系统并远程访问

文章目录 1.前言2. Lightpicture网站搭建2.1. Lightpicture下载和安装2.2. Lightpicture网页测试2.3.cpolar的安装和注册 3.本地网页发布3.1.Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 现在的手机越来越先进&#xff0c;功能也越来越多&#xff0c;而手机…

C#,码海拾贝(22)——“全选主元高斯-约当消去法“求解“线性方程组“的C#源代码,《C#数值计算算法编程》源代码升级改进版

using System; namespace Zhou.CSharp.Algorithm { /// <summary> /// 求解线性方程组的类 LEquations /// 原作 周长发 /// 改编 深度混淆 /// </summary> public static partial class LEquations { /// <summary> …

天天被开发怼?4个方法区分bug前后端归属,我再也不背锅了!

“开发都这么不友善吗&#xff1f;” 有朋友跟我说&#xff0c;刚上岗经常分不清bug是前端还是后端&#xff0c;一直需要开发帮忙重新指派&#xff0c;甚至还会被开发拿来吐槽.... 其实不是开发态度不好&#xff0c;而是对于前后端分离的应用&#xff0c;既需要进行功能测试&am…

什么是网络安全?如何让普通人简单的了解网络安全

一、介绍网络安全 可以介绍一下河南郑州的网络安全科技馆。网络安全科技馆设置个人安全、政企安全、社会安全、综合竞技四个主展区&#xff0c;帮大家普及网络安全知识。首先&#xff0c;可以从个人安全展区开始游览&#xff0c;了解我们身边的网络安全&#xff0c;原来网络安…

调幅波解调-二极管峰值包络检波器【Multisim】【高频电子线路】

目录 一、实验目的与要求 二、实验仪器 三、实验内容与测试结果 1.观测输入、输出波形&#xff0c;估算检波效率&#xff08;D1接法不同&#xff0c;分别观测&#xff09; 2.观察惰性失真波形(C1100nF&#xff0c;其他参数保持不变) 3.观测负峰切割失真(ma0.8&#xff0c…

【目标检测实验系列】AutoDL线上GPU服务器租用流程以及如何用Pycharm软件远程连接服务器进行模型训练 (以Pycharm远程训练Yolov5项目为例子 超详细)

目录 1. 文章主要内容2. 租用AutoDL服务器详细教程2.1 注册AutoDL账号&#xff0c;并申请学生认证(学生认证有优惠&#xff0c;如果不是学生可以忽略此点)2.2 算力市场选择GPU&#xff0c;并选择初始化配置环境2.3 控制台参数解析&#xff0c;并使用相关参数登录Xftp(Windows与…

Spring Boot如何实现OAuth2授权?

Spring Boot如何实现OAuth2授权&#xff1f; OAuth2是一种授权框架&#xff0c;用于授权第三方应用程序访问受保护的资源。在Web应用程序中&#xff0c;OAuth2通常用于授权用户访问受保护的API。 在本文中&#xff0c;我们将介绍如何使用Spring Boot实现OAuth2授权。我们将使…

5-python的Number类型

内容提要 主要介绍python中的Number类型&#xff1a; python的类型转换&#xff0c;oct()、hex()、bin()函数的使用。 python的整数表示&#xff1a;十进制、二进制、八进制、十六进制。&#xff08;*&#xff0c;0b&#xff0c;0o&#xff0c;0x&#xff09; python中ASCII码…

springboot+java+ssm教材管理系统87k61

教材管理系统&#xff0c;主要的模块包括查看主页、个人中心、教师管理、学生管理、教材分类管理、教材信息管理、个体预订管理、取消预订管理、集体预订管理、集体取消管理、系统管理等功能。系统中管理员主要是为了安全有效地存储和管理各类信息&#xff0c;还可以对系统进行…

开发微信公众号本地调试【内网穿透】

文章目录 前言1. 配置本地服务器2. 内网穿透2.1 下载安装cpolar内网穿透2.2 创建隧道 3. 测试公网访问4. 固定域名4.1 保留一个二级子域名4.2 配置二级子域名 5. 使用固定二级子域名进行微信开发 转载自cpolar内网穿透的文章&#xff1a;微信公众号开发&#xff1a;对接本地开发…

【QT】windows下OpenSSL的使用

设计需求 在QT端实现对字符串的加密与解密 OpenSSL下载教程 本人采用 Win64OpenSSL-1_1_1t.msi&#xff0c;百度网盘下载链接 链接&#xff1a;https://pan.baidu.com/s/1vg4s_1JmCpa68TMc1F2gMw 提取码&#xff1a;u4js OpenSSL安装参考链接 OpenSSL使用的参考链接 OpenSS使用…

onceperrequestfilter 和 webmvcconfigurer 区别

概述 在使用Spring框架进行Web开发的时候,我们经常会遇到需要对每个请求做一些统一的处理的情况。例如,我们可能需要在每个请求到达Controller之前进行身份验证,或者在每个请求结束后记录请求的日志信息。这时候,我们可以使用两种不同的方式来实现这些功能:onceperreques…

一款免费无广、简单易用的安全软件:火绒安全软件

名人说&#xff1a;往者不可谏&#xff0c;来者犹可追。——语出《论语微子篇》 Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; o(‐&#xff3e;▽&#xff3e;‐)o很高兴你打开了这篇博客&#xff0c;跟着步骤一步步尝试安装吧。✧ 目录…

Linux-基础篇:虚拟机环境搭建

目录 1、linux介绍 2、安装vm和centos 2.1、vmware下载 2.2、Centos 下载地址 3、虚拟机三种网络连接方式 3.1、桥接模式 3.2、NAT模式 3.3、主机模式 4、虚拟机克隆 5、虚拟机快照 6、虚拟机迁移和删除 7、安装vmtools 7.1、vmtools作用 7.2、安装vmtools步骤 …

django+vue+python 协同用过滤电商推荐系统w58n0

现在人们足不出户就可以购物&#xff0c;聊天&#xff0c;消费&#xff0c;我们的生活越来越智能&#xff0c;越来越人性化&#xff0c;随之而来的就是让它更懂你&#xff0c;给你推荐你可能喜欢的东西&#xff0c;这样你就不必再费力去找你喜欢的东西&#xff0c;既节约了你的…

博客系统前端页面代码实现及页面展示(代码版)

hi,大家好,今天为大家带来博客系统的前端代码及页面展示 我们使用VS code 这个编码工具来编写代码 博客系统前端页面分为四个部分 1.博客列表页 2.博客编辑页 3.博客登录页 4.博客详情页 &#x1f367;1.博客列表页 <!DOCTYPE html> <html lang"en"&…

关于linux的ssh(出现的问题以及ubuntu的ssh配置)

目录 Ubuntu进行ssh连接 关于ssh报错排错 备注&#xff1a;防火墙和selinux可能对ssh连接存在限制&#xff0c;但是我在操作的时候并没对我照成影响 查看selinux状态 ssh_config和sshd_config的区别 Ubuntu进行ssh连接 1.首先需要安装SSH服务器&#xff0c;在ubuntu终端输…

强化学习与ChatGPT:快速让AI学会玩贪食蛇游戏!

大家好&#xff0c;我是千寻哥&#xff0c;现在自动驾驶很火热&#xff0c;其实自动驾驶是一个很大的概念&#xff0c;主要涉及的领域包括强化学习以及计算机视觉。 今天给各位讲讲强化学习的入门知识&#xff0c;并且手把手和大家一起做一个强化学习的Demo。 一、 浅谈强化学习…

基于SSM的酒店客房管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 酒店管理系统是一款高…