数据结构~~链式二叉树

目录

一、基本概念

链式存储概念

 二、链式二叉树的结构

链式二叉树结构

构建链式二叉树

二叉树的遍历

 二叉树节点和高度等

 二叉树销毁

三、链式二叉树的练习

相同的树 

对称二叉树

 另外一颗子树

二叉树前序遍历 

 二叉树遍历

四、完整代码

Tree.h

Tree.c

五、总结


一、基本概念

链式二叉树是一种常见的数据结构,它是用链表结点来存储二叉树中的每一个结点,结点结构通常包括数据域和若干个指针域。其中,指针域用于指向左孩子结点和右孩子结点。

对于那些非完全二叉树,由于顺序存储结构的空间利用率低,因此二叉树一般都采用链式存储结构。在链式二叉树中,根据指针的数量可以分为二叉链和三叉链两种结构。二叉链的结点包含存储数据的变量、存储左孩子的指针以及存储右孩子的指针;而三叉链的结点除了包含存储数据的变量、存储左孩子的指针以及存储右孩子的指针,还包含存储双亲的指针。

二叉树的遍历是指按某条搜索路径访问树中每个结点,使得每个结点均被访问一次,而且仅被访问一次。根据访问根结点的顺序不同可以分为前序遍历、中序遍历和后序遍历。

链式存储概念

链式存储二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是 链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所 在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们学习中一般都是二叉链。

 二、链式二叉树的结构

链式二叉树结构

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;struct BinaryTreeNode* _left;struct BinaryTreeNode* _right;
}BTNode;

构建链式二叉树

int类型  手撕构建方便前期调试

BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc err");return NULL;}newnode->_data = x;newnode->_left = NULL;newnode->_right = NULL;return newnode;
}//123nn4n5nn67nn8nn  通过前序遍历构建
BTNode* BinaryTreeCreate()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);BTNode* node8 = BuyNode(8);node1->_left = node2;node1->_right = node6;node2->_left = node3;node2->_right = node4;node4->_right = node5;node6->_left = node7;node6->_right = node8;return node1;
}

char数组类型

// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreateChar(BTDataType* a, int* pi)
{if (a[(*pi)] == '#'){(*pi)++;return NULL;}BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc err");return NULL;}newnode->_data = a[(*pi)++];newnode->_left = BinaryTreeCreateChar(a, pi);newnode->_right = BinaryTreeCreateChar(a, pi);return newnode;
}

二叉树的遍历

前序:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。

前序遍历递归图解:

// 二叉树前序遍历
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}

中序:中序遍历(Inorder Traversal)——访问根结点的操作发生在遍历其左右子树之中(间)

// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}BinaryTreeInOrder(root->_left);printf("%d ",root->_data);BinaryTreeInOrder(root->_right);
}

后序:后序遍历(Postorder Traversal)——访问根结点的操作发生在遍历其左右子树之后

// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%d ",root->_data);
}

 层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在 层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层 上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

// 层序遍历
#include"Queue.h"
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* Fout = QueueFront(&q);QueuePop(&q);printf("%d ",Fout->_data);if (Fout->_left){QueuePush(&q,Fout->_left);}if (Fout->_right){QueuePush(&q, Fout->_right);}}QueueDestroy(&q);
}

判断二叉树是否是完全二叉树

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

 二叉树节点和高度等

1.二叉树节点个数 

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

2.二叉树叶子节点个数

// 二叉树叶子节点个数
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);
}

3.二叉树的最大高度

//二叉树的最大高度
int TreeHeight(BTNode* root) 
{if (root == NULL)return 0;int node_left=TreeHeight(root->_left); int node_right = TreeHeight(root->_right);return node_left > node_right ? node_left + 1 : node_right + 1;
}

4.二叉树第k层节点个数

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

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

// 二叉树查找值为x的节点
BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
{if (root == NULL)return NULL;if (root->_data == 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;}

 二叉树销毁

// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*(root) == NULL)return;BinaryTreeDestory(&(*root)->_left);BinaryTreeDestory(&(*root)->_right);free(*(root));
}

三、链式二叉树的练习

相同的树 

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

思路:  可以通过递归的方式同时遍历两棵树。

比较两棵树的根节点值是否相等,如果不相等则直接返回 false。

然后递归地对左子树和右子树分别进行相同的比较,只有当左右子树在相应位置上都相同的时候才返回 true。

在递归过程中,只要有一处不满足相同条件就可以立即返回 false,只有所有节点和结构都完全一致才能最终返回 true。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
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);
}

对称二叉树

给你一个二叉树的根节点 root , 检查它是否轴对称。 

思路:

采用递归的方法。

一个二叉树是轴对称的,意味着对于任意一个节点,它的左子树和右子树是镜像对称的。

具体来说,就是对于当前节点,它的左子节点和右子节点的值相等(如果都存在的话),并且左子节点的左子树和右子节点的右子树对称,左子节点的右子树和右子节点的左子树也对称。我们通过递归地比较左右子树的对应节点来判断整个二叉树是否对称。如果在递归过程中发现不满足对称条件的情况,就可以返回 false,如果递归完整棵树都满足,则返回 true。

 * Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
bool _isSymmetric(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 _isSymmetric(p->left, q->right)&&_isSymmetric(p->right, q->left);
}
bool isSymmetric(struct TreeNode* root) {return _isSymmetric(root->left, root->right);
}

 另外一颗子树

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

思路

我们可以从根节点开始,对主树 root 进行先序遍历。

在遍历过程中,每当遇到一个节点,就判断以这个节点为根的子树是否与 subRoot 完全相同。

为了判断子树是否相同,可以编写一个辅助函数来比较两棵树是否完全一致,这与前面判断两棵树是否相同的思路类似,即同时递归地检查节点值以及左右子树的结构和节点值是否匹配。如果找到匹配的子树,就返回 true,否则继续遍历主树的其他节点。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/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 &&isSameTree(root,subRoot))return true;return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}

二叉树前序遍历 

给你二叉树的根节点 root ,返回它节点值的 前序 遍历。

思路:

首先访问根节点,然后递归地对左子树进行前序遍历,最后递归地对右子树进行前序遍历。

具体来说,我们可以使用一个辅助函数,在这个函数中先输出当前节点的值,然后如果左子树存在就对左子树调用该函数进行递归遍历,接着如果右子树存在就对右子树调用该函数进行递归遍历。这样就可以按照前序遍历的顺序输出所有节点的值。

/*** Definition for a binary tree node.* struct TreeNode {*     int val;*     struct TreeNode *left;*     struct TreeNode *right;* };*/
/*** Note: The returned array must be malloced, assume caller calls free().*/
int TreeSize(struct TreeNode* root) {return root == NULL ? 0 : TreeSize(root->left) + TreeSize(root->right) + 1;
}
void PrevOrder(struct TreeNode* root,int* a,int* i)
{if(root==NULL)return;a[(*i)++]=root->val;PrevOrder(root->left,a,i);PrevOrder(root->right,a,i);
}
int* preorderTraversal(struct TreeNode* root, int* returnSize) 
{* returnSize=TreeSize(root);int* a=(int*)malloc(sizeof(int)*(*returnSize));int i = 0;PrevOrder(root,a,&i);return a;
}

 二叉树遍历

编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

输入描述:

输入包括1行字符串,长度不超过100。

输出描述:

可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。

思路:

1. 定义二叉树节点结构体:包含节点值以及左右子节点指针。

2. 构建二叉树函数:通过遍历输入的先序遍历字符串来构建二叉树。使用一个静态索引来跟踪当前处理的字符位置。如果遇到非'#'字符,就创建一个新节点,然后递归地构建左子树和右子树,遇到'#'则表示空节点。

3. 中序遍历函数:按照中序遍历的顺序(先左子树、当前节点、再右子树)输出节点值并添加空格。

4. 在主程序中,获取用户输入的字符串,调用构建二叉树函数得到二叉树,然后调用中序遍历函数输出结果。

#include<stdio.h>
#include<stdlib.h>typedef struct Tree {struct Tree* le;struct Tree* ri;int val;
} BTNode;void PrevInor(BTNode* root) 
{if (root == NULL)return;PrevInor(root->le);printf("%c ", root->val);PrevInor(root->ri);
}BTNode* BUTree(char* a,int* pi)
{if(a[*pi] =='#'){(*pi)++;return NULL;}BTNode* newnode=(BTNode*)malloc(sizeof(BTNode));newnode->val=a[(*pi)++];newnode->le=BUTree(a, pi);newnode->ri=BUTree(a, pi);return newnode;
}
int main()
{char a[100];scanf("%s",a);int i=0;BTNode* node=BUTree(a, &i);PrevInor(node);
}

四、完整代码

Tree.h

#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType _data;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);
// 二叉树第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);
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root);
BTNode* BuyNode(BTDataType x);//求二叉树的最长高度
int TreeHeight(BTNode* root);

Tree.c

#define _CRT_SECURE_NO_WARNINGS
#include"Tree.h"BTNode* BuyNode(BTDataType x)
{BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc err");return NULL;}newnode->_data = x;newnode->_left = NULL;newnode->_right = NULL;return newnode;
}/*int n,*/
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreateChar(BTDataType* a, int* pi)
{if (a[(*pi)] == '#'){(*pi)++;return NULL;}BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL){perror("malloc err");return NULL;}newnode->_data = a[(*pi)++];newnode->_left = BinaryTreeCreateChar(a, pi);newnode->_right = BinaryTreeCreateChar(a, pi);return newnode;
}//123nn4n5nn67nn8nn
BTNode* BinaryTreeCreate()
{BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);BTNode* node7 = BuyNode(7);BTNode* node8 = BuyNode(8);node1->_left = node2;node1->_right = node6;node2->_left = node3;node2->_right = node4;node4->_right = node5;node6->_left = node7;node6->_right = node8;return node1;
}
// 二叉树销毁
void BinaryTreeDestory(BTNode** root)
{if (*(root) == NULL)return;BinaryTreeDestory(&(*root)->_left);BinaryTreeDestory(&(*root)->_right);free(*(root));
}
// 二叉树节点个数
int BinaryTreeSize(BTNode* root)
{return root == NULL ? 0 : BinaryTreeSize(root->_left) + BinaryTreeSize(root->_left)+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)
{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->_left, x);if (ret1)return ret1;BTNode* ret2 = BinaryTreeFind(root->_right, x);if (ret2)return ret2;return NULL;}
// 二叉树前序遍历 
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);
}
// 二叉树中序遍历
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}BinaryTreeInOrder(root->_left);printf("%d ",root->_data);BinaryTreeInOrder(root->_right);
}
// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){printf("NULL ");return;}BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%d ",root->_data);
}
// 层序遍历
#include"Queue.h"
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* Fout = QueueFront(&q);QueuePop(&q);printf("%d ",Fout->_data);if (Fout->_left){QueuePush(&q,Fout->_left);}if (Fout->_right){QueuePush(&q, Fout->_right);}}QueueDestroy(&q);
}
// 判断二叉树是否是完全二叉树
bool BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root)QueuePush(&q, root);while (!QueueEmpty(&q)){BTNode* Fout = QueueFront(&q);QueuePop(&q);if (Fout == NULL){break;}QueuePush(&q, Fout->_left);QueuePush(&q, Fout->_right);}while (!QueueEmpty(&q)){BTNode* Fout = QueueFront(&q);QueuePop(&q);if (root){QueueDestroy(&q);return false;}}QueueDestroy(&q);return true;
}//二叉树的最大高度
int TreeHeight(BTNode* root) 
{if (root == NULL)return 0;int node_left=TreeHeight(root->_left); int node_right = TreeHeight(root->_right);return node_left > node_right ? node_left + 1 : node_right + 1;
}

Queue.c(部分)

void QueueInit(Queue* pq)
{assert(pq);pq->phead = NULL;pq->ptail = NULL;pq->size = 0;
}
void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newnode = (QNode*)malloc(sizeof(QNode));if (newnode == NULL){perror("malloc err");return;}newnode->data = x;newnode->next=NULL;if (pq->phead == NULL){assert(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(!QueueEmpty(pq));if (pq->phead->next == NULL){free(pq->phead);pq->phead = pq->ptail = NULL;}else {QNode* next = pq->phead->next;free(pq->phead);pq->phead = next;}pq->size--;
}
QDataType QueueFront(Queue* pq)
{assert(pq);assert(!QueueEmpty(pq));return pq->phead->data;
}
bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL&& pq->ptail == NULL;
}

五、总结

二叉树全面总结:

定义:
二叉树是一种特殊的树结构,每个节点最多有两个子节点,分别称为左子节点和右子节点。

主要特点:

• 节点度最大为 2。

• 具有递归结构。

重要类型:

• 满二叉树:所有节点都有两个子节点,且叶子节点都在同一层。

• 完全二叉树:除了最后一层,其他层都是满的,最后一层的叶子节点靠左排列。

遍历方式:

• 前序遍历:先访问根节点,再遍历左子树,最后遍历右子树。

• 中序遍历:先遍历左子树,再访问根节点,最后遍历右子树。

• 后序遍历:先遍历左子树,再遍历右子树,最后访问根节点。

• 层次遍历:按照层次依次访问节点。

应用:

• 高效搜索和排序。

• 表达式树。

• 二叉堆实现优先队列等。

性质:

• 在完全二叉树中,节点编号与层次存在特定关系。

• 叶子节点数与度为 2 的节点数存在一定关系。

存储方式:

• 链式存储:通过节点指针连接。

• 数组存储:适用于完全二叉树。

常见算法:

• 构建二叉树。

• 求深度、高度。

• 查找节点。

• 平衡性判断及调整(如 AVL 树、红黑树等)。

二叉树是数据结构中的基础且重要部分,在计算机科学中有广泛的应用和研究价值。

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

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

相关文章

Linux服务升级:Predixy 升级代理 Redis-cluster 集群

目录 一、实验 1.环境 2. 启动Redis服务 3.Predixy 升级代理 Redis-cluster 集群 二、问题 1. Predixy进行set操作报错 2.如何创建脚本启动predixy 3.Redis代理对比 一、实验 1.环境 &#xff08;1&#xff09;主机 表1 主机 系统版本节点软件IP备注CentOS7.9Redis…

Springboot开发 -- Postman 调试类型详解

引言 在 Spring Boot 应用开发过程中&#xff0c;接口测试是必不可少的一环。Postman 作为一款强大的 API 开发和测试工具&#xff0c;可以帮助开发者轻松构建、测试和管理 HTTP 请求。本文将为大家介绍如何在 Spring Boot 开发中使用 Postman 进行接口测试。 一、准备工作 安…

C/C++|malloc分配内存详解

看本节前&#xff0c;希望读者有linux内存分布的基本概念&#xff0c;可以阅读这篇文章&#xff1a; 进程虚拟地址空间和函数调用栈 在本节中希望读者可以一口气阅读完所有内容。 本博客内容全部来自小林coding&#xff1a;malloc 是如何分配内存的&#xff1f; 这里仅为笔记记…

Linux/Ubuntu 中安装 ZeroTier,实现内网穿透,2分钟搞定

相信很多人都有远程连接家中设备的需求&#xff0c;如远程连接家中的NAS、Windows等服务&#xff0c;所以会涉及到一个内网穿透工具的使用&#xff0c;如果没有公网IP的情况下&#xff0c;推荐大家使用ZeroTier&#xff0c;这是一款强大的内网穿透工具。 mac和windows版的操作…

Nginx-狂神说

Nginx概述 公司产品出现瓶颈&#xff1f; 我们公司项目刚刚上线的时候&#xff0c;并发量小&#xff0c;用户使用的少&#xff0c;所以在低并发的情况下&#xff0c;一个jar包启动应用就够了&#xff0c;然后内部tomcat返回内容给用户。 但是慢慢的&#xff0c;使用我们平台…

K8S认证|CKA题库+答案| 13. sidecar 代理容器日志

目录 13、使用 sidecar 代理容器日志 CKA v1.29.0模拟系统免费下载试用&#xff1a; 题目&#xff1a; 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、生成yaml文件 3&#xff09;、官网找模板 4&#xff09;、编辑yaml文件 5&#xff09;、应用yaml…

车载电子电器架构 —— 智能座舱技术

车载电子电器架构 —— 智能座舱技术 我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 屏蔽力是信息过载时代一个人的特殊竞争力&#xff0c;任何消耗你的…

GEO数据挖掘-GEO背景知识+表达芯片分析思路

From生物技能树 GEO数据挖掘第一节 &#xff08;pipeline&#xff09; 文章目录 1.图表分析2.GEO背景介绍及分析思路3.代码分析流程4.复杂数据分析理论知识1.数据从哪里来2.有什么类型的数据可挖掘3.如何筛选基因&#xff08;分析方法&#xff09;在这里插入图片描述 图表介绍1…

Jenkins + github 自动化部署配置

1 Jenkins安装 AWS EC2安装Jenkins&#xff1a;AWS EC2 JDK11 Jenkins-CSDN博客 AWS EC2上Docker安装Jenkins&#xff1a;https://blog.csdn.net/hhujjj2005/article/details/139078402 2 登录jenkins http://192.168.1.128:8080/ $ docker exec -it d1851d9e3386 /bin/ba…

Multi-objective reinforcement learning approach for trip recommendation

Multi-objective reinforcement learning approach for trip recommendation A B S T R A C T 行程推荐是一项智能服务&#xff0c;为游客在陌生的城市提供个性化的行程规划。 它旨在构建一系列有序的 POI&#xff0c;在时间和空间限制下最大化用户的旅行体验。 将候选 POI 添…

【Shell】sed编辑器实例

sed是用来解析和转换文本的工具&#xff0c;它使用简单&#xff0c;是简洁的程序设计语言。 sed编辑器 &#xff08;一&#xff09; sed编辑器基础1. 简介2. sed的模式空间 &#xff08;二&#xff09;基本的sed编辑命令&#xff08;三&#xff09;sed命令实例1. 向文件中添加或…

MFC GDI 绘图模式、映射模式、画笔、笔、字体

一 GDI 绘图模式&#xff08;RoP2 Mode&#xff09; 在使用VC MFC进行图形程序编程时&#xff0c;常会用到GDI绘图指令&#xff0c;而要做到绘图时有橡皮筋动态效果&#xff0c;就需设置GDI绘图模式。GDI绘图模式有多种&#xff0c;如下&#xff1a; 常用R2_NOT模式来实…

Linux|操作系统|如何下载各个版本的centos操作系统

前言&#xff1a; centos做为一个现在比较常用的Linux社区版本&#xff0c;还是比较受欢迎的&#xff0c;那么&#xff0c;如何下载centos的安装包&#xff0c;也就是centos的操作系统呢&#xff1f; 首先&#xff0c;我们应该知道硬件底层有aarch64&#xff0c;ppc64&#x…

【限免】短时傅里叶变换时频分析【附MATLAB代码】

来源&#xff1a;微信公众号&#xff1a;EW Frontier 简介 一种能够同时对信号时域和频域分析的方法——短时傅里叶变换&#xff08;STFT&#xff09;&#xff0c;可以在时频二维角度准确地描述信号 的时间、频域的局部特性&#xff0c;与其他算法不同&#xff0c;通过该算法可…

【Elasticsearch】Centos7安装Elasticsearch、kibana、IK分词

目录 本文安装包下载地址注意安装elasticsearch1.上传文件2.解压elasticsearch-6.3.1.tar.gz3.开启远程连接权限4.修改其他配置[root用户操作]5.重启虚拟机6.启动es7.外部访问 安装kibana-61.解压2.配置3.启动kibana4.访问5.在开发工具中做数据的增删改查操作 安装IK分词1.wind…

软件安全复习

文章目录 第一章 软件安全概述1.1 信息定义1.2 信息的属性1.3 信息安全1.4 软件安全1.5 软件安全威胁及其来源1.5.1 软件缺陷与漏洞1.5.1.1 软件缺陷1.5.1.2 漏洞1.5.1.3 软件漏洞1.5.1.4 软件缺陷和漏洞的威胁 1.5.2 恶意软件1.5.2.1 恶意软件的定义1.5.2.2 恶意软件的威胁 1.…

携手AI,如何共赢未来?

5/25日参加了一个培训分享会&#xff0c;由博奥研究院、武汉博奕咨询和华工科技联合举办&#xff0c;主题是“携手Ai&#xff0c;共赢未来”。 抱着跟书友线下交流的心态我参与了&#xff0c;参与前我对博奥做了基础了解&#xff0c;他们跟工信部考试和教育中心有合作&#x…

【C语言】指针作为参数(传值调用vs传址调用)

前言 在前面讲了那些指针相关的内容后&#xff0c;是时候探讨一下指针有什么作用了。 在C语言中&#xff0c;指针有多种各不相同的应用&#xff0c;在本篇文章中&#xff0c;我们探讨一下指针作为函数参数的作用&#xff08;对比传值与传址两种不同函数调用方式&#xff09;。…

【QGIS入门实战精品教程】10.7: 基于DEM的地形因子分析(坡度、坡向、粗糙度、山体阴影、耐用指数)

文章目录 一、加载dem二、山体阴影三、坡度四、坡向五、地形耐用指数六、地形位置指数七、地表粗糙度一、加载dem 二、山体阴影 方法一:符号系统 利用符号系统中的山体阴影,渲染出阴影效果。 方法二:山体阴影工具 该算法计算输入中的数字化地形模型的山体阴影。根据太阳的位…

2024 年 5 个 GO REST API 框架

什么是API&#xff1f; API是一个软件解决方案&#xff0c;作为中介&#xff0c;使两个应用程序能够相互交互。以下一些特征让API变得更加有用和有价值&#xff1a; 遵守REST和HTTP等易于访问、广泛理解和开发人员友好的标准。API不仅仅是几行代码&#xff1b;这些是为移动开…