C语言最终文章-二叉树

文章目录

  • 前言
  • 二叉树的性质
  • 二叉树的存储方式
    • 顺序存储
      • 堆及其应用
      • TopK问题
      • 堆排序
    • 链式存储
      • 二叉树的练习
        • 1.二叉树查找值为x的节点
        • 2.判断是否为完全二叉树
        • LC226.翻转二叉树
        • [LC572. 另一棵树的子树](https://leetcode.cn/problems/subtree-of-another-tree/description/)
        • 两道选择题
  • 结言

前言

  • 这篇文章大概就是我C语言学习的最后一篇文章了。

本篇文章主要内容:

  • 二叉树的几个性质,堆、堆排序和用堆实现TopK问题。
  • 向上建堆和向下建堆
  • 二叉树的练习

二叉树原图:

在这里插入图片描述

二叉树的性质

开始讲二叉树时,我们先来学一下二叉树的重要性质。

1.对于任意二叉树: n 0 = n 2 + 1 n0 = n2+1 n0=n2+1 (其中 n0代表度为0的个数,n2代表度为2的节点个数)
2. N − 1 = n 0 ∗ 0 + n 1 ∗ 1 + n 2 ∗ 2 + . . . . N-1 =n0*0+n1*1+n2*2+.... N1=n00+n11+n22+.... (N-1代表边的个数)
3. 对于满二叉树来说,二叉树节点个数 = 2 h − 1 2^h-1 2h1 (h为二叉树的高度)

先来看第一条 n 0 = = n 2 + 1 ? n0 ==n2+1? n0==n2+1

来让我们想一想二叉树是如何构建的呢?

首先我们要明白一件事: 首先我们要明白一件事: 首先我们要明白一件事: 度为1的是有度为0的节点增加一个分支得来的,度为2的是由度为1的节点增加一个分支得来的。

一开始我们只有一个根节点,那么我们的 n 0 = 1 n0=1 n0=1,当我们增加一个度为1的

节点时,那么此时我们的 n 0 还是 = 0 , n 1 = 1 n0还是 = 0,n1=1 n0还是=0n1=1,当我们增加一个度为2的时候
n 0 − > 2 , n 1 − > 0 , n 2 − > 1 n0->2,n1->0,n2->1 n0>2n1>0n2>1

过程如下图:
在这里插入图片描述
那我们不难发现,我们的 n 0 = n 2 + 1 n0=n2+1 n0=n2+1 这个条件始终成立,只要我们增加一个度为2的节点,那么n0肯定会增加一个。

再来看第二条,对与一棵树而言,子数肯定也是一棵树,两个兄弟节点之间也
不会有连线。那么 N 个节点就可以形成 N-1 条边。而 n0 有有0条边,n1有1条边…,那么总的边数 N-1 就可以得出来第二条的公式。

第三条

- 对于一个满二叉树来说
在这里插入图片描述

  • 第一层节点个数: 2 0 2^0 20
  • 第二层节点个数: 2 1 2^1 21
  • 第三层节点个数: 2 2 2^2 22
  • 第四层节点个数: 2 3 2^3 23

那么如果一个h层的满二叉树它的节点总数 T(N) = 2 0 + 2 1 + 2 2 + . . . + 2 h − 1 2^0+2^1+2^2+...+2^{h-1} 20+21+22+...+2h1

所以 T ( N ) = 2 h − 1 T(N) = 2^{h}-1 T(N)=2h1

二叉树的存储方式

顺序存储

顺序存储本质上就是用数组存。这里我们理解一下完全二叉树和满二叉树

  • 满二叉树:各层的节点都是满的状态-就如上面那个图一样如上图
  • 完全二叉树:前 h-1层都是满的,第h层从右向左连续去掉节点。这就相当于,在最后一层它的节点必须是连续的。
    在这里插入图片描述
    理解完这两个概念之后,如果我们把这些二叉树的节点都放入数组中会怎么样呢? 如图:
    在这里插入图片描述
    当我们把树的节点都放入数组中后,我们发现双亲节点和它的左孩子和右孩子之间存在这么一个关系。
  • l c h i l d i = 2 ∗ p a r e n t i + 1 , r c h i l d i = 2 ∗ p a r e n t i + 2 lchild_i = 2*parent_i+1,rchild_i = 2*parent_i+2 lchildi=2parenti+1rchildi=2parenti+2
  • p a r e n t i = ( ( l , r ) c h i l d i − 1 ) / 2 parent_{i} = ((l,r)child_i-1)/2 parenti=((l,r)childi1)/2

注意: 这个规则只对完全二叉树和满二叉树使用,当然其他的二叉树我们也可以这么存储,只不过途中我们要把位置空出来,这样比较浪费空间,所以我们会使用下面的链式存储。

堆及其应用

当我们对顺序存储有了以上的了解后,我们就可以来实现堆了。注意这里的堆跟操作系统的堆可不一样,我们这里只是一个数据结构。

堆的操作:

  • 入堆
  • 出堆顶元素
  • 取堆顶元素
  • 判空

堆可以用来做什么呢?
比如:排出中国最有钱的前10个人,堆排序等等。

这里先介绍两个概念:

  • 大堆:堆顶元素比其他元素大
  • 小堆:堆顶元素比其他元素小

为什么要有这两个堆呢?

同时注意:大堆和小堆并不意味着有序。

如下图:大堆和小堆,只能说明堆顶元素,一定比其他元素大,由于二叉树左子树和右子树是两个子树。子树和树具有相同的性质

  • 对于大堆而言: 左子树也是大堆,右子树也是大堆,那么左子树的左子树也是大堆…
    在这里插入图片描述
    如果你要排升序的话,利用堆排大堆还是小堆呢呢?

如果排小堆,那么每次堆顶就是我们的最小元素,但是然后怎么排呢?这样剩
下的元素就不一定是小堆了。所以当我们排升序的时候我们排大堆,直接把堆顶元素与最后一个位置的元素交换,注意这时我们下面的子树并没有受影响,所以我们直接再排一次大堆就可以了。然后不断的排,数组就有序了。

下面我们都以建大堆为例:

先来说入堆

入堆的话,我们需要用到向上调整算法

算法演示如下:
在这里插入图片描述
当我们插入一个新元素后,不断地去找双亲节点判断大小,如果比双亲的值大

那么就交换,否则就不交换。

代码:

void ADjustUp(HpDataType* a, int n)
{
	int child = n - 1;
	int parent = (n - 1 - 1) / 2;
	while (parent >= 0)
	{
		if (a[child] > a[parent]) //大的往上调
		{
			swap(&a[parent], &a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}
void HpPush(Hp* hp, HpDataType x)
{
	assert(hp);
	check_capacity(hp); //检查容量
	hp->a[hp->size] = x;
	hp->size++;
	ADjustUp(hp->a,hp->size); // 开区间
}

出堆顶元素

这里我们就要用到 向下调整算法:,由于我们必须保证树是一个大堆,所以每次把堆顶元素Pop调后,要保证树还是一个大堆。

这里我们直接把堆顶 a[0] 与 最后一个元素交换。我们本质上还是数组。
然后再用一次向下调整算法即可。

向下调整算法过程如图:
在这里插入图片描述
代码:

void AdjustDown(HpDataType* a, int begin, int end)
{
	int parent = begin;
	int child = 2 * parent + 1;
	while (child < end)
	{
		if (child + 1 < end && a[child] > a[child + 1])
		{
			child += 1;
		}
		if (a[parent] > a[child])
		{
			swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
			break;
	}
}
//出堆
void HpPop(Hp* hp)
{
	assert(hp && hp->size > 0);
	swap(&hp->a[0],&hp->a[hp->size-1]);//此时这个位置就不能才排了
	hp->size--;
	AdjustDown(hp->a,0,hp->size); 

}

堆的总代码:

typedef int HpDataType;
typedef struct Heap
{
	HpDataType* a;
	int size;
	int capacity;
}Hp;

//初始化堆
void HpInit(Hp* hp);
//销毁堆
void HpDestory(Hp* hp);
//入堆
void HpPush(Hp* hp, HpDataType x);
//出堆
void HpPop(Hp* hp);
//判空
bool HpEmpty(Hp* hp);
//堆顶元素
HpDataType HpTop(Hp* hp);
//向下
void AdjustDown(HpDataType* a, int begin, int end);

void swap(HpDataType* e1, HpDataType* e2);

void swap(HpDataType* e1, HpDataType* e2)
{
	HpDataType tmp = *e1;
	*e1 = *e2;
	*e2 = tmp;
}

//初始化堆
void HpInit(Hp* hp)
{
	hp->size = 0;
	hp->capacity = 4;
	hp->a = (HpDataType*)malloc(sizeof(HpDataType) * (hp->capacity));
	if (hp->a == NULL)
	{
		perror("malloc fail!\n");
		exit(-1);
	}
}
//销毁堆
void HpDestory(Hp* hp)
{
	hp->size = hp->capacity = 0;
	free(hp->a);
}
void check_capacity(Hp* hp)
{
	if (hp->capacity == hp->size)
	{
		HpDataType* ptr = (HpDataType*)realloc(hp->a, sizeof(HpDataType) * (hp->capacity * 2));
		if (ptr == NULL)
		{
			printf("realloc fail!\n");
			exit(-1);
		}
		hp->capacity *= 2;
		hp->a = ptr;
	}
}

//排倒序 - 建大堆
void ADjustUp(HpDataType* a, int n)
{
	int child = n - 1;
	int parent = (n - 1 - 1) / 2;
	while (parent >= 0)
	{
		if (a[child] > a[parent]) //大的往上调
		{
			swap(&a[parent], &a[child]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else
			break;
	}
}
//入堆
void HpPush(Hp* hp, HpDataType x)
{
	assert(hp);
	check_capacity(hp);
	hp->a[hp->size] = x;
	hp->size++;
	ADjustUp(hp->a,hp->size); // 开区间
}
//堆顶元素
HpDataType HpTop(Hp* hp)
{
	assert(hp && hp->size > 0);
	return hp->a[0];
}
//建大堆
void AdjustDown(HpDataType* a, int begin, int end)
{
	int parent = begin;
	int child = 2 * parent + 1;
	while (child < end)
	{
		if (child + 1 < end && a[child] > a[child + 1])
		{
			child += 1;
		}
		if (a[parent] > a[child])
		{
			swap(&a[parent], &a[child]);
			parent = child;
			child = 2 * parent + 1;
		}
		else
			break;
	}
}
//出堆
void HpPop(Hp* hp)
{
	assert(hp && hp->size > 0);
	swap(&hp->a[0],&hp->a[hp->size-1]);//此时这个位置就不能才排了
	hp->size--;
	AdjustDown(hp->a,0,hp->size); 

}
//判空
bool HpEmpty(Hp* hp)
{
	return hp->size == 0;
}

TopK问题

现在有一个问题

  • 你只有1KB的空间,如何把在4G的文件(假设都是整数)中找出前K(K > 0)大的数字
    既然我们学的是堆,肯定使用堆来解决,如果没有空间限制的话,我们可以把数据都读到内存中,然后排K次大堆即可。可关键我们只有1KB(1024byte)的空间,那如何做呢?

在这里插入图片描述
排成小堆后,堆顶元素就是最小值,每次读入一个比堆顶大的数据,读到最后就是前K个最大的数据了。

代码实现:

#define N 100000 //这里以 10万个数据为例子。
//创建数据
void CreatData()
{
	FILE* fin = fopen("data.txt", "w");
	if (fin == NULL)
	{
		perror("fopen fail!\n");
		exit(-1);
	}
	int i = 0;
	srand(time(0));
	for (i = 0; i < N; i++)
	{
		int x = (rand() + i) % 10000;
		fprintf(fin,"%d\n", x);
	}

	fclose(fin);
}

//要求:只给你1KB空间,排出4G个整数的前K个最大值
void TopK()
{
	FILE* fout = fopen("data.txt","r");
	if (fout == NULL)
	{
		perror("fopen fail!\n");
		exit(-1);
	}
	int k;
	printf("请输入k>: ");
	scanf("%d", &k);
	int i = 0;
	int* KminArr = (int*)malloc(sizeof(int) * k);
	//读取K个数建最小堆
	for (i = 0; i < k; i++)
	{
		fscanf(fout,"%d",&KminArr[i]);
	}
	int x = 0;
	while (fscanf(fout, "%d", &x) > 0)
	{
		if (x > KminArr[0])
		{
			KminArr[0] = x;
			AdjustDown(KminArr,0,k);
		}
	}

	HeapSort(KminArr,k);
	//前k个最大值
	printf("前%d个最大值为:", k);
	for (i = 0; i < k; i++)
	{
		printf("%d ", KminArr[i]);
	}
	printf("\n");
}

堆排序

当我们了解了向上和向下两种算法的时候,我们就可以来实现啊堆排序了。

如果给你这样一个数组,如何排序呢?
在这里插入图片描述
思路:

建大堆,不断交换堆顶和数组最后一个位置的元素,然后再对剩下的数字进行向下调整算法。直到数组有序为止。

关键就是,我们如何去建大堆呢,前面我们讲堆的时候,那数组经过向上调整算法之后,本来就是一个大堆(ps:建大堆的前提就是源数据也是大堆)。那我们拿到一个随机的数组之后如何建大堆呢?

  • 以最后一个非叶子节点为开始,不断向下调整,直到达到堆顶,此时即为大堆。

在这里插入图片描述
建完大堆之后,不断交换堆顶和数组最后一个位置的元素,然后再对剩下的数字进行向下调整算法。

总代码:

void HeapSort(int* a, int n)
{
	int i = 0;
	for (i = (n - 1 - 1) / 2; i >= 0; i--)
	{
		AdjustDown(a,i,n);
	}

	int end = n - 1;
	while (end > 0)
	{
		swap(&a[end],&a[0]);
		AdjustDown(a,0,end);
		end--;
	}
}

void PrintArray(int* a, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%d ", a[i]);
	}
	printf("\n");
}
void TestHeapSort()
{
	int a[] = { 6,1,3,8,9,3,2,5,10,7 };
	int sz = sizeof(a) / sizeof(a[0]);

	HeapSort(a,sz);
	PrintArray(a,sz);
}

那么堆排序的时间复杂度是多少呢?

我们先来看一下建堆的复杂度:
在这里插入图片描述
建堆是 O(N),下面交换以及排大堆是 N*LOGN,按照大O渐进表示法,我们堆排序的时间复杂度为: O ( N ∗ L O G N ) O(N*LOGN) O(NLOGN)

再来看一下向上调整算法,建堆的复杂度:

在这里插入图片描述
这也是为什么我们不用向上调整算法的原因。

链式存储

先来看一下链式二叉树如何定义。
在这里插入图片描述
每一个节点我们都有数据和左孩子和右孩子。直接看遍历方式

链式二叉树有那么四种遍历方式,他们的访问方式为:

  • 前序遍历: 根 − > 左子树 − > 右子树 根->左子树->右子树 >左子树>右子树
  • 中序遍历: 左子树 − > 根 − > 右子树 左子树->根->右子树 左子树>>右子树
  • 后序遍历: 左子树 − > 右子树 − > 根 左子树->右子树->根 左子树>右子树>

很明显,这三种遍历方式很适合用递归来解决。
再来看一下层序遍历 (以上面大堆结果为例):

在这里插入图片描述
然后再挨个把队列的元素,Pop完就可以了,由于我们现在队列的元素是树的节点,所以最后队列里面全是 N U L L NULL NULL

  • 层序遍历的结果:就是按照层次把树中的元素打印出来。这里我们打印的就为 10 − > 9 − > 3 − > 8 − > 7 − > 3 − > 2 − > 5 − > 1 − > 6 10->9->3->8->7->3->2->5->1->6 10>9>3>8>7>3>2>5>1>6

代码实现:

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{
	if (root == NULL)
		return;
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreePrevOrder(root->_left);
	printf("%c ", root->_data);
	BinaryTreePrevOrder(root->_right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
		return;
	BinaryTreePrevOrder(root->_left);
	BinaryTreePrevOrder(root->_right);
	printf("%c ", root->_data);
}
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q,root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		printf("%c ", front->_data);
		if (front->_left)
		{
			QueuePush(&q,front->_left);
		}
		if (front->_right)
		{
			QueuePush(&q, front->_right);

		}
	}
	QueueDestroy(&q);

}

二叉树的练习

1.二叉树查找值为x的节点

思路:

  • 如果此时我们这个节点的值 == 我们要找的值,直接返回即可。
  • 如果不等于取左右子树去找
  • 返回其中一个答案。

代码:

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
		return NULL;
	if (root->_data == x)
		return root;
	BTNode* left = BinaryTreeFind(root->_left,x);
	BTNode* right = BinaryTreeFind(root->_right,x);
	return left == NULL ? right : left;
}
2.判断是否为完全二叉树

思路:

非完全二叉树我们测序遍历的时候跟完全二叉树有什么区别呢?

在这里插入图片描述
那就是我们会入空值进去,所以当我们取队头元素去到空值的时候,我们要判断如果队列中出现了非空的值,那就说明这时一个非完全二叉树。

代码:

// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, root);
	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		QueuePop(&q);
		
		if (front == NULL)
			break;
		QueuePush(&q,front->_left);
		QueuePush(&q,front->_right);
	}

	while (!QueueEmpty(&q))
	{
		BTNode* front = QueueFront(&q);
		if (front != NULL)
			return false;
		QueuePop(&q);
	}
	QueueDestroy(&q);
	return true;
}
LC226.翻转二叉树

在这里插入图片描述
思路:

  • 翻转二叉树是把左子树和右子树互换,那么我们每一个子树都要互换。所以我们要不断往子树递归把子树的左子树和右子树交换。这就跟我们的层序遍历一样。

所以我们要递归左右子树,最后再把左右子树交换,然后再返回root。

代码:

struct TreeNode* invertTree(struct TreeNode* root) {
    if (root == NULL)
        return NULL;
    struct TreeNode* left = invertTree(root->left);
    struct TreeNode* right = invertTree(root->right);

    root->right = left;
    root->left = right;
    return root;
}

在这里插入图片描述

LC572. 另一棵树的子树
  • 建议先做一下这道题100. 相同的树

这题其实就是去找和 subRoot 相同的子树。

注意这个例子:我们要保证我们找的 root和 subRoot 左右子树都相同。
所以这时我们要遍历的root的左子树才能判断与subRoot相同。
在这里插入图片描述
思路:

  • 如果 r o o t 和 s u b R o o t 都为 N U L L ,直接返回 t r u e root和subRoot都为NULL,直接返回true rootsubRoot都为NULL,直接返回true,如果只有一个为空,返回false,如果此时两个树的val相同,判断此时这个位置是否相同,如果相同直接返回true,不想同去root的左右子树,继续去找。只要找到一个就返回true。

代码:

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 && subRoot == NULL)
        return true;
    if (root == NULL || subRoot == NULL)
        return false;
    if (root->val == subRoot->val)
    {
        if (isSameTree(root,subRoot))
            return true;
    }
    return isSubtree(root->left,subRoot) || isSubtree(root->right,subRoot);
}
两道选择题

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

结言

到这里本篇文章就结束了。

本篇文章的基本思路如下:
在这里插入图片描述
OK,二叉树部分就到这吧,学C++去了。
在这里插入图片描述

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

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

相关文章

python操作注册表没有权限(error:5拒绝访问)

在IDE中运行 1. Openkey( , , accesswinreg.KEY_ALL_ACCESS) 2. 管理员方式运行Vscode或PyCharm 如果要打包成应用呢&#xff1f; 怎么处理权限问题&#xff1f;

Python 循环语句

在Python当中&#xff0c;循环语句用于重复执行特定的代码块&#xff0c;知道某个条件不再满足为止。Python中常用的循环有两种&#xff1a;for 循环 和 while 循环&#xff0c;下面我会分别详细解释它们的用法和特点 for 循环 for循环用于遍历可迭代对象(iterable)&#xff0…

522. 最长特殊序列 II

题目 给定字符串列表 strs &#xff0c;返回其中最长的特殊序列的长度。如果最长特殊序列不存在&#xff0c;返回 -1。 特殊序列定义如下&#xff1a;该序列为某字符串独有的子序列&#xff08;即不能是其他字符串的子序列&#xff09;。 字符串 s 的子序列可以通过删去字符…

学习笔记——网络管理与运维——SNMP(基本配置)

四、SNMP基本配置 1、SNMP配置举例 整个华为数通学习笔记系列中&#xff0c;本人是以网络视频与网络文章的方式自学的&#xff0c;并按自己理解的方式总结了学习笔记&#xff0c;某些笔记段落中可能有部分文字或图片与网络中有雷同&#xff0c;并非抄袭。完处于学习态度&#x…

PaddleOCR学习——PP-OCR系列

相关知识前置&#xff1a; PP-LCNet PP-LCNetV3 PP-LCNetV3系列模型是PP-LCNet系列模型的延续&#xff0c;覆盖了更大的精度范围&#xff0c;能够适应不同下游任务的需要。PP-LCNetV3系列模型从多个方面进行了优化&#xff0c;提出了可学习仿射变换模块&#xff0c;对重参数…

人脸识别系统---年龄预测

一、预测年龄 1.加载预训练的人脸检测模型 face_cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml)2.加载预训练的性别和年龄识别模型 gender_net cv2.dnn.readNetFromCaffe(deploy_gender.prototxt, gender_net.caffemodel) age_net cv2.dnn.readNet…

Qwen-VL图文多模态大模型LoRA微调指南

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 大模型应用向开发路径&#xff1a;AI代理工作流大模型应用开发实用开源项目汇总大模…

数据可视化实验二:回归分析、判别分析与聚类分析

目录 一、使用回归分析方法分析某病毒是否与温度呈线性关系 1.1 代码实现 1.2 线性回归结果 1.3 相关系数验证 二、使用判别分析方法预测某病毒在一定的温度下是否可以存活&#xff0c;分别使用三种判别方法&#xff0c;包括Fish判别、贝叶斯判别、LDA 2.1 数据集展示&am…

软件改为开机自启动

1.按键 win R,输入“shell:startup”命令, 然后就可以打开启动目录了&#xff0c;如下&#xff1a; 2.然后&#xff0c;把要开机启动的程序的图标拖进去即可。 参考&#xff1a;开机启动项如何设置

App端接口用例设计方法和测试方法

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 前言 接口测试作为测试的重要一环&#xff0c;重点关注的是数据层面的输入输出&#xff0c;今天…

白帽子最喜欢用什么渗透测试工具?看看哪些是你用过的

一、白帽子最喜欢用什么安全工具? 2020 年的 HackerOne 黑客报告中,统计过白帽子们最喜欢用的软硬件工具。 从图中可以看到,89% 的白帽子都会使用 Burp Suite 这个 Web 应用安全测试工具,有 39% 会尝试自己写工具,第三名的 Fuzzers 是模糊测试工具。再后面主要是一些代理…

时间复杂度 空间复杂度分析

时间复杂度就是需要执行多少次&#xff0c;空间复杂度就是对象被创建了多少次。 O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(2^n) < O(n!) < O(n^n) 这里写目录标题 时间复杂度O(1)O(logn)、O(nlogn)O(mn)、O(m*n)最好、最坏情况时间复杂度平均情况…

SD-WAN在教育行业的应用及优势解析

随着教育领域的数字化转型&#xff0c;网络技术的需求变得愈发迫切。作为一种前沿的网络解决方案&#xff0c;SD-WAN正在为教育行业提供强有力的支持。本文将详细探讨SD-WAN在教育行业的应用&#xff0c;并分析其为教育行业带来的众多优势。 实现多校区高效互联 教育机构通常拥…

使用Multipass编译OpenHarmony工程

Multipass 是一个轻量级虚拟机管理器&#xff0c;支持 Linux、Windows 与 macOS&#xff0c;这是为希望使用单个命令提供全新 Ubuntu 环境的开发人员而设计的。使用 Linux 上的 KVM、Windows 上的 Hyper-V 和 macOS 上的 HyperKit 来以最小的开销运行 VM&#xff0c;同时它还可…

数据结构试题 16-17

先这样吧&#xff0c;&#xff0c;专业课不是统考&#xff0c;我发现每年的卷子风格都不太一样&#xff0c;侧重点也不一样。以及21的和16的发生了很大的改变。等明年1月再看看吧 那就先over啦 数据结构撒花&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&am…

Zenity向Ubuntu系统发送通知

文章目录 前言 一、Zenity是什么&#xff1f; 二、使用步骤 1.确认是否已安装 2.使用 三. 结论 前言 大家都知道&#xff0c;久坐带来的后果有多么痛苦&#xff0c;但是每天上班&#xff0c;一坐一整天&#xff0c;想着起来活动一下&#xff0c;干起活来就又忘啦&#x…

什么品牌洗地机性价比高?四大出色的王牌机型力荐

科技的发展让咱们的生活变得更加便捷&#xff0c;很多智能清洁家电的出现&#xff0c;例如洗地机&#xff0c;集合了扫地、吸尘、拖地、除菌的功能&#xff0c;帮助了我们高效地完成了家务活&#xff0c;给我们腾出了更多享受生活的时间。但&#xff0c;相信有不少的新手朋友们…

【教程】hexo 更换主题后,部署在 Github Page 无 CSS 样式

目录 前言环境hexo 更换主题解决部署到 Github Page 后无 CSS 样式的问题 前言 最近更换了 hexo 的主题后&#xff0c;重新部署到 Github Page 上发现不显示 CSS 样式&#xff0c;但在本地启动时又是正常的效果。此外&#xff0c;检查资源请求&#xff0c;发现多个 .css 文件请…

2024-6-17(沉默JVM,Spring)

1.反射 正射&#xff1a;Person person new Person(); 反射&#xff1a;我们只知道这个类的一些基本信息&#xff0c;就好像我们看电影的时候&#xff0c;为了抓住一个犯罪嫌疑人&#xff0c;警察就会问一些目击证人&#xff0c;根据这些证人提供的信息&#xff0c;找专家把…

Elasticsearch:智能 RAG,获取周围分块(一)

作者&#xff1a;来自 Elastic Sunile Manjee 在检索增强生成 (RAG) 领域&#xff0c;一个持续存在的挑战是找到输入大型语言模型 (LLM) 的最佳数据量。数据太少会导致响应不足或不准确&#xff0c;而数据太多会导致答案模糊。这种微妙的平衡启发我开发了一个专注于智能分块和利…