当前位置: 首页 > news >正文

数据结构--树

树的基本概念

  • 树:一个或多个节点的有限集合。
    存在一个称为的特定节点,其余的节点被分为n个互不相交的集合T1,T2,…,Tn,其中的每一个集合都是一棵树。T1,T2,…,Tn称为根节点的子树
    在这里插入图片描述

  • 结点:树中的一个独立单元

  • 结点的度:结点拥有的子树数称为结点的度。

  • 树的度:树内各结点度的最大值。

  • 叶子:度为0的节点或终结结点。

  • 非叶子结点(非终端结点):度不为0的结点。

  • 双亲,孩子,兄弟,堂兄弟结点

    • 1.结点的子树的根称为该结点的孩子。
    • 2.该结点称为孩子的双亲。
    • 3.同一双亲结点的所有子节点互称为兄弟节点。(eg:图6-1中结点B、C、D是兄弟节点,E、F是兄弟结点)
    • 4.双亲结点在同一层上的所有结点互称为堂兄弟结点(图6-1中结点EFGHIJ互称为堂兄弟结点)
  • 层次:结点的层次从根开始定义,根为第一层,根的孩子为第二层。以此类推。

  • 层次路径:从根节点开始,到达某结点p所经过的所有结点称为结点p的层次路径。(有且仅有一条)

  • 祖先(ancester):结点p的层次路径上的所有结点(p除外).

  • 子孙节点(descent):以某一结点为根的子树中的任意结点称为该结点的子孙结点

  • 树的深度(depth):树中结点的最大层次,即树总共的层数。也称为树的高度

  • 有序树和无序树:对于一棵树,若其中每一个结点的子树(若有)具有一定的次序,则该树为有序树,否则称为无序树。

  • 森林(forest):是m(m>=0)课互不相交的树的集合。显然,若将一棵树的根结点删除,剩余的子树就构成了森林。

  • 二叉树:二叉树(Binary tree)是n(n>0)个结点的有限集合。
    若n=0时称为空树,否则:
    (1)有且只有一个特殊的称为树的根(Root)结点
    (2)若n>1时,其余的结点被分成为二个互不相交的子集T1,T2分别称之为左、右子树,并且左、右子树又都是二叉树。
    由此可知,二叉树的定义是递归的。
    在这里插入图片描述

  • 满二叉树:深度为k且含有2^k-1个结点的二叉树

    • 1.所有的叶子节点只能出现在最后一层
    • 2.对于同样深度的二叉树,满二叉树的节点个数最多,叶子结点的数量也是最多的。
    • 3.如果对满二叉树进行编号,根结点从1开始,从上到下从左到右,对于编号为i的结点,若存在左孩子,则左孩子的编号为2i,右孩子为2i+1
  • 完全二叉树:深度为k、有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的节点一一对应时,称之为完全二叉树。

    • 1.叶子结点只可能在层数最大的两层上出现
    • 2.对任意结点,若其右分支下的子孙的最大层次为i,则其左分支下的子孙的最大层次必为i或i+1
  • 没有左子树,不能有右子树,上一层没有铺满,不能有下一层。

  • 线索化:利用叶节点的空余空间记录前驱、后继。

  • 线索二叉树:按照某种次序遍历,根据遍历的顺序加上线索的二叉树。

  • 结点的权:在实际应用中,给树种的结点赋予代表某种含义的数值

  • 结点的带权路径长度:从该节点到树根之间的路径长度与该节点权的乘积

  • 树的带权路径长度(WPL):树中所有节点的带权路径长度之和

  • 哈夫曼树:带权路径长度WPL最小的二叉树称为哈夫曼树。
    哈夫曼树的性质

    • 1.哈夫曼树没有度为1的结点
    • 2.树中两个权值最小的节点一定是兄弟结点
    • 3.树中任一非叶结点的权值一定不小于下一层任一结点的权值
  • 哈夫曼编码:左0右1,按在哈夫曼树中的路径写出的编码

1. 生成树 (Spanning Tree) 的定义

生成树 是一个图的子图,包含图中的所有节点,并且是一个树结构。生成树必须满足以下条件:

  • 包含所有节点:生成树的节点数与原图相同。
  • 无环性:生成树不能包含环。
  • 连通性:生成树中的每对节点之间都可以通过生成树中的边连通。
  • 边数:对于一个有 (V) 个节点的图,生成树的边数为 (V - 1)。

一个图可以有多个生成树,因为可以从图中选择不同的边组合来构成生成树。

2. 最小生成树 (Minimum Spanning Tree, MST) 的定义

最小生成树 是一个特殊的生成树,除了满足生成树的基本条件外,它还要求所有边的权重之和最小。换句话说,最小生成树是所有生成树中,边权和最小的那一棵生成树。

最小生成树的构建通常依赖于图中边的权重,而生成树只是关心是否覆盖所有节点且不形成环。

3. 生成树与最小生成树的关系
  • 每个最小生成树都是生成树:最小生成树首先满足生成树的所有基本要求,因为它是一个包含所有节点的连通无环子图。但它进一步满足了最小生成树的特性,即边的总权重最小。

  • 每个生成树不一定是最小生成树:虽然所有的最小生成树都是生成树,但并非所有的生成树都是最小生成树。生成树可以有多种形式,不一定考虑边的权重,因此可能有一些生成树的边权和比最小生成树要大。

4. 图的生成树和最小生成树的差异
特性生成树 (Spanning Tree)最小生成树 (MST)
定义包含所有节点且无环的子图,边数为 (V-1)除了是生成树,还要求边权和最小
边权要求不考虑边的权重边的权重和最小
生成方式可以随意选择边,不考虑权重需要选择权重最小的边
多个可能性对于一个图,生成树可能有多个对于一个图,最小生成树是唯一的(假设没有相同权重的边)
示例图中任意选择不形成环的 (V-1) 条边图中选择边权和最小的边,确保没有环且连通

6. 总结

  • 生成树 是一个无环且连通的子图,包含原图中的所有节点,边数为 (V-1)。
  • 最小生成树 是生成树的一种特例,它要求所有边的权重之和最小。
  • 每个最小生成树都是生成树,但不是所有生成树都是最小生成树
  • 求解最小生成树的常见算法有 Kruskal 算法Prim 算法,它们都是通过贪心策略选择权重最小的边来构建最小生成树。

树的表示形式

1.倒悬树,最常用的表示形式(eg:图6-1)
2.嵌套集合,是一些集合的集体,对于任何两个集合,或者不相交,或者一个集合包含另一个集合。(图6-2(a)是图6-1(b)树的嵌套集合形式)
3.广义表形式:eg:图6-2(b)
4.凹入法表示形式
在这里插入图片描述
树转化为二叉树
1.加线,在所有兄弟结点之间加一条线
2.去线,对树中的每一个结点,只保留
它与第一个孩子结点的连线,删除它与
其它孩子结点之间的连线.
3.层次调整,以树的根结点为轴
心,将整棵数顺时针旋转一定角
度,使之层次分明.注意第一个
孩子是二叉树结点的左孩子.兄
弟转过来的孩子是结点的右孩
子.
这样转换后的二叉树的特点是:
1.二叉树的根结点没有右子树,只有左子树
2.左子结点仍然是原来树中相应结点的左子结点,而所有沿右链往下的右子节点均是原来树中该结点的兄弟节点。
在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述
二叉树转化为树
1.加线,若某个结点的左孩子存在,则
将这个左孩子的所有右孩子结点都作为
此结点的孩子,将该结点与这些右孩子
结点用线连起来.
2.去线,删除二叉树中所有结点与其右
孩子结点的连线
3.调整,转一下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
森林转换成二叉树
当一半的树转换成二叉树后,二叉树的右子树必为空。若把森林中的第二课树(转换成二叉树后)的根结点作为第一棵树(二叉树)的根结点的兄弟结点,则可以导出森林转二叉树的方法。
步骤:
1.将所有树转化成二叉树
2.按照给出的森林中树的次序,从最后一颗二叉树开始,每棵二叉树作为前一颗二叉树的根结点的右子树,依此类推,则第一颗二叉树的根结点就是转换后生成的二叉树的根结点。
在这里插入图片描述
二叉树转森林
在这里插入图片描述

树的遍历

树:先根遍历 后根遍历
二叉树:先序遍历 中序遍历 后序遍历
森林:前序遍历 后序遍历
在这里插入图片描述

树的性质

1.树中所有节点数等于所有节点的度数之和加1
2.对于度为m的树,第i层上最多有m^(i-1)个节点
3.性质三:对于高度为 h,度为 m 的树,最多有(m^h-1)/(m-1)个结点

二叉树的性质

1.二叉树的第i层最多有2^(i-1)个节点
2.深度为k的二叉树最多有2^k-1个节点
3.对于任何非空的二叉树T,如果叶子节点的个数为n0,而度为2的节点数为n2,则n0=n2+1
性质3证明:设二叉树中度为1的结点数为m,二叉树中总结点数为N,因为二又树中所有结点均小于或等于2,则有:N=n0+n1+n2
再看二叉树中的分支数
除根结点外,其余每个结点都有唯一的一个进入分支而所有这些分支都是由度为1和2的结点射出的。设B为二叉树中的分支总数,则有:N=B+1
∴B=n1+2xn2
∴N=B+1=n+2xn2+1
∴n0+n1+n2=n1+2xn2+1
即n0=n2+1

完全二叉树的性质

1:具有n个结点的完全二叉树的深度为⌊log2(n+1)⌋
2:如果对一棵有n个结点的完全二叉树(其深度为⌊log2(n+1)⌋的结点按层序编号(从第1层到第⌊log2(n+1)⌋,每层左到右),则对任一结点
(1≤i≤n),以下结论成立。
(1)如果i=1,则结点i是二叉树的根,无双亲;如果结点i>1则其双亲是结点 ⌊i/2⌋
(2)如果 2i>n,则结点i无左孩子(结点i为叶子结点);否则其左孩子是结点2i
(3)如果 2i+1>n,则结点i无右孩子;否则其右孩子的结点是 2i+1。
在这里插入图片描述

二叉树的存储结构

1.顺序存储结构

用一组地址连续的存储单元依次“自上而下、自左至右”存储完全二又树的数据元素。
对于完全二叉树上编号为i的结点元素存储在一维数组的下标值为i-1的分量中,如图6-6©所示。
对于一般的二叉树,将其每个结点与完全二叉树上的结点相对照,存储在一维数组中,如图6-6(d)所示
在这里插入图片描述
最坏的情况下,一个深度为k且只有k个结点的单支树需要长度为2^k-1的一维数组。
顺序结构不适合存储非完全二叉树,顺序存储结构并不适合用于存储非完全二叉树,原因在于其存储方式是基于节点的逻辑位置(下标计算)进行的,而非完全二叉树在节点的分布上是不规则的,存在很多空闲位置,空闲位置得用无效标识符填充,不填充没法遍历。如果使用顺序存储,空闲位置会浪费内存,从而导致空间的浪费和不必要的复杂性。

2.链式存储结构

结点的类型及其定义
1.二叉链表结点。有三个域:一个数据域,两个分别指向左右子结点的指针域,如图6-7(a)所示。
2. 三叉链表结点。除二叉链表的三个域外,再增加一个指针域,用来指向结点的父结点,如图6-7(b)所示:
链式存储结构是最好用最方便最常用的存储树的方式。
在这里插入图片描述
在这里插入图片描述
链式存储结构非常适合用于存储任何类型的二叉树(包括非完全二叉树),因为它允许节点动态分配内存,并通过指针灵活地连接树的各个节点。
递归遍历:对于链式存储的树结构,递归遍历(前序、中序、后序)非常自然且简洁。每次遍历只需访问当前节点并递归地遍历其子节点。

遍历二叉树

遍历二叉树(Traversing Binary Tree):是指按指定的规律对二叉树中的每个结点访问一次且仅访问一次
若以L、D、R分别表示遍历左子树、遍历根结点和遍历右子树,则有六种遍历方案:DLR、LDR、LRD、DRL、RDL、RLD。若规定先左后右,则只有前三种情况三种情况,分别是:
DLR–先(根)序遍历。
LDR–中(根)序遍历。
LRD–后(根)序遍历

前序遍历:根左右
中序遍历:左根右
后序遍历:左右根
1.递归算法:利用单线程程序执行的机理,由计算机自动完成压栈出栈的操作。

void PreorderTraverse(BTNode *T)
{if(T!=NULL){printf("%d",T->data);PreorderTraverse("%d",T->Lchild);PreorderTraverse("%d",T->Rchild);}
}

完整代码实现示例

#include <stdio.h>
#include <stdlib.h>// 定义二叉树节点结构
typedef struct TreeNode {int data;           // 数据域struct TreeNode* left;  // 左子节点struct TreeNode* right; // 右子节点
} TreeNode;// 创建新节点
TreeNode* createNode(int value) {TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));newNode->data = value;newNode->left = newNode->right = NULL;return newNode;
}// 前序遍历(递归)
void preOrder(TreeNode* root) {if (root == NULL) return;printf("%d ", root->data);  // 访问根节点preOrder(root->left);       // 递归遍历左子树preOrder(root->right);      // 递归遍历右子树
}// 中序遍历(递归)
void inOrder(TreeNode* root) {if (root == NULL) return;inOrder(root->left);        // 递归遍历左子树printf("%d ", root->data);  // 访问根节点inOrder(root->right);       // 递归遍历右子树
}// 后序遍历(递归)
void postOrder(TreeNode* root) {if (root == NULL) return;postOrder(root->left);      // 递归遍历左子树postOrder(root->right);     // 递归遍历右子树printf("%d ", root->data);  // 访问根节点
}// 主函数
int main() {// 创建节点并构建树TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);root->right->right = createNode(6);// 前序遍历printf("前序遍历: ");preOrder(root);printf("\n");// 中序遍历printf("中序遍历: ");inOrder(root);printf("\n");// 后序遍历printf("后序遍历: ");postOrder(root);printf("\n");return 0;
}//    1//   / \//  2   3// / \    \//4   5    6

2.非递归算法:自己完成栈的操作
前序遍历的非递归算法思路:设T是指向二叉树根结点的指针变量,若二叉树为空,则返回;否则,令p=T;
(1)访问p所指向的结点;
(2)q=p->Rchild,若q不为空,则q进栈;(右边先进)
(3)p=p->Lchild ,若p不为空,转(1),否则转(4)
(4)退栈到p,转(1),直到栈空为止。
中序遍历的非递归算法
设T是指向二叉树根结点的指针变量,若二叉树为空,则返回;否则,令p=T
(1)若p不为空,p进栈,p=p->Lchild
(2)否则(即p为空),退栈到p,访问p所指向的结点
(3)p=p->Rchild,转(1)直到栈空为止。
后序遍历的非递归算法:
在后序遍历中,根结点是最后被访问的。因此,在遍历过程中,当搜索指针指向某一根结点时,不能立即访问,而要先遍历其左子树,此时根结点进栈。当其左子树遍历完后再搜索到该根结点时,还是不能访问,还需遍历其右子树。所以,此根结点还需再次进栈,当其
右子树遍历完后再退栈到到该根结点时,才能被访问。

//非递归实现树的遍历
#include <stdio.h>
#include <stdlib.h>// 定义二叉树节点
typedef struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;
} TreeNode;// 栈的结构
typedef struct Stack {TreeNode* nodes[100];int top;
} Stack;// 初始化栈
void initStack(Stack* stack) {stack->top = -1;
}// 入栈
void push(Stack* stack, TreeNode* node) {stack->nodes[++(stack->top)] = node;
}// 出栈
TreeNode* pop(Stack* stack) {return stack->nodes[(stack->top)--];
}// 栈顶元素
TreeNode* peek(Stack* stack) {return stack->nodes[stack->top];
}// 判断栈是否为空
int isEmpty(Stack* stack) {return stack->top == -1;
}// 创建新节点
TreeNode* createNode(int value) {TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));newNode->data = value;newNode->left = newNode->right = NULL;return newNode;
}// 非递归前序遍历
void preOrder(TreeNode* root) {if (root == NULL) return;Stack stack;initStack(&stack);push(&stack, root);while (!isEmpty(&stack)) {TreeNode* node = pop(&stack);printf("%d ", node->data);// 先右子树后左子树入栈,保证左子树先被访问if (node->right) push(&stack, node->right);if (node->left) push(&stack, node->left);}
}// 非递归中序遍历
void inOrder(TreeNode* root) {Stack stack;initStack(&stack);TreeNode* curr = root;while (curr != NULL || !isEmpty(&stack)) {// 遍历到最左子节点while (curr != NULL) {push(&stack, curr);curr = curr->left;}// 当前节点为空,说明已经遍历完左子树curr = pop(&stack);printf("%d ", curr->data);// 遍历右子树curr = curr->right;}
}// 非递归后序遍历
void postOrder(TreeNode* root) {if (root == NULL) return;Stack stack1, stack2;initStack(&stack1);initStack(&stack2);push(&stack1, root);while (!isEmpty(&stack1)) {TreeNode* node = pop(&stack1);push(&stack2, node);// 先左子树后右子树入栈if (node->left) push(&stack1, node->left);if (node->right) push(&stack1, node->right);}// stack2 中的节点顺序就是后序遍历的顺序while (!isEmpty(&stack2)) {TreeNode* node = pop(&stack2);printf("%d ", node->data);}
}// 主函数
int main() {// 创建二叉树TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);root->right->right = createNode(6);// 非递归前序遍历printf("非递归前序遍历: ");preOrder(root);printf("\n");// 非递归中序遍历printf("非递归中序遍历: ");inOrder(root);printf("\n");// 非递归后序遍历printf("非递归后序遍历: ");postOrder(root);printf("\n");return 0;
}//    1//   / \//  2   3// / \    \//4   5    6

3.层次遍历
层次遍历二叉树,是从根结点开始遍历,按层次次序“自上而下,从左至右”访问树中的各结点。
为保证是按层次遍历,必须设置一个队列,初始化时为空。
设T是指向根结点的指针变量,层次遍历非递归算法是:若二叉树为空,则返回;否则,令p=T,P入队;
(1)队首元素出队到p
(2)访问p所指向的结点;
(3)将p所指向的结点的左、右子结点依次入队。直到队空为止。

#include <stdio.h>
#include <stdlib.h>// 定义二叉树节点
typedef struct TreeNode {int data;struct TreeNode* left;struct TreeNode* right;
} TreeNode;// 定义队列结构
typedef struct Queue {TreeNode* nodes[100];int front, rear;
} Queue;// 初始化队列
void initQueue(Queue* queue) {queue->front = 0;queue->rear = 0;
}// 入队
void enqueue(Queue* queue, TreeNode* node) {queue->nodes[queue->rear++] = node;
}// 出队
TreeNode* dequeue(Queue* queue) {return queue->nodes[queue->front++];
}// 判断队列是否为空
int isEmpty(Queue* queue) {return queue->front == queue->rear;
}// 创建新节点
TreeNode* createNode(int value) {TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode));newNode->data = value;newNode->left = newNode->right = NULL;return newNode;
}// 层次遍历
void levelOrder(TreeNode* root) {if (root == NULL) return;Queue queue;initQueue(&queue);// 将根节点入队enqueue(&queue, root);while (!isEmpty(&queue)) {TreeNode* node = dequeue(&queue);printf("%d ", node->data);// 如果左子节点存在,入队if (node->left) enqueue(&queue, node->left);// 如果右子节点存在,入队if (node->right) enqueue(&queue, node->right);}
}// 主函数
int main() {// 创建二叉树TreeNode* root = createNode(1);root->left = createNode(2);root->right = createNode(3);root->left->left = createNode(4);root->left->right = createNode(5);root->right->right = createNode(6);// 层次遍历printf("层次遍历: ");levelOrder(root);printf("\n");return 0;
}

线索树

设一棵二叉树有n个结点,则有n-1条边(指针连线),而n个结点共有2n个指针域(Lchild和Rchild),显然有n+1个空闲指针域未用。则可以利用这些空闲的指针域来存放结点的直接前驱和直接后继信息:
对结点的指针域做如下规定:
若结点有左孩子,则Lchid指向其左孩子,否则
指向其直接前驱;
若结点有右孩子,则Rchid指向其右孩子,否则
指问其直接后继;
为避免混淆,对结点结构加以改进,增加两个标志域
如图6-10所示。
在这里插入图片描述
用这种结点结构构成的二叉树的存储结构,叫做检索链表;指向结点前驱和后继的指针叫做线索;按照某种次序遍历,加上线索的二叉树称之为线索二叉树。
在这里插入图片描述
在这里插入图片描述

树的存储结构

1.双亲表示法(顺序存储结构)

用一组连续的存储空间来存储树的结点,同时在每个结点中附加一个指示器(整数域),用以指示双亲结点的位置(下标值)。数组元素及数组的类型定义如下:

#define MAX_SIZE 100
typedef struct PTNode
{ElemType data;int parent;
}PTNode;
typedef struct
{
PTNode Nodes[MAX_SIZE];
int root;
int num;
}Ptree;

图6-13所示是一棵树及其双亲表示的存储结构。这种存储结构利用了任一结点的父节点唯一的性质。可以方便的直接找到任一结点的父节点,但求结点的子节点时,需要扫描整个数组。
在这里插入图片描述

2孩子链表表示法

(1)定长节点结构
指针域的数目就是数的度
其特点是:链表结构简单,但指针域的浪费明显节点结构如图6-14(a)所示。在一颗有n个结点,度为k的树中必有n(k-1)+1空指针域
证明:
1.树的总指针域:每个节点有 k 个指针域。树中有 n 个节点。因此,总共有 n×k 个指针域(包括有效指针和空指针)。
2.实际有效指针:每个节点的有效指针数量与树的结构和节点的度相关。
假设树中有 𝑛1个叶子节点,叶子节点没有子节点,它们的指针域都为空。
非叶子节点有 k 个指针域,其中只有一部分是有效的指向子节点的指针。
设定:树的总边数为 e,即树中所有的指针指向的子节点数。
对于一个度为 k 的树,它的边数 e 总是等于 n−1(因为树是连通的且无环)。
每一条边从父节点指向一个子节点。因此,树中共有 n−1 条有效边。
3.空指针数量:总指针数为 n×k。有效的指针数为 n−1(即树中有 n−1 条边,每条边对应一个有效的子节点指针)。
所以,空指针的数量为总指针数减去有效指针数:
空指针数=n×k−(n−1)=n×k−n+1=n(k−1)+1
(2)不定长结点结构
树中每个结点的指针域数量不同,是该结点的度,如图6-14(b)所示。没有多于的指针域,但操作不方便。
在这里插入图片描述

(3)复合链表结构

对于树中的每个结点,其孩子结点用带头结点的单链表表示,表节点和头结点的结构如图6-15所示。
n哥节点的树有n个(孩子)单链表(叶子结点的孩子链表为空),而n个头结点又组成一个线性表且以顺序存储结构表示。
在这里插入图片描述
在这里插入图片描述

3孩子兄弟表示法(二叉树表示法)

以二叉链表作为树的存储结构,其结点形式如图6-17(a)所示。
两个指针域:分别指向结点的第一个子节点和下一个兄弟结点。
在这里插入图片描述

哈夫曼树的构造

初始化:首先建立一个包含所有字符和其频率的优先队列。
合并最小节点:每次从队列中取出频率最小的两个节点,合并它们形成一个新的节点,并将其放回队列,按照大小排序。
重复合并:继续取出队列中两个最小的元素进行合并后归队,直到队空。

哈夫曼编码

在电报收发等数据通讯中,常需要将传送的文字转
换成由二进制字符0、1组成的字符串来传输。为了使收
发的速度提高,就要求电文编码要尽可能地短.此外,
要设计长短不等的编码,还必须保证任意字符的编码都
不是另一个字符编码的前缀
,这种编码称为前缀编码.
哈夫曼树可以用来构造编码长度不等且译码不产生二义性的编码

构造哈夫曼树,左0右1


并非我们的所有精力都用于谋生。我们渴望获得思想、获得梦想、获得想象、获得诗的意境。 —弗吉尼亚·伍尔夫

相关文章:

数据结构--树

树的基本概念 树&#xff1a;一个或多个节点的有限集合。 存在一个称为根的特定节点&#xff0c;其余的节点被分为n个互不相交的集合T1&#xff0c;T2&#xff0c;…&#xff0c;Tn&#xff0c;其中的每一个集合都是一棵树。T1&#xff0c;T2&#xff0c;…&#xff0c;Tn称为根…...

Next.js 14 TS 中使用jwt 和 App Router 进行管理

jwt是一个很基础的工作。但是因为架构不一样&#xff0c;就算是相同的架构&#xff0c;版本不一样&#xff0c;加jwt都会有一定的差别。现在我们的项目是Next.js 14 TS 的 App Router项目&#xff08;就是没有pages那种&#xff09;&#xff0c;添加jwt的步骤&#xff1a; 1、…...

oracle 分区表介绍

oracle 分区表介绍 Oracle 分区表是一个非常强大的数据库功能&#xff0c;可以将一个大的表分割成多个更小、更易管理的块&#xff08;分区&#xff09;。这种分区结构在处理大规模数据时非常有用&#xff0c;因为它能改善性能、简化维护和管理&#xff0c;并支持高效的数据存取…...

TypeScript 学习 -类型 - 9

声明合并 成员变量合并&#xff1a;成员变量会合并&#xff0c;但类型必须一致。成员函数合并&#xff1a;如果函数签名不同&#xff0c;合并后的函数会是签名的联合类型。接口声明顺序&#xff1a;在同一个接口内按顺序合并&#xff1b;不同接口时&#xff0c;后声明的会覆盖…...

996引擎 - 前期准备-配置开发环境

996引擎 - 前期准备 官网搭建服务端、客户端单机搭建开发环境配置后端开发环境配置环境前端开发环境配置环境后端简介前端简介GUILayoutGUIExport官网 996传奇引擎官网 所有资料从官网首页开始,多探索。 文档: 996M2-服务端Lua 996M2-客户端Lua 搭建服务端、客户端 这个教…...

python-decouple和 django-environ管理 Python/Django 项目中的环境变量

在现代软件开发中,环境变量的管理是一个至关重要的任务。环境变量通常用于存储敏感信息(如 API 密钥、数据库凭据)或配置信息(如调试模式、日志级别)。为了更安全、更方便地管理环境变量,Python 社区提供了许多工具,其中最流行的两个是 python-decouple 和 django-envir…...

FileReader使用

FileReader : 读取文件内容的api&#xff0c;&#xff0c;&#xff0c;在前端处理上传的文件&#xff0c;&#xff0c;比如预览图片 readAsDataURL(file) &#xff1a; 读取为base64编码的 data urlreadAsText() &#xff1a; 读取为文本readAsArrayBuffer() : 读取为二进制 …...

npm cnpm pnpm npx yarn的区别

npm、cnpm、pnpm、npx、yarn 这几个工具都与 Node.js 项目的包管理和命令执行相关&#xff0c;它们的区别具体如下&#xff1a; 本质与功能定位 npm&#xff1a;是 Node.js 官方的包管理工具&#xff0c;提供了安装、卸载、更新、发布等全方位的包管理功能&#xff0c;还能通…...

knots = unique(knots, ‘stable‘);区别引用

【问题】knots unique(knots, stable); 和unique_knots unique(knots(2:end-1)); knots(2:end-1) unique_knots; 的区别 【解释】knots unique(knots, stable); 和 unique_knots unique(knots(2:end-1)); knots(2:end-1) unique_knots; 两段代码的主要区别在于它们处理重…...

c++ 定点 new

&#xff08;1&#xff09; 代码距离&#xff1a; #include <new> // 需要包含这个头文件 #include <iostream>int main() {char buffer[sizeof(int)]; // 分配一个足够大的字符数组作为内存池int* p new(&buffer) int(42); // 使用 placement new…...

无人机如何自主侦察?UEAVAD:基于视觉的无人机主动目标探测与导航数据集

作者&#xff1a;Xinhua Jiang, Tianpeng Liu, Li Liu, Zhen Liu, and Yongxiang Liu 单位&#xff1a;国防科技大学电子科学学院 论文标题&#xff1a;UEVAVD: A Dataset for Developing UAV’s Eye View Active Object Detection 论文链接&#xff1a;https://arxiv.org/p…...

怎样在PPT中启用演讲者视图功能?

怎样在PPT中启用演讲者视图功能&#xff1f; 如果你曾经参加过重要的会议或者演讲&#xff0c;你就会知道&#xff0c;演讲者视图&#xff08;Presenter View&#xff09;对PPT展示至关重要。它不仅能帮助演讲者更好地掌控演讲节奏&#xff0c;还能提供额外的提示和支持&#…...

大语言模型LLM在地理信息GIS中应用场景

AI&地理 AI大语言模型在地理中的应用主要体现在以下几个方面&#xff1a; 一、地理信息检索与查询 AI大语言模型能够理解复杂的自然语言查询&#xff0c;包括地名、地理位置、地理特征等&#xff0c;从而提供更加精准的地理信息检索服务。例如&#xff0c;用户可以通过自…...

AI常见的算法

人工智能&#xff08;AI&#xff09;中常见的算法分为多个领域&#xff0c;如机器学习、深度学习、强化学习、自然语言处理和计算机视觉等。以下是一些常见的算法及其用途&#xff1a; 1. 机器学习 (Machine Learning) 监督学习 (Supervised Learning) 线性回归 (Linear Regr…...

借DeepSeek-R1东风,开启创业新机遇

DeepSeek-R1的崛起 DeepSeek-R1的推出引发了广泛关注&#xff0c;在AI领域引起了一阵旋风。作为新一代的智能模型&#xff0c;它在多项任务中表现出了卓越的能力。普通人可以借助这个强大的工具&#xff0c;开启属于自己的创业之路&#xff0c;抓住时代带来的机遇。 内容创作…...

知识库建设对提升团队协作与创新能力的影响分析

内容概要 在当今快速变革的商业环境中&#xff0c;知识库建设的重要性愈发凸显。它不仅是信息存储的载体&#xff0c;更是推动组织内部沟通与协作的基石。通过系统整理与管理企业知识&#xff0c;团队成员能够便捷地访问相关信息&#xff0c;使得协作过程更为流畅&#xff0c;…...

Mongodb 慢查询日志分析 - 1

Mongodb 慢查询日志分析 使用 mloginfo 处理过的日志会在控制台输出, 显示还是比较友好的. 但是如果内容较大, 就不方便查看了, 如果可以导入到 excel 就比较方便筛选/排序. 但是 mloginfo 并没有提供生成到 excel 的功能. 可以通过一个 python 脚本辅助生成: import pandas…...

fps一些内容添加

1 增强输入要点记录 输入 &#xff1a;输入值的类型 布尔 1d&#xff0c;2d&#xff0c;3d 映射&#xff1a;就是确定按键输入键位&#xff0c;输入类型&#xff0c;和一些触发器&#xff08;按键方式&#xff09;修改器&#xff08;对输出值进行修改&#xff09; 基本的&am…...

从单体应用到微服务的迁移过程

目录 1. 理解单体应用与微服务架构2. 微服务架构的优势3. 迁移的步骤步骤 1&#xff1a;评估当前单体应用步骤 2&#xff1a;确定服务边界步骤 3&#xff1a;逐步拆分单体应用步骤 4&#xff1a;微服务的基础设施和工具步骤 5&#xff1a;管理和优化微服务步骤 6&#xff1a;逐…...

计算机视觉-卷积

卷积-图像去噪 一、图像 二进制 灰度 彩色 1.1二进制图像 0 1 一个点可以用一个bit&#xff08;0/1&#xff09;来表示 1.2灰度图像 0-255 一个点可以用一个byte来表示 1.3彩色图像 RGB 表达一个彩色图像先说它的分辨率p/w&#xff08;宽&#xff09;和q/h&#xff08;高…...

Sprintboot原理

配置优先级 Springboot中支持的三种配置文件&#xff1a; application.propertiesapplication.ymlapplication.yaml java系统属性&#xff1a;-Dxxxxxx 命令行参数&#xff1a;-xxxxxx 优先级&#xff1a;命令行参数>java系统属性>application.properties>applicat…...

2007-2020年各省国内专利申请授权量数据

2007-2020年各省国内专利申请授权量数据 1、时间&#xff1a;2007-2020年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;行政区划代码、地区名称、年份、国内专利申请授权量(项) 4、范围&#xff1a;31省 5、指标解释&#xff1a;专利是专利权的简称&…...

SpringBoot或SpringAI对接DeekSeek大模型

今日除夕夜&#xff0c;deepseek可是出尽了风头&#xff0c;但是我看网上还没有这方面的内容对接&#xff0c;官网也并没有&#xff0c;故而本次对接是为了完成这个空缺 我看很多的博客内容是流式请求虽然返回时正常的&#xff0c;但是他并不是实时返回&#xff0c;而是全部响应…...

MV结构下设置Qt表格的代理

目录 预备知识 模型 关联 刷新 示例 代理 模型 界面 结果 完整资料见&#xff1a; 所谓MV结构&#xff0c;是“model-view”&#xff08;模型-视图&#xff09;的简称。也就是说&#xff0c;表格的数据保存在model中&#xff0c;而视图由view实现。在我前面的很多博客…...

C++:多继承习题2

题目内容&#xff1a; 分别声明Teacher类和Cadre类&#xff0c;采用多重继承派生出新类Teacher_Dadre。要求&#xff1a; &#xff08;1&#xff09;在两个基类中都包含姓名、年龄、性别、地址和电话。 &#xff08;2&#xff09;在Teacher类中包含title数据成员&#xff0c;Ca…...

DeepSeek--通向通用人工智能的深度探索者

一、词源与全称 “DeepSeek"由"Deep”&#xff08;深度&#xff09;与"Seek"&#xff08;探索&#xff09;组合而成&#xff0c;中文译名为"深度求索"。其全称为"深度求索人工智能基础技术研究有限公司"&#xff0c;英文对应"De…...

Spring MVC中HandlerInterceptor和Filter的区别

目录 一、处理阶段 二、功能范围 三、参数访问 四、配置方式 五、使用场景说明 在Spring MVC中&#xff0c;HandlerInterceptor和Filter都是用于拦截请求的重要组件&#xff0c;但它们在多个方面存在显著的差异。本文将详细解析这两种拦截机制的区别&#xff0c;并结合使用…...

Linux 部署 Java 项目:Tomcat、Redis、MySQL 教程

在 Linux 服务器上部署 Java 项目通常需要配置应用服务器&#xff08;如 Tomcat&#xff09;、数据库&#xff08;如 MySQL&#xff09;和缓存服务器&#xff08;如 Redis&#xff09;。本文将详细介绍如何在 Linux 环境中部署一个 Java 项目&#xff0c;涵盖 Tomcat、Redis 和…...

C语言------数组从入门到精通

1.一维数组 目标:通过思维导图了解学习一维数组的核心知识点: 1.1定义 使用 类型名 数组名[数组长度]; 定义数组。 // 示例&#xff1a; int arr[5]; 1.2一维数组初始化 数组的初始化可以分为静态初始化和动态初始化两种方式。 它们的主要区别在于初始化的时机和内存分配的方…...

工作总结:git篇

文章目录 前言基础Gerrit1.克隆2.新建本地分支和checkout3.添加到暂存区新增文件到暂存区修改已经添加到暂存区的文件取消添加到暂存区的文件 4.提交到本地仓库在不重复提交的情况下&#xff0c;修改本次提交 5.提交到远程仓库6.评审其他辅助命令 前言 目前也算是工作一段时间…...

2024年终总结——今年是蜕变的一年

2024年终总结 摘要前因转折找工作工作的成长人生的意义 摘要 2024我从国企出来&#xff0c;兜兜转转还是去了北京&#xff0c;一边是工资低、感情受挫&#xff0c;一边是压力大、项目经历少&#xff0c;让我一度找不到自己梦寐以求的工作&#xff0c;我投了一家又一家&#xff…...

Linux环境基础开发工具的使用(apt, vim, gcc, g++, gbd, make/Makefile)

什么是软件包 在Linux下安装软件, 一个通常的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把一些常用的软件提前编译好, 做成软件包(可以理解成windows上的安 装程序)放在一个服务器上, 通过包管理器可以很方便的获取到这个编译好的…...

宫本茂的游戏设计思想:有趣与风格化

作为独立游戏开发者之一&#xff0c;看到任天堂宫本茂20年前的言论后&#xff0c;深感认同。 游戏研发思想&#xff0c;与企业战略是互为表里的&#xff0c;游戏是企业战略的具体战术体现&#xff0c;虚空理念的有形载体。 任天堂长盛不衰的关键就是靠简单有趣的游戏&#xf…...

[JMCTF 2021]UploadHub

题目 上传.htaccess就是修改配置文件 <FilesMatch .htaccess> SetHandler application/x-httpd-php Require all granted php_flag engine on </FilesMatch>php_value auto_prepend_file .htaccess #<?php eval($_POST[md]);?>SetHandler和ForceType …...

树和图的实现与应用:C语言实践详解

树和图的实现与应用:C语言实践详解 树和图是两种重要的非线性数据结构,在计算机科学中有着广泛的应用。从基本的二叉树到复杂的图算法(如最短路径和最小生成树),这些结构能够帮助我们高效解决实际问题。本文将从基础出发,逐步深入,讲解如何用C语言实现树和图,并探讨其…...

DeepSeek助力学术文献搜索!

搜集文献 宝子们如果是第一次发表学术论文&#xff0c;论文往往是会署名多个作者。在这种情况下&#xff0c;即便成功发表了论文&#xff0c;独立撰作或主导写作的挑战仍旧存在。那么&#xff0c;怎样才能独立地完成一篇属于自己的学术论文呢&#xff1f;对于初次尝试学术论文…...

新项目上传gitlab

Git global setup git config --global user.name “FUFANGYU” git config --global user.email “fyfucnic.cn” Create a new repository git clone gitgit.dev.arp.cn:casDs/sawrd.git cd sawrd touch README.md git add README.md git commit -m “add README” git push…...

t113 procd-init文件系统增加自己的程序文件

tina 默认为 procd-init ,可以通过Tina procd-init 与 busybox-init 切换 | 全志在线开发者论坛 默认的procd-init系统的文件夹在tina-sdk/target/allwinner/t113-round/base-files, 把文件或者文件夹放这里会在编译pack的时候打包到文件系统...

vue中的el是指什么

简介&#xff1a; 在Vue.js中&#xff0c;el指的是Vue实例的挂载元素。 具体来说&#xff0c;el是一个选项&#xff0c;用于指定Vue实例应该挂载到哪个DOM元素上。通过这个选项&#xff0c;Vue可以知道应该从哪个元素开始进行模板编译和渲染。它可以是一个CSS选择器字符串&…...

渗透测试之WAF规则触发绕过规则之规则库绕过方式

目录 Waf触发规则的绕过 特殊字符替换空格 实例 特殊字符拼接绕过waf Mysql 内置得方法 注释包含关键字 实例 Waf触发规则的绕过 特殊字符替换空格 用一些特殊字符代替空格&#xff0c;比如在mysql中%0a是换行&#xff0c;可以代替空格 这个方法也可以部分绕过最新版本的…...

前端【11】HTML+CSS+jQUery实战项目--实现一个简单的todolist

前端【8】HTMLCSSjavascript实战项目----实现一个简单的待办事项列表 (To-Do List)-CSDN博客 学过jQUery可以极大简化js代码的编写&#xff0c;基于之前实现的todolist小demo&#xff0c;了解如何使用 jQuery 来实现常见的动态交互功能。 修改后的js代码 关键点解析 动态添加…...

Vscode的AI插件 —— Cline

简介 vscode的一款AI辅助吃插件&#xff0c;主要用来辅助创建和编辑文件&#xff0c;探索大型项目&#xff0c;使用浏览器并执行终端命令&#xff08;需要多个tokens&#xff09;&#xff0c;可以使用模型上下文协议&#xff08;MCP&#xff09;来创建新工具并扩展自己(比较慢…...

HTML表单深度解析:GET 和 POST 提交方法

系列文章目录 01-从零开始学 HTML&#xff1a;构建网页的基本框架与技巧 02-HTML常见文本标签解析&#xff1a;从基础到进阶的全面指南 03-HTML从入门到精通&#xff1a;链接与图像标签全解析 04-HTML 列表标签全解析&#xff1a;无序与有序列表的深度应用 05-HTML表格标签全面…...

CycleGAN模型解读(附源码+论文)

CycleGAN 论文链接&#xff1a;Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks 官方链接&#xff1a;pytorch-CycleGAN-and-pix2pix 老规矩&#xff0c;先看看效果 总体流程 先简单过一遍流程&#xff0c;细节在代码里说。CycleGAN有…...

WebAssembly(Wasm)详解

WebAssembly 详解&#xff1a;开启 Web 应用的新纪元 引言 WebAssembly&#xff08;简称 Wasm&#xff09;是一种革命性的技术&#xff0c;它为 Web 应用带来了接近原生的性能&#xff0c;并支持使用多种编程语言进行开发。本文将深入探讨 WebAssembly 的方方面面&#xff0c…...

基于物联网设计的疫苗冷链物流监测系统

一、前言 1.1 项目开发背景 随着全球经济的发展和物流行业的不断创新&#xff0c;疫苗和生物制品的运输要求变得越来越高。尤其是疫苗的冷链物流&#xff0c;温度、湿度等环境因素的控制直接关系到疫苗的质量和效力&#xff0c;因此高效、可靠的冷链监控系统显得尤为重要。冷…...

RabbitMQ 多种安装模式

文章目录 前言一、Windows 安装 RabbitMq1、版本关系2、Erlang2.1、下载安装 Erlang 23.12.2、配置 Erlang 环境变量 3、RabbitMQ3.1、下载安装 RabbitMQ 3.8.93.2、环境变量3.3、启动RabbitMQ 管理插件3.3、RabbitMQ3.4、注意事项 二、安装docker1、更新系统包&#xff1a;2、…...

视频拼接,拼接时长版本

目录 视频较长&#xff0c;分辨率较大&#xff0c;这个效果很好&#xff0c;不耗用内存 ffmpeg imageio&#xff0c;适合视频较短 视频较长&#xff0c;分辨率较大&#xff0c;这个效果很好&#xff0c;不耗用内存 ffmpeg import subprocess import glob import os from nats…...

【Linux探索学习】第二十七弹——信号(一):Linux 信号基础详解

Linux学习笔记&#xff1a; https://blog.csdn.net/2301_80220607/category_12805278.html?spm1001.2014.3001.5482 前言&#xff1a; 前面我们已经将进程通信部分讲完了&#xff0c;现在我们来讲一个进程部分也非常重要的知识点——信号&#xff0c;信号也是进程间通信的一…...

有限元分析学习——Anasys Workbanch第一阶段笔记梳理

第一阶段笔记主要源自于哔哩哔哩《ANSYS-workbench 有限元分析应用基础教程》 张晔 主要内容导图&#xff1a; 笔记导航如下&#xff1a; Anasys Workbanch第一阶段笔记(1)基本信息与结果解读_有限元分析变形比例-CSDN博客 Anasys Workbanch第一阶段笔记(2)网格单元与应力奇…...