【数据结构之二叉树的构建和遍历】

news2024/12/25 9:30:02

数据结构学习笔记---009

  • 数据结构之二叉树
    • 1、二叉树的概念和结构
      • 1.1、回顾二叉树的重要性质
      • 1.2、回顾二叉树的主要分类
      • 1.1、如何实现二叉树?
    • 2、二叉树的实现
      • 2.1、二叉树的BinaryTree.h
      • 2.2、二叉树的BinaryTree.c
        • 2.2.1、二叉树的构建
        • 2.2.2、二叉树销毁
        • 2.2.3、二叉树前序、中序、后序遍历操作
        • 2.2.4、二叉树取结点个数操作
        • 2.2.5、二叉树取叶子结点个数操作
        • 2.2.6、取二叉树的高度/深度操作
        • 2.2.7、二叉树取第k层结点个数操作
        • 2.2.8、二叉树取查找值为x的节点操作
        • 2.2.9、二叉树层序遍历操作
        • 2.2.10、二叉树判断是否为完全二叉树操作
        • 2.2.11、二叉树的判空
      • 2.3、二叉树的main.c
    • 3、二叉树OJ巩固练习
      • 3.1、练习题1:二叉树的深度
      • 3.2、练习题2:单值二叉树
      • 3.3、练习题3:相同的树
      • 3.4、练习题4:二叉树的前序遍历 存入数组
      • 3.5、练习题5:对称二叉树
      • 3.6、练习题6:另一棵树的子树
      • 3.7、练习题7:计算左叶子节点个数

数据结构之二叉树

前言:
前篇学习了 数据结构之树和二叉树的基本概念知识,那么这篇继续完善二叉树的相关知识并完成实现二叉树的构建和遍历的内容。

/知识点汇总/

1、二叉树的概念和结构

因为前篇已经非常详细的单独学习了数和二叉树的基本知识概念,那么这里就简单回顾一下即可。
概念
二叉树(Binary Tree)是树形结构的一个重要类型。每个节点最多只能有两棵子树,且有左右之分。
它的定义可以概括为:一个n个有限元素的集合,该集合或者为空、或者由一个称为根的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。
形象一点就是:

(1)空二叉树——(a);
(2)只有一个根结点的二叉树——(b);
(3)只有左子树——©;
(4)只有右子树——(d);
(5)完全二叉树——(e)

1.1、回顾二叉树的重要性质

1.二叉树第i层上的结点数目最多为2^(i-1) (i≥1)。
2.深度为k的二叉树至多有2^k-1个结点(k≥1)。
3.包含n个结点的二叉树的高度至少为log2(n+1)。
4.在任意一棵二叉树中,若终端结点的个数为n0,度为2的结点数为n2,则n0=n2+1。
5.如果有一颗n个结点的完全二叉树(其深度为⌊log2n⌋+1)的结点按层序编号(从第一层到最后一层,每层从左到右),对任一结点i(1≤i≤n):
1)如果i=1,则结点i是二叉树的根,无双亲;如果i>1,则其双亲是结点⌊i/2⌋。
2)如果2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子LCHILD(i)是结点2i。
3)如果2i+1>n,则结点i无右孩子,否则其右孩子RCHILD(i)是结点2i+1。

1.2、回顾二叉树的主要分类

1.满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,那么这棵二叉树就被称为满二叉树。
2.完全二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。每个结点最多有两个子树,因此不存在度大于2的结点。左子树和右子树是有顺序的,次序不能任意颠倒。
3.二叉搜索树(二叉排序树):可以为空树,或者是具备如下性质:若它的左子树不空,则左子树上的所有结点的值均小于根节点的值;若它的右子树不空,则右子树上的所有结点的值均大于根节点的值,左右子树分别为二叉排序树。
4.平衡二叉树:这是一种概念,是二叉查找树的一个进化体,它有几种实现方式:红黑树、AVL树。平衡二叉树的特点是任意节点的子树的高度差都小于等于1。

1.1、如何实现二叉树?

二叉树的存储结构分类
1.二叉树的数组存储结构
一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费等问题。
并且实际应用中,也只有堆会用数组的形式存储。因为堆满足完全二叉树

typedef int HPDataType;
typedef struct Heap
{
	HPDataType* a;
	int size;
	int capacity;
}HP;

2、二叉树的链式存储结构
常用链表来指示元素的逻辑关系。
通常,以链表中的每一个结点,三个域组成,分别是数据域、左指针域和右指针域,左指针指向左孩子,右指针指向右孩子。
链式结构也分为二叉链和三叉链,一般是二叉链。高阶数据结构涉及三叉链。

typedef int BTDataType;
typedef struct BinaryTreeNode
{
	BTDataType data;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}TreeNode;

2、二叉树的实现

2.1、二叉树的BinaryTree.h

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <math.h>

typedef char BTDataType;

typedef struct BinaryTreeNode
{
	BTDataType Val;
	struct BinaryTreeNode* left;
	struct BinaryTreeNode* right;
}BTNode;

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi);

// 二叉树销毁
void BinaryTreeDestory(BTNode** root);

// 二叉树节点个数
int BinaryTreeSize(BTNode* root);

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root);

// 二叉树的高度/深度
int BinaryTreeHeight(BTNode* root);

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k);

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x);

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root);

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root);

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root);


//创建队列结构体成员与变量
typedef struct BinaryTreeNode* QDatetype;//注意这里的返回类型和参数与二叉树的接口类型要对应

typedef struct QueueNode
{
	QDatetype val;
	struct QueueNode* next;
}QNode;

typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;

//队列初始化
void QueueInit(Queue* pq);

//队列销毁
void QueueDestory(Queue* pq);

//元素入队
void QueuePush(Queue* pq, QDatetype x);

//元素出队
void QueuePop(Queue* pq);

//获取队头元素
QDatetype QueueFront(Queue* pq);

//获取队尾元素
QDatetype QueueBack(Queue* pq);

//获取队列元素个数或队列大小
int QueueSize(Queue* pq);

//队列判断空
bool QueueEmpty(Queue* pq);

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);

//写法2:
//int BinaryTreeComplete2(BTNode* root);

2.2、二叉树的BinaryTree.c

2.2.1、二叉树的构建
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{
	assert(a);
	if (a[*pi] == '#' || *pi >= n)
	{
		++(*pi);
		return NULL;
	}
	BTNode* root = (BTNode*)malloc(sizeof(BTNode));
	if (root == NULL)
	{
		perror("malloc fail");
		exit(-1);
	}
	root->Val = a[*pi];
	++(*pi);
	root->left = BinaryTreeCreate(a, n, pi);
	root->right = BinaryTreeCreate(a, n, pi);
	return root;
}
2.2.2、二叉树销毁
// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	if (*root == NULL)
	{
		return;
	}
	BinaryTreeDestory(&(*root)->left);
	BinaryTreeDestory(&(*root)->right);
	free(*root);
	*root = NULL;
}
2.2.3、二叉树前序、中序、后序遍历操作
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("# ");
		return;
	}
	printf("%c ", root->Val);
	BinaryTreePrevOrder(root->left);
	BinaryTreePrevOrder(root->right);
}

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("# ");
		return;
	}
	BinaryTreeInOrder(root->left);
	printf("%c ", root->Val);
	BinaryTreeInOrder(root->right);
}

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		//printf("# ");
		return;
	}
	BinaryTreePostOrder(root->left);
	BinaryTreePostOrder(root->right);
	printf("%c ", root->Val);
}

2.2.4、二叉树取结点个数操作
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}
2.2.5、二叉树取叶子结点个数操作
// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	//为空返回0,不能assert,否则递归走不动
	if (root == NULL)
	{
		return 0;
	}
	//只有根节点或叶子节点,则返回1
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	//其余情况的叶子节点=左子树叶子节点+右子树叶子节点
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}
2.2.6、取二叉树的高度/深度操作
int BinaryTreeHeight(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return fmax(BinaryTreeHeight(root->left), BinaryTreeHeight(root->right)) + 1;
}
2.2.7、二叉树取第k层结点个数操作
// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	//为空
	if (root == NULL)
		return 0;
	//根节点
	if (k == 1)
		return 1;
	//其余层,递归k-1
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}
2.2.8、二叉树取查找值为x的节点操作
// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	//参数为空
	if (root == NULL)
	{
		return NULL;
	}
	//根节点匹配,则返回空节点
	if (root->Val == x)
	{
		return root;
	}
	//遍历左右子树,找匹配值
	BTNode* ret1 = BinaryTreeFind(root->left, x);
	if (ret1)
	{
		return ret1;
	}
	BTNode* ret2 = BinaryTreeFind(root->right, x);
	if (ret2)
	{
		return ret2;
	}
	//遍历结束都没有匹配,则返回空
	return NULL;
}
2.2.9、二叉树层序遍历操作
//队列初始化
void QueueInit(Queue* pq)
{
	assert(pq);
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

//队列销毁
void QueueDestory(Queue* pq)
{
	assert(pq);
	//工作指针,遍历销毁
	QNode* cur = pq->phead;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	pq->phead = NULL;
	pq->ptail = NULL;
	pq->size = 0;
}

//元素入队
void QueuePush(Queue* pq, QDatetype x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->next = NULL;
	newnode->val = x;
	//空队列的处理
	if (pq->ptail == NULL)
	{
		pq->phead = pq->ptail = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		//尾指针后移
		pq->ptail = newnode;
	}
	pq->size++;
}

//元素出队
void QueuePop(Queue* pq)
{
	assert(pq);
	//判空,空队列不能出队
	assert(pq->phead);
	//兼容只有一个节点的情况
	//delfront保存当前头指针地址,以便free掉,并防止内存泄漏
	QNode* delfront = pq->phead;
	//首元素出队,头指针直接后移即可
	pq->phead = pq->phead->next;
	free(delfront);
	delfront = NULL;
	//只有一个节点时,出队后,为空,那么尾指针也得置空
	if (pq->phead == NULL)
	{
		pq->ptail = NULL;
	}
	pq->size--;
}

//获取队头元素
QDatetype QueueFront(Queue* pq)
{
	assert(pq);
	//判空,为空没有元素取
	assert(pq->phead);
	return pq->phead->val;
}

//获取队尾元素
QDatetype QueueBack(Queue* pq)
{
	assert(pq);
	//判空,为空没有元素取
	assert(pq->phead);
	return pq->ptail->val;
}

//获取队列元素个数或队列大小
int QueueSize(Queue* pq)
{
	assert(pq);
	return pq->size;
}

//队列判断空
bool QueueEmpty(Queue* pq)
{
	assert(pq);
	return pq->phead == NULL;
}

// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	assert(root);
	//创建队列
	Queue q;
	QueueInit(&q);
	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		printf("%c ", front->Val);
		if (front->left)
		{
			QueuePush(&q, front->left);
		}
		if (front->right)
		{
			QueuePush(&q, front->right);
		}
		QueuePop(&q);
	}
	printf("\n");
	QueueDestory(&q);
}

2.2.10、二叉树判断是否为完全二叉树操作

判断完全二叉树的思路1;
1.如果树为空,直接返回错误;
2.如果树非空,层序遍历二叉树;
3.如果一个结点左右孩子均Not NULL时,则pop该结点,将其左右孩子入队列;
4.如果遇到一个结点,左孩子为空,而右孩子非空,则一定不为完全二叉树;
5.如果遇到一个结点,左孩子不为空,而右孩子为空;或者是左右孩子均为空,则结点之后的队列的结点都为叶子结点;
满足以上条件则为完全二叉树,否则不是完全二叉树。
核心思想:类似于层序一层层的节点构造而成,即最后一层的节点上面的层节点都是满的。前提是最后一层不是根节点,即第一层.
所以遍历不连续就不是完全二叉树,并且队列比栈适用于判断的重要原因之一就是,第一个NULL出队列时,所有的非空节点一定会进队列。

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	assert(root);
	Queue q;
	QueueInit(&q);
	if (root)
	{
		QueuePush(&q, root);
	}
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		//遇见空就结束
		if (front == NULL)
		{
			break;
		}
		QueuePush(&q, front->left);
		QueuePush(&q, front->right);
	}
	//因为出到空,退出循环后,再写一个循环判断队列里是否还有非空
	//若有非空,则false,若没有非空或不进入循环,则true
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		//遇见空就结束
		if (front)
		{
			QueueDestory(&q);
			return false;
		}
	}
	QueueDestory(&q);
	return true;
}

2.2.11、二叉树的判空
//二叉树判空
bool BinaryTreeEmpty(BTNode* root)
{
	return root == NULL;
}

2.3、二叉树的main.c

#include "BinaryTree.h"

int main()
{
	char str[] = "ABC##DE#G##F###";// ABC##DE#G##F###
	//char str2[] = "ABCDEGF";
	int len = strlen(str);
	int NodeNum = 0;
	BTNode* tree = BinaryTreeCreate(str, len, &NodeNum);

	printf("前序遍历:");
	// 二叉树前序遍历 
	BinaryTreePrevOrder(tree);
	printf("\n");

	printf("中序遍历:");
	// 二叉树中序遍历
	BinaryTreeInOrder(tree);
	printf("\n");

	printf("后序遍历:");
	// 二叉树后序遍历
	BinaryTreePostOrder(tree);
	printf("\n");

	// 二叉树节点个数
	printf("节点个数:%d\n", BinaryTreeSize(tree));

	printf("层序遍历:");
	// 层序遍历
	BinaryTreeLevelOrder(tree);
	printf("\n");

	//二叉树判空
	if (BinaryTreeEmpty(tree))
	{
		printf("空树\n");
	}
	else
	{
		printf("非空树\n");
	}

	// 判断二叉树是否是完全二叉树
	if (BinaryTreeComplete(tree))
	{
		printf("是完全二叉树\n");
	}
	else
	{
		printf("非完全二叉树\n");
	}

	// 二叉树叶子节点个数
	printf("叶子节点:%d\n", BinaryTreeLeafSize(tree));

    //计算二叉树的高度
	printf("二叉树的高度:%d\n", BinaryTreeHeight(tree));

	// 二叉树第k层节点个数
	printf("第k层叶子节点:%d\n", BinaryTreeLevelKSize(tree, 3));

	// 二叉树查找值为x的节点
	printf("第k层叶子节点:%c\n", BinaryTreeFind(tree, 'E')->Val);

	// 二叉树销毁
	BinaryTreeDestory(&tree);
	return 0;
}

运行结果,如图所示
在这里插入图片描述

3、二叉树OJ巩固练习

3.1、练习题1:二叉树的深度

核心思想就是取左右子树叶子节点的高度,将比较大的值+根节点的第一层即可。因为计算是以0计算所以需要把第一层加回来。或者+1也可以理解为(考虑只有根节点),加自己本身这层,就像数数需要加上自己。
方法1:fmax调用库函数更方便,fmax用于比较出较大值并返回较大值。头文件:<math.h>
方法2:通过变量保存,递归的值,最后比较大小之后加回第一层。

//方法1:fmax函数
/**/
int calculateDepth(struct TreeNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	return fmax(calculateDepth(root->left), calculateDepth(root->right)) + 1;
}


//方法2:保存变量
/**/
int calculateDepth(struct TreeNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	int left = calculateDepth(root->left);
	int right = calculateDepth(root->right);
	return left > right ? left + 1 : right + 1;
}

3.2、练习题2:单值二叉树

单值二叉树(每个节点都具有相同的值) — 给定的二叉树是单值二叉树就返回true,否则就返回false
思路:排除法和分治法,检查每个节点和他的孩子的值是否匹配。

bool isUnivaTree(struct TreeNode* root)
{
	if (root == NULL)
	{
		return true;
	}
	//排除法,排除左孩子值与其父节点值不等
	if (root->left && root->lefd->val != root->val)
	{
		return false;
	}
	//排除法,排除右孩子值与其父节点值不等
	if (root->right && root->right->val != root->val)
	{
		return false;
	}
	//执行递归,返回结果,若是不满足上述排除的情况,说明满足单值二叉树
	return isUnivaTree(root->left) && isUnivaTree(root->right);
}

3.3、练习题3:相同的树

相同的树 — 给你两棵二叉树的根节点p和q,编写一个函数来检验这两棵树是否相同(如果这两棵树的结构和节点值相同,则认为是相同的)
思路:排除法和分治法,自己比,左子树比,右子树比

bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
	//都为空
	if (p == NULL && q == NULL)
		return true;
	//其中一个为空
	if (p == NULL || q == NULL)
		return false;
	//都不为空且不相等
	if (p->val != q->val)
		return false;
	//递归遍历完,都不满足上述排除的情况,则满足相同的树。
	return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}

3.4、练习题4:二叉树的前序遍历 存入数组

这道题的关键在于获取结点个数开辟数组,并涉及前序遍历的参数设计细节问题。
方法1:递归法
方法2:全局变量法(不推荐)
方法3:指针法

int TreeSize(struct TreeNode* root)
{
	return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}

void preorder(struct TreeNode* root, int* a, int i)
{
	if (root == NULL)
		return;
	a[i++] = root->val;
	preorder(root->left,a,i);
	preorder(root->right,a,i);
}
//全局变量法
//int i = 0;
//void preorder(struct TreeNode* root, int* a)
//{
//	if (root == NULL)
//		return;
//	a[i++] = root->val;
//	preorder(root->left, a);
//	preorder(root->right, a);
//}

//指针法
void preorder(struct TreeNode* root, int* a, int* pi)
{
	if (root == NULL)
		return;
	a[(*pi)++] = root->val;
	preorder(root->left, a, pi);
	preorder(root->right, a, pi);
}

int* preorderTraversal(struct TreeNode* root, int* returnSize)
{
	int n = TreeSize(root);
	int* a = (int*)malloc(sizeof(int) * n);
	*returnSize = n;
	
    //方法1:递归法
	preorder(root, a, 0);
    
    //方法2:全局变量法(不推荐)
	//i= 0; --- 必须置0
	//preorder(root, a); -- 全局变量法,但尽量不用
    
    //方法3:指针法
	//int i = 0;
	//preorder(root, a, &i);
	return a;
}

3.5、练习题5:对称二叉树

对称(镜像)二叉树 — 给你一个二叉树的根结点root,检查它是否轴对称。
思路:设计一个复用函数,继续利用排除法和递归遍历,排除不成立的结果,能成功返回的对称二叉树。

bool _isSymmetric(struct TreeNode* root1, struct TreeNode* root2)
{
	if (root1 == NULL && root2 == NULL)
	{
		return true;
	}
	//一个为空,另一个不为空
	if (root1 == NULL || root2 == NULL)
	{
		return false;
	}
	//都不为空
	if (root1->val != root2->val)
	{
		return false;
	}
	return _isSymmetric(root1->left, root2->right) && _isSymmetric(root1->right, root2->left);
}
bool isSymmetric(struct TreeNode* root)
{
	return _isSymmetric(root->left, root->right);
}

3.6、练习题6:另一棵树的子树

另一棵树的子树:给两颗二叉树,检验一棵树是否包含另一棵树的子树。
思路:结合上面相同的树的方法,去匹配子树

//相同的树
bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
	//都为空
	if (p == NULL && q == NULL)
		return true;
	//其中一个为空
	if (p == NULL || q == NULL)
		return false;
	//都不为空且不相等
	if (p->val != q->val)
		return false;
	return isSameTree(p->left, q->left) && isSameTree(p->right, q->right);
}
//另一棵树的子树
bool isSubtree(struct TreeNode* root, struct TreeNode* subRoot)
{
    //为空没有子树,匹配失败
	if (root == NULL)
		return false;
	//根节点匹配,调用相同的树方法,去匹配
	if (root->val == subRoot->val)
		return isSameTree(root, subRoot);
	//递归前序遍历匹配
	return isSameTree(root, subRoot) || 
	isSameTree(root->left, subRoot) || 
	isSameTree(root->right, subRoot);
}

3.7、练习题7:计算左叶子节点个数

计算二叉树中左叶子节点的个数。
思路:递归遍历左右子树,累计左叶子节点个数即可。
1.判断是否为空
2.判断是否为左叶子节点
3.递归累加。

// 二叉树左叶子节点个数
int BinaryTreeLeftLeafSize(BTNode* root)
{
	//为空返回0
	if (root == NULL)
	{
		return 0;
	}
	//判断有左孩子,并是左叶子节点
	if (root->left && root->left->left == NULL && root->left->right == NULL)
	{
		return 1;
	}
	//其余情况的左叶子节点=左子树叶子节点+右子树叶子节点
	return BinaryTreeLeftLeafSize(root->left) + BinaryTreeLeftLeafSize(root->right);
}

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

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

相关文章

RabbitMQ入门概念

目录 一、RabbitMQ入门 1.1 rabbitmq是啥&#xff1f; 1.2 应用场景 1.3 AMQP协议与RabbitMQ工作流程 1.4 Docker安装部署RabbitMQ 二、SpringBoot连接MQ配置 2.1 示例1 2.1 示例2 —— 发送实体 一、RabbitMQ入门 1.1 rabbitmq是啥&#xff1f; MQ&#xff08;Message…

Hutool导入导出用法

整理了下Hutool导入导出的简单使用。 导入maven或jar包&#xff08;注意这里导入的poi只是为了优化样式&#xff09; <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all --> <dependency><groupId>cn.hutool</groupId><artifactId&g…

Kube-Promethus配置Nacos监控

Kube-Promethus配置Nacos监控 前置&#xff1a;Kube-Promethus安装监控k8s集群 一.判断Nacos开启监控配置 首先通过集群内部任一节点访问Nacos的这个地址<NacosIP>:端口号/nacos/actuator/prometheus&#xff0c;查看是否能够获取监控数据。 如果没有数据则修改Nacos集群…

qt中使用mysql 数据库

QT 版本介绍 虽然版本是这个&#xff0c;但是工作目录确是&#xff1a; 下面陈述安装步骤 第一步&#xff1a; 就是安装MYSQL 数据库&#xff0c;在此不再赘述了&#xff0c;很多博主已经上传了。 第二步&#xff1a; 就是拷贝QT 对应mysql 的版本驱动到 QT 的编译器文件中…

基于人工智能的质量保证(QA)流程

AI模型质量保证需知 推出准确、可靠、公正的人工智能&#xff08;AI&#xff09;模型无疑是一项挑战。设法成功实施AI计划的企业很可能意识到&#xff0c;AI质量保证&#xff08;QA&#xff09;流程与传统QA流程迥然不同。 质量保证对于AI模型的准确性至关重要&#xff0c;不…

SD卡写保护无法格式化怎么办?

一般来说&#xff0c;写保护&#xff08;也称为只读&#xff09;是数据存储设备防止写入新数据或修改旧信息的能力。换句话说&#xff0c;您可以读取存储在磁盘上的信息&#xff0c;但是却不能删除、更改或复制它们&#xff0c;因为访问会被拒绝。那么SD卡有写保护怎么格式化呢…

【图像拼接 精读】Parallax-Tolerant Unsupervised Deep Image Stitching

【精读】Parallax-Tolerant Unsupervised Deep Image Stitching 在这篇论文中&#xff0c;"warp"&#xff08;变形&#xff09;和"composition"&#xff08;组合&#xff09;是两个关键的概念。"Warp"指的是图像变形的过程&#xff0c;用于调整…

【乳腺肿瘤诊断分类及预测】基于LVQNN学习向量量化神经网络

课题名称&#xff1a;基于LVQ神经网络的乳腺肿瘤诊断&#xff08;类型分类&#xff09; 版本日期&#xff1a;2023-03-10 运行方式: 直接运行0501_LVQ0501.m 文件即可 代码获取方式&#xff1a;私信博主或QQ&#xff1a;491052175 模型描述&#xff1a; 威斯康辛大学医学院…

NetCore实现输入用户名和密码后访问Swagger页面

1 原理说明 在后端编程时&#xff0c;通常使用swagger文档来呈现接口文档。为了接口的安全性&#xff0c;可通过输入用户名和密码的方式来进行验证。 这里用到了Basic认证方式。原理图如下&#xff1a; 步骤 1&#xff1a; 当请求的资源需要 B A S I C \textcolor{red}{BA…

力扣238. 除自身以外数组的乘积(前后缀和)

Problem: 238. 除自身以外数组的乘积 文章目录 题目描述思路复杂度Code 题目描述 思路 思路1&#xff1a; 1.先求取数组的包括当前下标值得前后缀乘积&#xff08;利用两个数组记录下来分别为leftProduct和rightProduct&#xff09; 2.当求取一个下标为i的数组中的元素&#x…

正则表达式补充以及sed

正则表达式&#xff1a; 下划线算 在单词里面 解释一下过程&#xff1a; 在第二行hello world当中&#xff0c;hello中的h 与后面第一个h相匹配&#xff0c;所以hello中的ello可以和abcde匹配 在world中&#xff0c;w先匹配h匹配不上&#xff0c;则在看0&#xff0c;r&#…

【Java 数据结构】LinkedList与链表

LinkedList与链表 1. ArrayList的缺陷2. 链表2.1 链表的概念及结构2.2 链表的实现 3. LinkedList的模拟实现4.LinkedList的使用4.1 什么是LinkedList4.2LinkedList的使用 5. ArrayList和LinkedList的区别 1. ArrayList的缺陷 上节课已经熟悉了ArrayList的使用&#xff0c;并且…

多头 eRCD(Multi-Headed eRCD)

&#x1f525;点击查看精选 CXL 系列文章&#x1f525; &#x1f525;点击进入【芯片设计验证】社区&#xff0c;查看更多精彩内容&#x1f525; &#x1f4e2; 声明&#xff1a; &#x1f96d; 作者主页&#xff1a;【MangoPapa的CSDN主页】。⚠️ 本文首发于CSDN&#xff0c…

在哪里申请SSL证书

其实只是单纯的申请SSL证书来说&#xff0c;渠道还是比较多的。只是需要格外注意在申请SSL证书的过程中&#xff0c;对于自身需求的认知。 首先最重要的是&#xff0c;该证书是否可信。就目前而言&#xff0c;非可信根的证书是无法与主流浏览器兼容的&#xff0c;会时常发生风险…

503 Service Temporarily Unavailable nginx 原因和解决办法

前言 HTTP 503 Service Temporarily Unavailable 错误通常表示服务器无法处理请求&#xff0c;可能是由于服务器过载、维护或其他临时性问题导致的。在 Nginx 中&#xff0c;这种错误通常与后端服务的可用性问题相关。以下是可能的原因和解决办法&#xff1a; 正文…

RTC实时时钟之读取时间

1. RTC 基本介绍 RTC(Real Time Clock) 即实时时钟&#xff0c;它是一个可以为系统提供精确的时间基准的元器件&#xff0c;RTC一般采用精度较高的晶振作为时钟源&#xff0c;有些RTC为了在主电源掉电时还可以工作&#xff0c;需要外加电池供电 2. RTC 控制器 2.1 RTC的特点是:…

VxTerm:SSH工具中的中文显示和乱码时的相关信息和一些基本的知识

当我们写的程序含有控制台(Console)输出时&#xff0c;如果输入内容包含中文时&#xff0c;我们一般需要知道下面的信息&#xff0c;才能正确的搞清楚怎么处理中文显示的问题&#xff1a; 1、实际程序或文件中的实际编码&#xff1a; Linux下的应用程序和文本文件&#xff0c;…

mkcert的安装和使用,5分学会在本地开启localhost的https访问方式

mkcert官方仓库地址&#xff1a;https://github.com/FiloSottile/mkcert#installation mkcert 是一个简单的工具&#xff0c;用于制作本地信任的开发证书。它不需要配置。 简化我们在本地搭建 https 环境的复杂性&#xff0c;无需操作繁杂的 openssl 实现自签证书了&#xff…

【开源操作系统】上海道宁为您带来稳定、安全、开源和易用的操作系统——Ubuntu,为您的数字化生活保驾护航

Ubuntu是 源于非洲的一种传统价值观 意为“人性、关爱和共享” 这种价值观在 开源、稳定、安全、易用的 Ubuntu操作系统中 得到了完美的体现 除此之外&#xff0c;Ubuntu还具有 强大的安全性 它自带了诸多安全功能 如防火墙、加密文件系统等 可以有效地保护用户的隐私…

CRF条件随机场学习记录

阅读建议 仔细阅读书[1]对应的序列标注章节&#xff0c;理解该方法面向的问题以及相关背景&#xff0c;然后理解基础的概念。 引言 威胁情报挖掘的相关论文中&#xff0c;均涉及到两部分任务&#xff1a;命名实体识别&#xff08;Named Entity Recognition&#xff0c;NER&a…