C语言:二叉树的构建

news2024/11/25 7:08:49

目录

一、二叉树的存储

1.1        顺序存储

1.2        链式存储

二、二叉树的顺序结构及实现

2.1堆的概念及结构

2.2堆的构建

2.3堆的插入

2.4堆顶的删除

2.5堆的完整代码

三、二叉树的链式结构及实现

3.1链式二叉树的构建

3.2链式二叉树的遍历

3.2.1前序遍历

3.2.2中序遍历

3.2.3后序遍历

3.2.4层序遍历


一、二叉树的存储

二叉树一般用顺序结构存储或链式结构存储。

1.1        顺序存储

顺序存储就是用数组来存储,但一般使用数组只适合用来表示完全二叉树,如果不是完全二叉树,就可能存在空间浪费,甚至极大的空间浪费。二叉树的顺序存储在物理结构上是数组,在逻辑上是一颗二叉树。

例:1、完全二叉树

2、非完全二叉树

由上面两幅图可以看出,如果二叉树是非完全二叉树,则在数组中会存在很多空位,导致空间浪费。

1.2        链式存储

链式存储就是用链表来表示二叉树,一般用结构体表示每一个节点,每个节点中有三个域,数据域和左右指针域。数据域用来存储节点的数据,左指针指向左孩子,右指针指向右孩子。

二、二叉树的顺序结构及实现

在现实中,一般的二叉树用顺序存储可能会存在大量空间浪费,所以一般只用堆来用顺序结构存储。

这里的堆与地址空间中的堆不同,前者是数据结构,后者是操作系统中的一块内存区域分段。

2.1堆的概念及结构

1.概念:如果有一个集合K,将它的所有元素按照完全二叉树的顺序存储方式存储在一个一维数组中,并满足K(i)<=K(2*i+1)且K(i)<=K(2*i+1),则称为小堆,如果大于等于就是大堆。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

2.性质:

堆中某个节点的值总是不大于或不小于其父节点的值。

堆总是一颗完全二叉树。

 

2.2堆的构建

void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	assert(hp);//断言堆是否存在
	hp->_a = NULL;//将数据置为空
	hp->_capacity = 0;//将堆的容量清零
	hp->_size = 0;//将堆的大小清零
}

2.3堆的插入

void AdjustUp(HPDataType* a, int child)//向上调整堆
{
	int parent = (child - 1) / 2;//父节点在孩子节点-1除2的位置
	while (child>0)//如果孩子节点的位置不在最上面
	{
		if (a[child] < a[parent])//如果父节点小于孩子节点
		{
			swap(&a[child], &a[parent]);//交换值
			child = parent;
			parent = (child - 1) / 2;

		}
		else
		{
			break;
		}
	}
}

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);//断言堆是否存在
	if (hp->_size == hp->_capacity)//如果堆的大小等于容量,需扩容
	{
		size_t newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
		HPDataType* tmp = realloc(hp->_a, sizeof(HPDataType) * newcapacity);//定义临时变量扩容
		if (tmp == NULL)//判断扩容是否成功
		{
			perror("realloc fail");//扩容失败
			return;
		}
		hp->_a = tmp;//将变量传给a
		hp->_capacity = newcapacity;//扩容
	}
	hp->_a[hp->_size] = x;//将值插入堆的最后
	hp->_size++;//堆的大小加1
	AdjustUp(hp->_a ,hp->_size -1);//用向上调整的方法重新调整堆,防止插入后不再是大堆或小堆
}

2.4堆顶的删除

void AdjustUp(HPDataType* a, int child)//向下调整堆
{
	int parent = (child - 1) / 2;//父节点在孩子节点-1除2的位置
	while (child>0)//如果孩子节点的位置不在最上面
	{
		if (a[child] < a[parent])//如果父节点小于孩子节点
		{
			swap(&a[child], &a[parent]);//交换值
			child = parent;
			parent = (child - 1) / 2;

		}
		else
		{
			break;
		}
	}
}
// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);//断言堆是否存在
	assert(hp->_size > 0);//断言堆的大小是否为0
	swap(&hp->_a[0], &hp->_a[hp->_size - 1]);//交换堆顶和堆尾的值
	hp->_size--;//堆的大小减1
	AdjustDown(hp->_a, hp->_size, 0);//向下调整堆
}

2.5堆的完整代码


// 堆的构建
void HeapCreate(Heap* hp, HPDataType* a, int n)
{
	assert(hp);//断言堆是否存在
	hp->_a = NULL;//将数据置为空
	hp->_capacity = 0;//将堆的容量清零
	hp->_size = 0;//将堆的大小清零
}

// 堆的销毁
void HeapDestory(Heap* hp)
{
	assert(hp);//断言堆是否存在
	free(hp->_a);//释放数据
	hp->_a = NULL;//将指针置为空
	hp->_capacity = 0;将堆的容量清零
	hp->_size = 0;//将堆的大小清零
}
void swap(HPDataType* x, HPDataType* y)
{
	HPDataType tmp = *x;
	*x = *y;
	*y = tmp;
}


void AdjustDown(HPDataType* a, int n, int parent)
{
	int child = parent * 2 + 1;//左孩子节点是父亲节点的2倍加1
	while (child < n)//如果孩子节点不在最后
	{
		//找到左右孩子中较小的
		if (child + 1 < n && a[child + 1] < a[child])//如果左孩子大于右孩子
		{
			++child;
		}
		if (a[child] < a[parent])//如果孩子小于父亲
		{
			swap(&a[child], &a[parent]);//交换父节点与子节点
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			break;
		}
	}
}

void AdjustUp(HPDataType* a, int child)//向上调整堆
{
	int parent = (child - 1) / 2;//父节点在孩子节点-1除2的位置
	while (child>0)//如果孩子节点的位置不在最上面
	{
		if (a[child] < a[parent])//如果父节点小于孩子节点
		{
			swap(&a[child], &a[parent]);//交换值
			child = parent;
			parent = (child - 1) / 2;

		}
		else
		{
			break;
		}
	}
}

// 堆的插入
void HeapPush(Heap* hp, HPDataType x)
{
	assert(hp);//断言堆是否存在
	if (hp->_size == hp->_capacity)//如果堆的大小等于容量,需扩容
	{
		size_t newcapacity = hp->_capacity == 0 ? 4 : hp->_capacity * 2;
		HPDataType* tmp = realloc(hp->_a, sizeof(HPDataType) * newcapacity);//定义临时变量扩容
		if (tmp == NULL)//判断扩容是否成功
		{
			perror("realloc fail");//扩容失败
			return;
		}
		hp->_a = tmp;//将变量传给a
		hp->_capacity = newcapacity;//扩容
	}
	hp->_a[hp->_size] = x;//将值插入堆的最后
	hp->_size++;//堆的大小加1
	AdjustUp(hp->_a ,hp->_size -1);//用向上调整的方法重新调整堆,防止插入后不再是大堆或小堆
}


// 取堆顶的数据
HPDataType HeapTop(Heap* hp)
{
	assert(hp);//断言堆是否存在
	return hp->_a[0];
}


// 堆的删除
void HeapPop(Heap* hp)
{
	assert(hp);//断言堆是否存在
	assert(hp->_size > 0);//断言堆的大小是否为0
	swap(&hp->_a[0], &hp->_a[hp->_size - 1]);//交换堆顶和堆尾的值
	hp->_size--;//堆的大小减1
	AdjustDown(hp->_a, hp->_size, 0);//向下调整堆
}

// 堆的数据个数
int HeapSize(Heap* hp)
{
	assert(hp);
	return hp->_size;
}
// 堆的判空
int HeapEmpty(Heap* hp)
{
	assert(hp);
	return hp->_size == 0;
}


// 对数组进行堆排序
void HeapSort(int* a, int n)
{
	for (int i = (n - 1) / 2; i >= 0; --i)
	{
		AdjustDown(a, n, i);
	}
}

三、二叉树的链式结构及实现

一颗链式二叉树一般用结构体表示,结构体中一个存储数据,一个链表指向左孩子节点,一个指向右孩子节点。

typedef int BTDataType;//方便后面改变二叉树中的数据类型

typedef struct BinaryTreeNode
{
	BTDataType data;//二叉树存储数据的节点
	struct BinaryTreeNode* left;//左孩子节点
	struct BinaryTreeNode* right;//右孩子节点
}BTNode;//重命名

3.1链式二叉树的构建

BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)//二叉树一般需要手动扩建
{
	BTNode* n1 = BuyNode('A');
	BTNode* n2 = BuyNode('B');
	BTNode* n3 = BuyNode('C');
	BTNode* n4 = BuyNode('D');
	BTNode* n5 = BuyNode('E');
	BTNode* n6 = BuyNode('F');
	BTNode* n7 = BuyNode('G');
	BTNode* n8 = BuyNode('H');
	n1->left = n2;
	n1->right = n3;
	n2->left = n4;
	n2->right = n5;
	n3->left = n6;
	n3->right = n7;
	n5->left = n8;
	return n1;
}

3.2链式二叉树的遍历

二叉树的遍历就是按照某种特殊规则,依次对二叉树的节点进行操作,每个节点只能操作一次。

二叉树的遍历一般有4种方式。

3.2.1前序遍历

前序遍历:优先操作每个节点的自身,后操作左节点,最后操作右节点。

例如上图的树就是按照A-B-D-E-H-C-F-G的顺序操作。

从A开始,先操作A的自身,再访问A的左节点B。

B节点先操作自身,再访问B的左节点D。

D节点操作自身,无孩子节点则返回到B,访问B的右节点E。 

E节点操作自身,再访问E的左节点H。

H节点操作自身,无孩子节点则返回到E,E无左孩子节点则返回到B,B的左右孩子都已访问则返回到A,访问A的右节点C。

C节点操作自身,再访问C的左节点F。

F节点操作自身,无孩子节点则返回C,访问C的右节点G

G节点操作自身,无孩子节点,访问结束。

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root) 
{
	if (root == NULL)
	{
		printf("N ");//如果节点为空打印N
		return;
	}
	printf("%c ", root->data);//打印节点
	BinaryTreePrevOrder(root->left);//访问左节点
	BinaryTreePrevOrder(root->right);//访问右节点
}

3.2.2中序遍历

中序遍历:优先操作每个节点的左节点,后操作自身,最后操作右节点。

上图按照D-B-H-E-A-F-C-G的顺序操作。 

从A开始,先访问A的左节点B,B节点先访问D,D无左节点,操作自身。

D无右节点,则返回B,操作B的自身,再访问B的右节点E。

E节点先访问左节点H,H无左节点,操作自身,H无右节点,则返回E节点。

E节点操作自身,无右节点,返回B节点,再返回A节点。

A节点操作自身,再访问右节点C,C节点访问左节点F。

F无左节点操作自身,无右节点,返回C节点。

C节点操作自身,再访问C的右节点G。

G无左节点,操作自身,无右节点,访问结束。

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");//如果节点为空打印N
		return;
	}
	BinaryTreePrevOrder(root->left);//访问左节点
	printf("%c ", root->data);//打印节点
	BinaryTreePrevOrder(root->right);//访问右节点
}

3.2.3后序遍历

后序遍历:优先操作每个节点的左节点,后操作右节点,最后操作自身。

上图按照D-B-H-E-F-C-G-A的顺序操作。

从A开始,访问A的左节点B,再访问B的左节点D,D无左右节点,操作自身,返回B节点。

访问B节点的右节点E,再访问E的左节点H,H无左右节点, 操作自身,返回E节点。

E节点操作自身,返回B节点。

B节点操作自身,返回A节点,再访问A节点的右节点C,访问C的左节点F。

F无左右节点,操作自身,返回C节点,访问C节点的右节点G。

G无左右节点,操作自身,返回C节点。

C节点操作自身,返回A节点。

A节点操作自身,访问结束。

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");//如果节点为空打印N
		return;
	}
	BinaryTreePrevOrder(root->left);//访问左节点
	BinaryTreePrevOrder(root->right);//访问右节点
	printf("%c ", root->data);//打印节点
}

3.2.4层序遍历

 层序遍历:按照二叉树的每一层,一层一层的从左向右操作。

实现二叉树的层序遍历需要用到队列的知识。

队列是一个有着先进先出原则的链表,先进的元素永远比后进的元素先出来。通过队列的规则,只要二叉树的每一个节点出队列时将其左右孩子节点入队列即可完成二叉树的层序遍历。

上图的操作顺序是A-B-C-D-E-F-G-H

A节点入队列,A节点出队列,将A的左右子节点BC入队列。

此时队列中有B-C,将B出队列,B的左右子节点DE入队列。

此时队列中有C-D-E,将C出队列,C的左右子节点FG入队列。

此时队列中有D-E-F-G,将D出队列,D无子节点。

此时队列中有E-F-G,将F出队列,F的左节点H入队列。

此时队列中有F-G-H,均无子节点,一个一个出队列即可。

 队列头文件代码

#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
typedef  struct BinTreeNode* QDataType;
// 链式结构:表示队列 
typedef struct QueueNode
{
	QDataType data;
	struct QueueNode* next;
}QNode;
// 队列的结构 
typedef struct Queue
{
	QNode* phead;
	QNode* ptail;
	int size;
}Queue;
// 初始化队列 
void QueueInit(Queue* q);
// 队尾入队列 
void QueuePush(Queue* q, QDataType data);
// 队头出队列 
void QueuePop(Queue* q);
// 获取队列头部元素 
QDataType QueueFront(Queue* q);
// 获取队列队尾元素 
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数 
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q);
// 销毁队列 
void QueueDestroy(Queue* q);

队列代码

#include"1.h"

// 初始化队列 
void QueueInit(Queue* q)
{
	assert(q);//断言队列是否存在
	q->phead = NULL;//将头节点的置为空
	q->ptail = NULL;//将尾节点置为空
	q->size = 0;//将队列大小初始化为0
}

// 队尾入队列 
void QueuePush(Queue* pq, QDataType x)
{
	assert(pq);//断言队列是否存在
	QNode* newnode = (QNode*)malloc(sizeof(QNode));//创建临时变量
	if (newnode == NULL)//判断变量是否创建成功
	{
		perror("malloc fail");
		return;
	}
	newnode->data = x;//将要入队列的值给临时变量
	newnode->next = NULL;//将临时变量的指向下一个节点的指针置空

	if (pq->ptail)//如果尾队列存在,则队列中含有数据
	{
		pq->ptail->next = newnode;//将原本尾队列指向下一个节点的指针指向临时变量
		pq->ptail = newnode;//将临时变量设为尾节点
	}
	else//尾队列不存在,则队列为空
	{
		pq->phead = pq->ptail = newnode;//将头节点和尾节点都设为临时变量
	}

	pq->size++;//队列大小加1
}


// 队头出队列 
void QueuePop(Queue* q)
{
	assert(q);//断言队列是否存在
	assert(q->phead != NULL);//断言队列的头节点是否为空
	if (q->phead->next == NULL)//队列头节点的下一个节点为空,则队列中只有一个元素
	{
		free(q->phead);//释放头节点
		q->phead = q->ptail = NULL;//将头节点和尾节点置空
	}
	else//队列中不止1个元素
	{
		QNode* next = q->phead->next;//创建临时变量指向头节点的下一个节点
		free(q->phead);//是否头节点
		q->phead = next;//将头节点的下一个节点设为头节点
	}
	q->size--;//队列大小减1
}

// 获取队列头部元素 
QDataType QueueFront(Queue* q)
{
	assert(q);//断言队列是否存在
	assert(q->phead != NULL);//断言队列的头节点是否为空
	return q->phead->data;//返回队列头节点的数据
}

// 获取队列队尾元素 
QDataType QueueBack(Queue* q)
{
	assert(q);//断言队列是否存在
	assert(q->ptail != NULL);//断言队列的尾节点是否为空
	return q->ptail->data;//返回队列尾节点的数据
}

// 获取队列中有效元素个数 
int QueueSize(Queue* q)
{
	assert(q);//断言队列是否存在
	return q->size;//返回队列的大小
}

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0 
int QueueEmpty(Queue* q)
{
	assert(q);//断言队列是否存在
	return q->size == 0;//判断队列的大小是否为0
}

// 销毁队列 
void QueueDestroy(Queue* q)
{
	assert(q);//断言队列是否存在
	QNode* cur = q->phead;//定义临时节点等于头节点
	while (cur)//如果头节点不为空
	{
		QNode* next = cur->next;//定义临时节点指向头节点的下一个节点
		free(cur);//释放头节点
		cur = next;//将下一个节点当作头节点
	}
	q->phead = NULL;//将头节点指针置空
	q->ptail = NULL;//将尾节点指针置空
	q->size = 0;//将队列大小置为0
}

 二叉树头文件

#pragma once
#include<stdio.h>
#include<string.h>
#include<assert.h>
#include<stdlib.h>
typedef int BTDataType;//方便后面改变二叉树中的数据类型

typedef struct BinaryTreeNode
{
	BTDataType data;//二叉树存储数据的节点
	struct BinaryTreeNode* left;//左孩子节点
	struct BinaryTreeNode* right;//右孩子节点
}BTNode;//重命名

#include"1.h"

// 通过前序遍历的数组"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);
// 二叉树第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);
// 层序遍历
void BinaryTreeLevelOrder(BTNode* root);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);

二叉树代码

#include"tree.h"
BTNode* BuyNode(BTDataType a)//a是要创建的值
{
	BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));//定义临时变量扩容
	if (newnode == NULL)
	{
		printf("malloc fail");//扩容失败
		return NULL;
	}
	newnode->data = a;
	newnode->left = NULL;
	newnode->right = NULL;
	return newnode;
}
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)//二叉树一般需要手动扩建
{
	BTNode* n1 = BuyNode('A');
	BTNode* n2 = BuyNode('B');
	BTNode* n3 = BuyNode('C');
	BTNode* n4 = BuyNode('D');
	BTNode* n5 = BuyNode('E');
	BTNode* n6 = BuyNode('F');
	BTNode* n7 = BuyNode('G');
	BTNode* n8 = BuyNode('H');
	n1->left = n2;
	n1->right = n3;
	n2->left = n4;
	n2->right = n5;
	n3->left = n6;
	n3->right = n7;
	n5->left = n8;
	return n1;
}


// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{
	assert(root);
	free(root);
	
}

// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{
	return root == NULL ? 0 :
		BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
}

// 二叉树叶子节点个数
int BinaryTreeLeafSize(BTNode* root)
{
	if (root == NULL)
	{
		return 0;
	}
	if (root->left == NULL && root->right == NULL)
	{
		return 1;
	}
	return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
}

// 二叉树第k层节点个数
int BinaryTreeLevelKSize(BTNode* root, int k)
{
	assert(k > 0);
	if (root == NULL)
	{
		return 0;
	}
	if (k == 1)
	{
		return 1;
	}
	return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);
}

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{
	if (root == NULL)
	{
		return NULL;
	}
	if (root->data == x)
	{
		return root;
	}
	BTNode* ret1= BinaryTreeFind(root->right, x);
	if (ret1)
	{
		return ret1;
	}
	BTNode* ret2=BinaryTreeFind(root->left , x);
	if (ret2)
	{
		return ret2;
	}
	return NULL;
}

// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root) 
{
	if (root == NULL)
	{
		printf("N ");//如果节点为空打印N
		return;
	}
	printf("%c ", root->data);//打印节点
	BinaryTreePrevOrder(root->left);//访问左节点
	BinaryTreePrevOrder(root->right);//访问右节点
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");//如果节点为空打印N
		return;
	}
	BinaryTreePrevOrder(root->left);//访问左节点
	printf("%c ", root->data);//打印节点
	BinaryTreePrevOrder(root->right);//访问右节点
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{
	if (root == NULL)
	{
		printf("N ");//如果节点为空打印N
		return;
	}
	BinaryTreePrevOrder(root->left);//访问左节点
	BinaryTreePrevOrder(root->right);//访问右节点
	printf("%c ", root->data);//打印节点
}
// 层序遍历
void TreeLevelOrder(BTNode* root)
{
	Queue q;//定义临时节点
	QueueInit(&q);//创建临时节点
	if (root)//如果节点不为空
	{
		QueuePush(&q, root);//节点入队列
	}
	while (!QueueEmpty(&q))//如果队列不为空
	{
		BTNode* front = QueueFront(&q);//获取队头元素
		QueuePop(&q);//队头元素出队列
		if (front)//如果节点存在
		{
			printf("%d ", front->data);//打印节点数据
			// 带入下一层
			QueuePush(&q, front->left);//左孩子节点入队列
			QueuePush(&q, front->right);//右孩子节点入队列
		}
		else
		{
			printf("N ");//不存在打印N
		}
	}
	printf("\n");
	QueueDestroy(&q);//销毁临时节点,防止空间泄露
}

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

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

相关文章

【Zblog搭建博客网站】windows环境搭建属于自己的博客并发布上线 – cpolar内网穿透

目录 1. 前言 2. Z-blog网站搭建 2.1 XAMPP环境设置 2.2 Z-blog安装 2.3 Z-blog网页测试 2.4 Cpolar安装和注册 3. 本地网页发布 3.1. Cpolar云端设置 3.2 Cpolar本地设置 4. 公网访问测试 5. 结语 1. 前言 想要成为一个合格的技术宅或程序员&#xff0c;自己搭建网…

论文精读--GPT4

现有的所有模型都无法做到在线学习&#xff0c;能力有限&#xff0c;而让大模型拥有一个tools工具库&#xff0c;则可以使大模型变成一个交互式的工具去协调调用API完成任务&#xff0c;同时GPT4还联网了&#xff0c;可以不断地更新自己的知识库 多模态模型&#xff0c;接受文…

docker容器之etcd安装

一、etcd介绍 1、etcd是什么 etcd是CoreOS团队于2013年6月发起的开源项目&#xff0c;它的目标是构建一个高可用的分布式键值(key-value)数据库。 2、etcd特点 简单的接口&#xff0c;通过标准的HTTP API进行调用&#xff0c;也可以使用官方提供的 etcdctl 操作存储的数据。…

鸿蒙开发岗位需求激增、鸿蒙迎来“薪”时代

随着科技的快速发展&#xff0c;智能操作系统已经成为科技巨头们争夺的焦点。近期&#xff0c;华为鸿蒙操作系统再次迎来重大突破&#xff0c;11家万亿市值的巨头纷纷宣布与华为达成合作&#xff0c;全面拥抱鸿蒙生态。 11家万亿市值巨头的签约涵盖了多个领域&#xff0c;包括…

yolov7代码 | model.named_models

文章目录 前言1. print(model)2. print(model.named_models)2.1 print(name)2.2 print(module)2.3 print(f"{name}:: {module}") 3. hasattr(module, weight) 前言 了解model.named_models&#xff0c;为剪枝做准备。 剪枝有一些层如果你不想剪掉&#xff0c;那就用…

OpenHarmony实战:小型系统 STM32MP1 芯片移植案例

本文章基于意法半导体 STM32MP157 芯片的小熊派 BearPi-HM Micro 开发板&#xff0c;进行小型带屏开发板的移植&#xff0c;实现了 ace_engine_lite、arkui_ui_lite、aafwk_lite、appexecfwk_lite、HDF 等部件基于 OpenHarmony LiteOS-A 内核的适配。移植架构上采用 Board 与 S…

总结UDP协议各类知识点

前言 本篇博客博主将详细地介绍UDP有关知识点&#xff0c;坐好板凳发车啦~ 一.UDP特点 1.无连接 UDP传输的过程类似于发短信&#xff0c;知道对端的IP和端口号就直接进行传输&#xff0c;不需要建立连接&#xff1b; 2.不可靠传输 没有任何的安全机制&#xff0c;发送端发…

Linux 进程信号:内核中信号结构、阻塞信号、捕捉信号

目录 一、阻塞信号 1、信号的状态 2、内核中的信号 信号集&#xff08;Signal Set&#xff09; task_struct 结构体 信号处理函数&#xff08;Handler&#xff09; 信号传递与调度 3、“signal_struct结构体”与“信号集sigset_t” 4、信号集操作函数 5、信号屏蔽字si…

YARN集群 和 MapReduce 原理及应用

YARN集群模式 本文内容需要基于 Hadoop 集群搭建完成的基础上来实现 如果没有搭建&#xff0c;请先按上一篇: <Linux 系统 CentOS7 上搭建 Hadoop HDFS集群详细步骤> 搭建&#xff1a;https://mp.weixin.qq.com/s/zPYsUexHKsdFax2XeyRdnA 配置hadoop安装目录下的 etc…

Python学习:面相对象

面向对象 面向对象技术简介 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。方法:类中定义的函数。类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实…

数据库-root密码丢失的重置方案(win11环境)

当在windows系统中安装的mysql由于操作不当&#xff0c;或者密码遗忘&#xff0c;今天测试了一下&#xff0c;可以用以下方法重置root的密码。 mysqlwindows环境root密码重置问题 在win10/11环境下mysql8密码遗忘后的重置密码方案。 停止mysql服务 查找windows中的mysql服务名称…

Windows下用CMake编译PugiXML及配置测试

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 PugiXML是什么&#xff1f; PugiXML 是一个用于解析和操作 XML 文档的 C 库。它提供了简单易用的接口&#xff0c;能够高效地加载…

Spring IoCDI(2)

IoC详解 通过上面的案例, 我们已经知道了IoC和DI的基本操作, 接下来我们来系统地学习Spring IoC和DI的操作. 前面我们提到的IoC控制反转, 就是将对象的控制权交给Spring的IoC容器, 由IoC容器创建及管理对象. (也就是Bean的存储). Bean的存储 我们之前只讲到了Component注解…

C 练习实例97 - 读磁盘 写磁盘

题目&#xff1a;从键盘输入一些字符&#xff0c;逐个把它们送到磁盘上去&#xff0c;直到输入一个‘#’为止 在桌面新建一个hello.txt文件&#xff0c;内容示例&#xff1a; 代码&#xff1a; #include <stdio.h> #include <stdlib.h>int main() {FILE *fp; //文…

PetaLinux 去除自动获取 IP 地址

问题&#xff1a;系统启动的时候会自动检测 IP 地址&#xff0c;如不需要这个功能&#xff08;该过程需耗时十几秒&#xff09;。可以自定义 IP 地址&#xff0c;去掉这一步。 操作步骤如下&#xff1a; 所有命令均需在非管理员模式下执行 1. 初始化 PetaLinux 运行环境 运行…

新手学python还是c?

考虑到个人情况和职业规划是非常重要的。我这里有一套编程入门教程&#xff0c;不仅包含了详细的视频讲解&#xff0c;项目实战。如果你渴望学习编程&#xff0c;不妨点个关注&#xff0c;给个评论222&#xff0c;私信22&#xff0c;我在后台发给你。 Python作为初学者入门语言…

isaacgym 渲染黑屏

问题描述&#xff1a; isaacgym安装完IsaacGym_Preview_4_Package.tar.gz之后&#xff0c;运行python joint_monkey.py没有任何内容现实&#xff0c;但是终端还是正常输出信息。 环境是ubuntu22服务器&#xff0c;python3.8&#xff0c;nvidia Driver Version: 515.65.01 CUDA…

IP代理池赋能Python网络爬虫

文章目录 什么是IP代理池代理服务器IP代理池的作用IP代理池的构建IP代理池的管理 相关案例IP代理在爬虫中的运用IP代理在数据收集中的运用IP代理在反爬虫中的运用 结语 什么是IP代理池 IP代理池是一个存储了多个可用代理IP地址的资源池&#xff0c;用于在网络爬虫、数据采集、…

【实战项目】某考务成绩查询小程序

熊猫开发记录 – QQ&#xff1a;1040375575 【实战项目】某考务成绩查询小程序 一、项目功能二、项目涉及三、部分代码四、程序实现 一、项目功能 实现通过身份证号、手机号、手机验证码三层进行后台成绩获取&#xff0c;并输出提示。 二、项目涉及 项目涉及前端开发&#x…

B树,红黑树,LR,RL

红黑树来源于多叉树–>234树4阶B树 红黑树&#xff1a;每个节点不是红色就是黑色&#xff0c;根节点一定是黑色&#xff0c;叶子节点是黑色的&#xff0c;一个红色节点的子节点一定是黑色的&#xff0c;从根节点到根节点都会经过相同数量的黑色节点&#xff0c;从根节点到任…