二叉树(C/C++)
本篇将较为详细的介绍二叉树的相关知识,以及二叉树的实现。对于二叉树的相关知识,本篇介绍了其概念、特殊的二叉树、性质还有存储结构。
接着对于实现二叉树的每个函数都有其思路讲解,主要的函数分为:遍历:前中后序遍历;结点个数:二叉树总结点个数、叶子结点个数、第k层结点个数、二叉树的高度;建立销毁二叉树:前序遍历建立二叉树与销毁二叉树;层序遍历与判断是否为完全二叉树;在二叉树中查找值为x的结点。
然后测试了所有的代码,其中使用到的队列代码本篇就没有讲解,若详细查看队列代码可去主页查找对应的文章。
目录如下:
目录
1. 二叉树的概念及结构
1.1 概念 1.2 特殊的二叉树 1.3 二叉树的性质 1.4 二叉树的存储结构
2. 二叉树的实现
2.1 二叉树的遍历 2.2 计算结点个数 2.3 通过前序遍历建立二叉树、销毁二叉树 2.4 层序遍历与判断二叉树是否为完全二叉树 2.5 二叉树查找值为x的结点。
3. 所有代码
3.1 All.h 3.2 Queue.c 3.3 BinaryTree.c 3.4 test.c 3.5 测试结果
1. 二叉树的概念及结构
1.1 概念
一颗二叉树是结点的一个有限集合,该集合:或者为空(空二叉树)、或一个根节点加上两颗别称为左子树和右子树的二叉树组成。
从上图中可以看出:
1.二叉树中不存在度大于2的结点;
2.二叉树的子树存在左右之分,次序不能颠倒,因此二叉树是有序树。
注意:对于任意的二叉树都是由以下几种情况复合而成:
1.2 特殊的二叉树
特殊的二叉树包括两种:满二叉树、完全二叉树。
满二叉树:一个二叉树,若每一层的节点数都达到最大值,则这个二叉树就为满二叉树。也就是说,若一个二叉树的层数为 k ,且结点总数为 2^k - 1 ,则它就是满二叉树。
完全二叉树:对于深度为 k 的,有 n 个结点的二叉树,当且仅当其中每一个结点都与深度为 k 的满二叉树中编号从 1 到 n 的结点一一对应时称之为完全二叉树。满二叉树是一种特殊的完全二叉树,完全二叉树是一种效率很高的数据结构,完全二叉树是由满二叉树引出来的。
1.3 二叉树的性质
1.若规定根节点的层数为1,则一颗非空二叉树的第 i 层上最多有2^( i - 1 )个结点。
2.若规定根节点的层数为1,则深度为 h 的二叉树的最大节点数为 2^h - 1。
3.对任意一棵二叉树,若度为0的叶子节点个数为n0,度为2的分支结点个数为n2,则有n0 = n2 + 1。
4.若规定根节点的层数为1,若具有n个结点的满二叉树的深度:
。
5.对于具有n个结点的完全二叉树,若按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点:
a.若 i > 0, i 位置结点的双亲结点序号:( i - 1 ) / 2;i = 0时,表示为根节点编号,无双亲结点。
b.若 2 * i + 1 < n, 左孩子序号:2 * i + 1,若2 * i + 1 >= n 表示无左孩子。
c.若 2 * i + 2 < n, 右孩子序号:2 * i + 2,若2 * i + 2 >= n 表示无右孩子。
1.4 二叉树的存储结构
二叉树一般可以使用两种结构存储,一种顺序存储,一种链式存储。本篇主讲链式存储。
1.顺序存储:顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。而现实中使用中只有堆才会使用数组来存储。二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。
2.链式存储:二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。链式结构又分为二叉链和三叉链,当前我们所介绍的主要为二叉链。
2. 二叉树的实现
接下来将实现二叉树,其中主要实现的为链式二叉树,其中包括几个部分:
1.二叉树的遍历:二叉树的前序、中序、后序遍历;
2.计算结点个数:计算二叉树结点个数、叶子结点个数、第k层结点的个数和二叉树的高度;
3.通过前序遍历构建二叉树、二叉树的销毁;
4.层序遍历二叉树、判断二叉树是否为完全二叉树;
5.二叉树查找值为x的结点。
主要就为以上几个部分,其中需要使用到的其他数据结构为:队列。
2.1 二叉树的遍历
对于二叉树的前序、中序和后序遍历本文使用递归遍历;对于层序遍历就使用非递归遍历,首先介绍的为前序、中序和后序遍历:
对于递归遍历,主要思路为:递归分治,将问题分为当前问题和子问题,以及递归结束的调节。
以前序遍历为主:前序遍历的主要关键为,若当前结点不为NULL,我们就将其遍历,然后接着遍历左子树、右子树。若当前结点为NULL,我们就返回当前函数,此次递归结束。中序就为:先遍历左子树,然后遍历根节点、最后遍历右子树;后序为先遍历左子树,然后遍历右子树,最后遍历根节点。代码如下:
// 二叉树前序遍历 void BinaryTreePrevOrder(BTNode* root) {if (root) {printf("%c ", root->data);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);} }// 二叉树中序遍历 void BinaryTreeInOrder(BTNode* root) {if (root) {BinaryTreeInOrder(root->left);printf("%c ", root->data);BinaryTreeInOrder(root->right);} }// 二叉树后序遍历 void BinaryTreePostOrder(BTNode* root) {if (root) {BinaryTreePostOrder(root->left);BinaryTreePostOrder(root->right);printf("%c ", root->data);} }
2.2 计算结点个数
接下来将用递归分别计算二叉树的结点个数、叶子结点个数、第k层结点的个数以及计算二叉树的高度;先以计算二叉树的个数为例:我们要计算二叉树的结点个数,可以将其分为:左子树结点个数+右子树结点个数+1(根节点个数),其中的核心思想就为此,若遇到空结点则返回0,代码具体实现如下:
// 二叉树节点个数 int BinaryTreeSize(BTNode* root) {return root == NULL ? 0 : BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1; }
计算叶子结点个数:我们首先需要找到叶子结点的特点,左右子树为NULL,所以我们可以将此递归分为:遇到叶子结点返回1、左子树叶子结点+右子树叶子结点,当访问到空结点时即返回0,具体代码实现如下:
// 二叉树叶子节点个数 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层的结点个数:既然需要计算第k层的结点个数,那么我们肯定需要锁定到第k层,所以我们需要在每一次递归时都将k减一,然后在k==1时返回1。所以我们可以将这个递归分为:当k==1时返回1,递归返回左子树第k个结点+右子树第k个结点。具体实现代码如下:
// 二叉树第k层节点个数 int BinaryTreeLevelKSize(BTNode* root, int k) {assert(k > 0);if (k == 1)return 1;if (root == NULL)return 0;return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1); }
计算二叉树的高度:对于计算二叉树的高度,我们首先需要知道的是左子树更高还是右子树更高,计算出子树的最高高度,然后加上根节点,所以可以将其递归分为:比较左右子树的高度,然后返回最高的高度+1(加根节点),若递归到空节点返回0,具体实现如下:
// 二叉树的高度 int BinaryTreeHeight(BTNode* root) {if (root == NULL)return 0;int leftHeight = BinaryTreeHeight(root->left);int rightHeight = BinaryTreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1; }
2.3 通过前序遍历建立二叉树、销毁二叉树
对于用此方法构建二叉树,我们只需要输入二叉树的前序序列,然后根据此建立出对应的二叉树。其中输入的前序序列需要包含空结点,空结点用”#“表示。
此函数传入的参数为:字符串(前序序列)、记录当前递归处理到了前序序列字符串的哪一个位置的整数的地址。函数返回根节点。
对于此函数的实现,主要还是依靠递归,将这个递归分为:若当前字符为:#,返回NULL,若不为:#,malloc一个新节点,新节点的数据为当前字符,然后将整数+1,然后递归新节点的左右孩子结点,最后返回新节点,具体代码实现如下:
BTNode* CreatBTNode(BTDataType x) {BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL) {perror("newnode malloc:\n");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode; }// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 BTNode* BinaryTreeCreate(BTDataType* a, int* pi) {if (a[*pi] == '#') {(*pi)++;return NULL;}BTNode* newNode = CreatBTNode(a[*pi]);(*pi)++;newNode->left = BinaryTreeCreate(a, pi);newNode->right = BinaryTreeCreate(a, pi);return newNode; }
二叉树的销毁:二叉树的销毁仍然使用递归进行销毁处理,其主要思想和后序遍历基本一致,主要为:递归删除左子树+递归删除右子树+删除根节点,主要实现代码如下:
// 二叉树销毁 void BinaryTreeDestory(BTNode** root) {// 递归销毁,先销毁左子树,后销毁右子树if (*root == NULL)return;BTNode* tmp = *root;BinaryTreeDestory(&tmp->left);BinaryTreeDestory(&tmp->right);free(tmp);tmp = NULL; }
2.4 层序遍历与判断二叉树是否为完全二叉树
层序遍历:对于层序遍历的主要思想就是将二叉树按层次遍历,先遍历第一层根节点,然后遍历下一层,从左到右,直至遍历结束。对于此方法,我们不使用递归,我们使用队列来辅助我们遍历。
我们首先将根节点放入队列,然后开始进行遍历循环,只要队列不为空,我们就一直入循环。在循环中,我们得到排在队列的第一个元素将其访问,然后,若第一个元素的左子树不为空,则将其入队列,右子树不为空,将其入队列(孩子结点不为空就入队列),接着将第一个元素出队列,循环往复就可以将二叉树进行层序遍历,因为是将结点一层一层的加入队列,然后又出队列的。具体实现代码如下:
// 层序遍历 void BinaryTreeLevelOrder(BTNode* root) {if (root == NULL)return;Queue pQ;QueueInit(&pQ);QueuePush(&pQ, *root);while (!QueueEmpty(&pQ)) {BTNode new = QueueFront(&pQ);printf("%c ", new.data);if(new.left)QueuePush(&pQ, *(new.left));if(new.right)QueuePush(&pQ, *(new.right));QueuePop(&pQ);}QueueDestory(&pQ); }
判断二叉树是否为完全二叉树:对于完全二叉树的判断,主要就是判断一个结点是否存在:不存在左孩子存在右孩子的情况,当出现这种情况时,就可以判断出该二叉树不为完全二叉树。所以我们只需将所有的结点进行判断,若所有结点都判断通过,则返回true,若发现其中一个结点存在:没有左孩子存在右孩子,则返回false。
对于每个孩子的判断,其实我们就可以使用以上的层序遍历,在遍历每个结点时对结点进行判断,具体实现代码如下:
// 判断二叉树是否是完全二叉树 bool BinaryTreeComplete(BTNode* root) {if (root == NULL)return true;Queue pQ;QueueInit(&pQ);QueuePush(&pQ, *root);while (!QueueEmpty(&pQ)) {BTNode new = QueueFront(&pQ);if (new.left == NULL && new.right)return false;if (new.left)QueuePush(&pQ, *(new.left));if (new.right)QueuePush(&pQ, *(new.right));QueuePop(&pQ);}QueueDestory(&pQ);return true; }
2.5 二叉树查找值为x的结点。
对于二叉树的查找,我们同样使用递归对二叉树进行遍历查找,其主要思想为:若当前结点为NULL,则返回NULL,若当前结点的值等于 x ,则返回当前结点,然后依次遍历查找左子树和右子树,但是在左子树和右子树的查找返回中,我们一个函数只能返回一次,不能同时递归返回左右子树,所有需要在对左子树的递归返回时加上一个判断,若左子树不为NULL,则先查找递归返回左子树,当左子树递归结束都还没找到时,自然递归返回右子树。具体实现代码如下:
// 二叉树查找值为x的节点 BTNode* BinaryTreeFind(BTNode* root, BTDataType x) {if (root == NULL)return NULL;if (root->data == x)return root;BTNode* leftFind = BinaryTreeFind(root->left, x);if (leftFind)return leftFind;return BinaryTreeFind(root->right, x); }
3. 所有代码
3.1 All.h
以下为头文件:All.h的代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> #include <math.h>typedef char BTDataType;typedef struct BinaryTreeNode {BTDataType data;struct BinaryTreeNode* left;struct BinaryTreeNode* right; }BTNode;typedef BTNode QDataType;typedef struct Node {QDataType val;struct Node* next; }QNode;typedef struct Queue {int size;QNode* phead;QNode* ptail; }Queue;//队列的初始化/销毁 void QueueInit(Queue* pQ); void QueueDestory(Queue* pQ);//队列的入队/出队 void QueuePush(Queue* pQ, QDataType x); void QueuePop(Queue* pQ);//返回队首元素/队尾元素 QDataType QueueFront(Queue* pQ); QDataType QueueBack(Queue* pQ);//判断队列是否为NULL/返回队列的大小 bool QueueEmpty(Queue* pQ); int QueueSize(Queue* pQ);// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 BTNode* BinaryTreeCreate(BTDataType* a, 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); // 二叉树的高度 int BinaryTreeHeight(BTNode* root);
3.2 Queue.c
以下为队列部分的代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include "All.h"void QueueInit(Queue* pQ) {assert(pQ);pQ->phead = 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 = 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:");exit(1);}newnode->val = x;newnode->next = NULL;if (pQ->phead == 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);QNode* cur = pQ->phead;pQ->phead = pQ->phead->next;free(cur);cur = NULL;pQ->size--; }QDataType QueueFront(Queue* pQ) {assert(pQ);assert(pQ->phead);return pQ->phead->val; }QDataType QueueBack(Queue* pQ) {assert(pQ);assert(pQ->phead);return pQ->ptail->val; }bool QueueEmpty(Queue* pQ) {assert(pQ);return pQ->phead == NULL; }int QueueSize(Queue* pQ) {assert(pQ);return pQ->size; }
3.3 BinaryTree.c
以下为实现二叉树的代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include "All.h"// 二叉树节点个数 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 (k == 1)return 1;if (root == NULL)return 0;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* leftFind = BinaryTreeFind(root->left, x);if (leftFind)return leftFind;return BinaryTreeFind(root->right, x); }// 二叉树前序遍历 void BinaryTreePrevOrder(BTNode* root) {if (root) {printf("%c ", root->data);BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);} }// 二叉树中序遍历 void BinaryTreeInOrder(BTNode* root) {if (root) {BinaryTreePrevOrder(root->left);printf("%c ", root->data);BinaryTreePrevOrder(root->right);} }// 二叉树后序遍历 void BinaryTreePostOrder(BTNode* root) {if (root) {BinaryTreePrevOrder(root->left);BinaryTreePrevOrder(root->right);printf("%c ", root->data);} }// 层序遍历 void BinaryTreeLevelOrder(BTNode* root) {if (root == NULL)return;Queue pQ;QueueInit(&pQ);QueuePush(&pQ, *root);while (!QueueEmpty(&pQ)) {BTNode new = QueueFront(&pQ);printf("%c ", new.data);if(new.left)QueuePush(&pQ, *(new.left));if(new.right)QueuePush(&pQ, *(new.right));QueuePop(&pQ);}QueueDestory(&pQ); }// 二叉树的高度 int BinaryTreeHeight(BTNode* root) {if (root == NULL)return 0;int leftHeight = BinaryTreeHeight(root->left);int rightHeight = BinaryTreeHeight(root->right);return leftHeight > rightHeight ? leftHeight + 1 : rightHeight + 1; }BTNode* CreatBTNode(BTDataType x) {BTNode* newnode = (BTNode*)malloc(sizeof(BTNode));if (newnode == NULL) {perror("newnode malloc:\n");exit(1);}newnode->data = x;newnode->left = newnode->right = NULL;return newnode; }// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树 BTNode* BinaryTreeCreate(BTDataType* a, int* pi) {if (a[*pi] == '#') {(*pi)++;return NULL;}BTNode* newNode = CreatBTNode(a[*pi]);(*pi)++;newNode->left = BinaryTreeCreate(a, pi);newNode->right = BinaryTreeCreate(a, pi);return newNode; }// 二叉树销毁 void BinaryTreeDestory(BTNode** root) {// 递归销毁,先销毁左子树,后销毁右子树if (*root == NULL)return;BTNode* tmp = *root;BinaryTreeDestory(&tmp->left);BinaryTreeDestory(&tmp->right);free(tmp);tmp = NULL; }// 判断二叉树是否是完全二叉树 bool BinaryTreeComplete(BTNode* root) {if (root == NULL)return true;Queue pQ;QueueInit(&pQ);QueuePush(&pQ, *root);while (!QueueEmpty(&pQ)) {BTNode new = QueueFront(&pQ);printf("%c ", new.data);if (new.left == NULL && new.right)return false;if (new.left)QueuePush(&pQ, *(new.left));if (new.right)QueuePush(&pQ, *(new.right));QueuePop(&pQ);}QueueDestory(&pQ);return true; }
3.4 test.c
以下为测试的所有代码:
#define _CRT_SECURE_NO_WARNINGS 1 #include "All.h"int main() {char ch[] = "ABD##E#H##CF##G##";int i = 0;BTNode* root = BinaryTreeCreate(ch, &i);printf("BinaryTreePrevOrder: ");BinaryTreePrevOrder(root);printf("\n");printf("BinaryTreeInOrder: ");BinaryTreeInOrder(root);printf("\n");printf("BinaryTreePostOrder: ");BinaryTreePostOrder(root);printf("\n");if (BinaryTreeComplete(root))printf("BinaryTree is Complete: true\n");elseprintf("BinaryTree is Complete: false\n");printf("BinaryTreeLevelKSize: %d\n", BinaryTreeLevelKSize(root, 3));printf("BinaryTreeLeafSize: %d\n",BinaryTreeLeafSize(root));printf("BinaryTreeSize: %d\n", BinaryTreeSize(root));printf("BinaryTreeHeight: %d\n", BinaryTreeHeight(root));BTNode* Find = BinaryTreeFind(root, 'A');if (Find)Find->data = 'Y';printf("BinaryTreePrevOrder: ");BinaryTreePrevOrder(root);printf("\n");printf("BinaryTreeLevelOrder: ");BinaryTreeLevelOrder(root);BinaryTreeDestory(&root);return 0; }
3.5 测试结果
对于字符串"ABD##E#H##CF##G##"建立的树如下:
代码实现如下:
相关文章:

二叉树(C/C++)
本篇将较为详细的介绍二叉树的相关知识,以及二叉树的实现。对于二叉树的相关知识,本篇介绍了其概念、特殊的二叉树、性质还有存储结构。 接着对于实现二叉树的每个函数都有其思路讲解,主要的函数分为:遍历:前中后序遍历…...

Django学习笔记-ModelForm使用(完全依赖)
1.创建模型 ,code,name,sex,entrydate 2.模型映射 python manage.py makemigrations myapp01,python manage.py migrate 3.创建模型表单,继承forms.ModelForm,Meta:元数据,models需引入,fields填写引用的模型变量 4.创建testModelForm.html,添加urls 5.views编写testmodelfo…...

动态规划之使用最小花费爬楼梯【LeetCode】
动态规划之使用最小花费爬楼梯 LCR 088. 使用最小花费爬楼梯解法1解法2 LCR 088. 使用最小花费爬楼梯 LCR 088. 使用最小花费爬楼梯 解法1 状态表示(这是最重要的):dp[i]表示以第i级台阶为楼层顶部,到达第i层台阶的最低花费。 状…...

双指针---解决实际问题
...
每天一个数据分析题(一百七十八)
在大样本(样本量为n)下进行某一列数据(A列)均值的区间估计时,假设点估计的值计算为a,显著性水平为0.05,z0.025为给定的显著性水平下的正态分布的临界值,则使用EXCEL的计算方法正确的…...

Ethernet/IP转Modbus TCP网关
产品功能 1 YC-EIP-TCP工业级EtherNet/IP 网关 2 Modbus TCP 转 EtherNet/IP 3支持ModBus主从站 4 即插即用 无需编程 轻松组态 ,即实现数据交互 5导轨安装 支持提供EDS文件 6 EtherNET/IP与ModBus互转数据透明传输可接入PLC组态 支持CodeSys/支持欧姆龙PLC 支持罗克韦尔(AB) 典…...

const详解
文章目录 简介什么是const呢?const 的使用1.用来定义常量2.和指针相关的const3.函数与const4.类中使用const(重点) c中去掉const属性验证不同对象的调用const修饰类内成员 c中的const 和 c中的const 的区别c中的const为什么c中的const常量又不能通过指针修改呢 const 和 #defi…...
多方面浅谈互联网技术
目录 方向一:物联网技术概述 方向二:物联网技术的应用 方向三:物联网发展所需技术和创新挑战 物联网技术(Internet of Things,IoT)是一种将各种智能设备、传感器、电子产品等连接起来,通过互…...

Oracle EBS GL 外币折算逻辑
背景 由于公司财务在10月份期间某汇率维护错误,导致帐套折算以后并合传送至合并帐套生成合并日记帐凭证的借贷金额特别大,但是财务核对的科目余额有没有问题,始终觉得合并日记帐生成会计分发有问题,需要我们给出外币折算逻辑。 基础设置 汇率 Path: GL->设置->币种-&…...
Java面试题之mysql
Mysql 1. MySQL的索引原理是什么?什么是索引?以及索引的优缺点?2. 解释一下B树和B树的区别及各自定义?3. MyISAM索引和Innodb索引的区别?4. 什么是聚簇索引?辅助索引?5.非聚簇索引一定会回表查询么?6. 什…...
抖音直播封禁申诉话术怎么讲?抖音直播封号怎么申请解封?
一.抖音直播封禁申诉话术怎么讲? 1. 了解封禁原因:首先,您需要清楚自己为何被封禁。抖音通常会在封禁时给出原因,如违规内容、恶意行为等。了解原因有助于您针对性地构建申诉话术。 2. 表达诚挚歉意:在申诉话术中,首…...

使用Jenkins部署前端Vue项目和后端Java服务
Jenkins安装相关插件,供后续使用(Dashboard - Manage Jenkins - Plugins) Maven Integration plugin https://plugins.jenkins.io/maven-plugin CloudBees Docker Build and Publish pluginhttps://plugins.jenkins.io/docker-build-publish…...
刷题——显示屏
目录 题目描述 输入格式 输出格式 输入输出样例 说明/提示 解 题目描述 液晶屏上,每个阿拉伯数字都是可以显示成 35 的点阵的(其中 X 表示亮点,. 表示暗点)。现在给出数字位数(不超过 100100)和一串数…...

WEB服务器-Tomcat(黑马学习笔记)
简介 服务器概述 服务器硬件 ● 指的也是计算机,只不过服务器要比我们日常使用的计算机大很多。 服务器,也称伺服器。是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障…...

第五节:Vben Admin权限-前端控制方式
系列文章目录 第一节:Vben Admin介绍和初次运行 第二节:Vben Admin 登录逻辑梳理和对接后端准备 第三节:Vben Admin登录对接后端login接口 第四节:Vben Admin登录对接后端getUserInfo接口 第五节:Vben Admin权限-前端控制方式 文章目录 系列文章目录前言一、Vben Admin权…...
蓝桥杯备赛第二篇(背包问题)
1. 01 背包(采用状态压缩) public static void main(String[] args) {Scanner scanner new Scanner(System.in);int M scanner.nextInt();int N scanner.nextInt();int[] value new int[N 1];int[] weight new int[N 1];int[] dp new int[M 1];…...
【postgresql 基础入门】带过滤条件的查询,where子句中的操作符介绍,案例展示,索引失效的大坑就在这里
查询数据-过滤数据 专栏内容: postgresql内核源码分析手写数据库toadb并发编程 开源贡献: toadb开源库 个人主页:我的主页 管理社区:开源数据库 座右铭:天行健,君子以自强不息;地势坤&#…...

vue项目打包获取git commit信息并输出到打包后的指定文件夹中
需求背景: 前端项目经常打包,发包部署,为了方便测试及运维发现问题时与正确commit信息对比 实现方式: 使用Node.js的child_process模块来执行git命令 实现步骤: 1.在package.json的同级目录下新建一个version.js文件。…...
vue 移动端app预览和保存pdf踩坑
需求 使用Vue开发h5,嵌套到Android和IOS的Webview里,需要实现pdf预览和保存功能,预览pdf的功能,我这边使用了三个库,pdf5,pdf.js,vue.pdf,现在把这三个库在app端的坑分享一下。先说…...

Vueuse:打造高效的 Vue.js 开发利器
Vueuse:打造高效的 Vue.js 开发利器 Vueuse 是一个功能强大的 Vue.js 生态系统工具库,它提供了一系列的可重用的 Vue 组件和函数,帮助开发者更轻松地构建复杂的应用程序。本文将介绍 Vueuse 的主要特点和用法,以及它在 Vue.js 开发…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂
蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

DIY|Mac 搭建 ESP-IDF 开发环境及编译小智 AI
前一阵子在百度 AI 开发者大会上,看到基于小智 AI DIY 玩具的演示,感觉有点意思,想着自己也来试试。 如果只是想烧录现成的固件,乐鑫官方除了提供了 Windows 版本的 Flash 下载工具 之外,还提供了基于网页版的 ESP LA…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
uniapp中使用aixos 报错
问题: 在uniapp中使用aixos,运行后报如下错误: AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...

mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...

C++ Visual Studio 2017厂商给的源码没有.sln文件 易兆微芯片下载工具加开机动画下载。
1.先用Visual Studio 2017打开Yichip YC31xx loader.vcxproj,再用Visual Studio 2022打开。再保侟就有.sln文件了。 易兆微芯片下载工具加开机动画下载 ExtraDownloadFile1Info.\logo.bin|0|0|10D2000|0 MFC应用兼容CMD 在BOOL CYichipYC31xxloaderDlg::OnIni…...