二叉树的实现(初阶数据结构)
1.二叉树的概念及结构
1.1 概念
一棵二叉树是结点的一个有限集合,该集合:
1.或者为空
2.由一个根结点加上两棵别称为左子树和右子树的二叉树组成
从上图可以看出:
1.二叉树不存在度大于2的结点
2.二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
1.2 特殊二叉树
1.满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树,也就是说没如果一个二叉树的层数为K,且结点总数是2^k-1,则它就是满二叉树。
2.完全二叉树:完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当每一个结点都与深度为K的满二叉树中编号从1至n的结点——对应时称之为完全二叉树,要注意的是满二叉树是一中特殊的完全二叉树。
1.3二叉树的性质
1.若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有2^(i-1)个结点。
2.若规定根结点的层数为1,则深度为h的二叉树的最大结点数是2^h-1。
3.对任何一棵二叉树,如果度为0其叶子结点个数为a,度为2的分支个数为b,则有a=b+1。
4.若规定根结点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1).(ps:以2为底,n+1为对数)
5.对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有结点从0开始编号,则对于序号为i的结点有:
1.若i>0,i的位置结点的双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点
2.2i+1<n,左孩子序号:2i+1,2i+1>=n否则无左孩子
3.2i+2<n,右孩子序号:2i+2,2i+2>=n否则无右孩子
1.4二叉树的存储结构
二叉树一般可以使用两种结构存储,一种顺序结构,一种链式结构。
1.顺序存储
顺序结构村塾就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费,而现实中使用只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一棵二叉树。
2.链式存储
二叉树的链式存储结构是指用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。链式结构又分为二叉链和三叉链。
2.二叉树的实现
#pragma once#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef char 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);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);
//二叉树的高度
int TreeHigh(BTNode* root);
2.1创建新的结点
调用函数BuyNode来创建新的结点
BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->_data = x;node->_left = NULL;node->_right = NULL;return node;
}
2.2通过前序遍历数组来构建二叉树
// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
//a为我们所要遍历的数组
//n是最大数组的长度
//pi是我们用来遍历数组的指针
//当遍历是遇到‘#’或者指针超出了数组的范围就返回NULL
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{if (a[*pi] == '#' || *pi >= n){printf("NULL ");(*pi)++;return NULL;}//创建一个新的二叉树的节点BTNode* dst = BuyNode(a[*pi]); printf("%c ", dst->_data);(*pi)++;dst->_left = BinaryTreeCreate(a, n, pi);dst->_right = BinaryTreeCreate(a, n, pi);return dst;
}
构建出来的二叉树如下:
2.3二叉树的销毁
实现二叉树的销毁时,我们要正确选择以哪种遍历的方式,这里使用后序遍历,从底层叶子层开始,先释放左子树和右子树的空间,再释放根结点的空间,如果先对根结点释放,就找不到它所对应的左子树和右子树了。
//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return;}BinaryTreeDestory(&((*root)->_left));BinaryTreeDestory(&((*root)->_right));free(*root);*root = NULL;return;}
2.4计算二叉树的结点个数
这里我罗列了两种方法:
一种是用一个静态变量通过size++的形式来计算结点的个数(局部的静态变量只能初始化一次)
另一种是递归遍历二叉树通过放回: 左子树+右子树+1
int BinaryTreeSize(BTNode* root)
{//方法一://用静态变量(在堆上,不在栈上)改变局部变量 -> 使得递归的size可以累加起来,但是局部的静态只能初始化一次/*static int size = 0;if (root == NULL){return 0;}else++size;BinaryTreeSize(root->_left);BinaryTreeSize(root->_right);*///方法二://如果我们当前的节点为空,也就是说我们已经到了叶子节点的左右节点,也就是没有节点//所以我们需要返回0if (root == NULL){return 0;}//如果我们当前的节点的左指针和右指针都是空的话,也就是说这是我们的叶子节点//就返回1,也就是只有一个节点if (root->_left == NULL && root->_right == NULL){return 1;}//使用递归遍历我们的二叉树,即分别统计我们左子树的节点个数再加上右子树中的节点个数再加上1//因为我们需要将我们当前所指的节点算上return BinaryTreeSize(root->_left) + BinaryTreeSize(root->_right) + 1;}
2.5计算二叉树叶子结点的个数
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);
}
2.6二叉树第k层的结点个数
二叉树第一层结点个数为1,第k层结点是第一层结点往下找k-1层,第二层的结点往下找k-2层,当k为1的时候返回的结果就是找的k层的结点的个数的总和。
int BinaryTreeLevelKSize(BTNode* root, int k)
{if (root == NULL){return 0;}if (k == 1){return 1;}//分别遍历我们的左右子树,并且将我们的k的参数--,当我们的k为1时,就到达了我们所想要查找对应的层return BinaryTreeLevelKSize(root->_left, k - 1) + BinaryTreeLevelKSize(root->_right, k - 1);
}
2.7查找值为x的结点
查找第一个指定值为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;*/return BinaryTreeFind(root->_right, x);
}
2.8二叉树前序遍历
前序遍历的顺序是根 - 左子树 - 右子树
void BinaryTreePrevOrder(BTNode* root)
{if (root == NULL){return;}printf("%c ", root->_data);BinaryTreePrevOrder(root->_left);BinaryTreePrevOrder(root->_right);}
2.9二叉树中序遍历
中序遍历的顺序是左子树 - 根 - 右子树
void BinaryTreeInOrder(BTNode* root)
{if (root == NULL){return;}BinaryTreeInOrder(root->_left);printf("%c ", root->_data);BinaryTreeInOrder(root->_right);}
2.10二叉树后序遍历
后序遍历的顺序是左子树 - 右子树 - 根
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){return;}BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%c ", root->_data);}
2.11二叉树层序遍历
需要使用一个队列实现层序遍历,先将指向根结点的指针入队,当根结点出队列的时候,将它的左右子树的结点的指针入队,就达到了层层遍历的效果
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root){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);
}
2.12判断二叉树是否为完全二叉树
思路是通过层序遍历的方法,二叉树的叶子结点的下一层节点全部都是NULL,那么在根出队列,左右子树进队列的情况下:
当出队列出到空的时候,判断队列里面的结点是否有非空结点,如果有则证明不是完全二叉树,
反之队列里面都是空结点,则是完全二叉树。
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root){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);QueuePop(&q);//如果有非空,就不是完全二叉树if (front){QueueDestroy(&q);printf("不是完全二叉树\n");return 0;}}QueueDestroy(&q);printf("是完全二叉树\n");return 1;
}
2.13求二叉树的高度
int TreeHigh(BTNode* root)
{if (root == NULL){return 0;}int lefthigh = TreeHigh(root->_left);int righthigh = TreeHigh(root->_right);return lefthigh > righthigh ? lefthigh + 1 : righthigh + 1;//return TreeHigh(root->_left) > TreeHigh(root->_right) ? TreeHigh(root->_left) + 1 : TreeHigh(root->_right) + 1;
}
3.二叉树总代码
3.1 Tree.h
#pragma once#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include <stdbool.h>
typedef char 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);
// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root);
//二叉树的高度
int TreeHigh(BTNode* root);
3.2 Tree.c
#define _CRT_SECURE_NO_WARNINGS 1#include"Tree.h"
#include"Queue.h"BTNode* BuyNode(BTDataType x)
{BTNode* node = (BTNode*)malloc(sizeof(BTNode));if (node == NULL){perror("malloc fail");return NULL;}node->_data = x;node->_left = NULL;node->_right = NULL;return node;
}// 通过前序遍历的数组"ABD##E#H##CF##G##"构建二叉树
BTNode* BinaryTreeCreate(BTDataType* a, int n, int* pi)
{//这里我们的a为我们的数组//n为我们数组的最大长度//pi为我们遍历数组的指针//这里我们使用'#'来表示NULL//当我们所指向的位置的元素为#或者我们的指针已经超过了数组的范围的时候,我们就需要返回NULL//并且将我们的指针后移if (a[*pi] == '#' || *pi >= n){printf("NULL ");(*pi)++;return NULL;}//创建一个新的二叉树的节点BTNode* dst = BuyNode(a[*pi]); printf("%c ", dst->_data);(*pi)++;//将我们之前开创的节点的左右指针指向数组中所对应的节点//如果我们的对应数组中的数据不为空的话,我们的左右指针都会指向新的对应的节点//如果我们的节点为空的话,我们会得到的返回值为NULLdst->_left = BinaryTreeCreate(a, n, pi);dst->_right = BinaryTreeCreate(a, n, pi);return dst;
}//二叉树的销毁
void BinaryTreeDestory(BTNode** root)
{if (*root == NULL){return;}BinaryTreeDestory(&((*root)->_left));BinaryTreeDestory(&((*root)->_right));free(*root);*root = NULL;return;}//计算二叉树的节点个数int BinaryTreeSize(BTNode* root)
{//用静态变量(在堆上,不在栈上)改变局部变量 -> 使得递归的size可以累加起来,但是局部的静态只能初始化一次/*static int size = 0;if (root == NULL){return 0;}else++size;BinaryTreeSize(root->_left);BinaryTreeSize(root->_right);*///如果我们当前的节点为空,也就是说我们已经到了叶子节点的左右节点,也就是没有节点//所以我们需要返回0if (root == NULL){return 0;}//如果我们当前的节点的左指针和右指针都是空的话,也就是说这是我们的叶子节点//就返回1,也就是只有一个节点if (root->_left == NULL && root->_right == NULL){return 1;}//使用递归遍历我们的二叉树,即分别统计我们左子树的节点个数再加上右子树中的节点个数再加上1//因为我们需要将我们当前所指的节点算上return 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)
{if (root == NULL){return 0;}if (k == 1){return 1;}//分别遍历我们的左右子树,并且将我们的k的参数--,当我们的k为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;*/return BinaryTreeFind(root->_right, x);
}// 二叉树前序遍历
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;}BinaryTreeInOrder(root->_left);printf("%c ", root->_data);BinaryTreeInOrder(root->_right);}// 二叉树后序遍历
void BinaryTreePostOrder(BTNode* root)
{if (root == NULL){return;}BinaryTreePostOrder(root->_left);BinaryTreePostOrder(root->_right);printf("%c ", root->_data);}// 层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{Queue q;QueueInit(&q);if (root){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);
}// 判断二叉树是否是完全二叉树
int BinaryTreeComplete(BTNode* root)
{Queue q;QueueInit(&q);if (root){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);QueuePop(&q);//如果有非空,就不是完全二叉树if (front){QueueDestroy(&q);printf("不是完全二叉树\n");return 0;}}QueueDestroy(&q);printf("是完全二叉树\n");return 1;
}int TreeHigh(BTNode* root)
{if (root == NULL){return 0;}int lefthigh = TreeHigh(root->_left);int righthigh = TreeHigh(root->_right);return lefthigh > righthigh ? lefthigh + 1 : righthigh + 1;//return TreeHigh(root->_left) > TreeHigh(root->_right) ? TreeHigh(root->_left) + 1 : TreeHigh(root->_right) + 1;
}
3.3 Queue.h
#pragma once#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>typedef struct BinaryTreeNode* QDataType;typedef struct QueueNode
{struct QueueNode* next;QDataType val;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;void QueueInit(Queue* pq);
void QueueDestroy(Queue* pq);
//队尾插入
void QueuePush(Queue* pq, QDataType x);//队头删除
void QueuePop(Queue* pq);//队头和队尾的数据
QDataType QueueFront(Queue* pq);
QDataType QueueBack(Queue* pq);bool QueueEmpty(Queue* pq);
int QueueSize(Queue* pq);
3.4 Queue.c
#define _CRT_SECURE_NO_WARNINGS 1#include"Queue.h"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 fail");return;}newnode->next = NULL;newnode->val = x;if (pq->ptail == NULL){pq->phead = pq->ptail = newnode;}else{pq->ptail->next = newnode;pq->ptail = newnode;}pq->size++;
}int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}//队头删除
void QueuePop(Queue* pq)
{assert(pq);assert(QueueSize(pq) != 0);//一个节点if (pq->phead == pq->ptail){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(pq->phead);return pq->phead->val;
}QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}
3.5 Test.c
#define _CRT_SECURE_NO_WARNINGS 1#include "Tree.h"int main()
{char a[] = { 'A','B','D','#','#','E','#','H','#','#','C','F','#','#','G','#','#' };int b = 0;int* pi = &b;BTNode* Btree = BinaryTreeCreate(a, 16, pi);printf("\n");//前序遍历BinaryTreePrevOrder(Btree);printf("\n");//中序遍历BinaryTreeInOrder(Btree);printf("\n");//后序遍历BinaryTreePostOrder(Btree);printf("\n");//层次遍历BinaryTreeLevelOrder(Btree);printf("\n");int number = BinaryTreeSize(Btree);printf("%d", number);printf("\n");//查找为x的节点BTNode* find = BinaryTreeFind(Btree, 'A');printf("%c", find->_data);printf("\n");//查询第K层的节点个数int W = BinaryTreeLevelKSize(Btree, 3);printf("%d\n", W);//查询叶子节点的个数int count = BinaryTreeLeafSize(Btree);printf("%d\n", count);//判断当前是否为一颗完全二叉树int ret = BinaryTreeComplete(Btree);int x = TreeHigh(Btree);printf("%d\n", x);BinaryTreeDestory(&Btree);return 0;
}
相关文章:

二叉树的实现(初阶数据结构)
1.二叉树的概念及结构 1.1 概念 一棵二叉树是结点的一个有限集合,该集合: 1.或者为空 2.由一个根结点加上两棵别称为左子树和右子树的二叉树组成 从上图可以看出: 1.二叉树不存在度大于2的结点 2.二叉树的子树有左右之分,次序不能…...

C++笔试强训day41
目录 1.棋子翻转 2.宵暗的妖怪 3.过桥 1.棋子翻转 链接https://www.nowcoder.com/practice/a8c89dc768c84ec29cbf9ca065e3f6b4?tpId128&tqId33769&ru/exam/oj (简单题)对题意进行简单模拟即可: class Solution { public:int dx[…...

【JavaScript】内置对象 - 字符串对象 ⑤ ( 判断对象中是否有某个属性 | 统计字符串中每个字符出现的次数 )
文章目录 一、判断对象中是否有某个属性1、获取对象属性2、判定对象是否有某个属性 二、统计字符串中每个字符出现的次数1、算法分析2、代码示例 String 字符串对象参考文档 : https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/String 一、判…...
Linux环境下测试服务器的DDR5内存性能
要在Linux环境下测试服务器的DDR5内存性能,可以采用以下几种方法和工具: ### 测试原理 内存性能测试主要关注以下几个关键指标: - **带宽**:内存每秒能传输的数据量。 - **延迟**:内存访问请求从发出到完成所需的时间…...

19、matlab信号预处理中的中值滤波(medfilt1()函数)和萨维茨基-戈雷滤波滤(sgolayfilt()函数)
1、中值滤波:medfilt1()函数 说明:一维中值滤波 1)语法 语法1:y medfilt1(x) 将输入向量x应用3阶一维中值滤波器。 语法2:y medfilt1(x,n) 将一个n阶一维中值滤波器应用于x。 语法3:y medfilt1(x,n…...

Scala 练习一 将Mysql表数据导入HBase
Scala 练习一 将Mysql表数据导入HBase 续第一篇:Java代码将Mysql表数据导入HBase表 源码仓库地址:https://gitee.com/leaf-domain/data-to-hbase 一、整体介绍二、依赖三、测试结果四、源码 一、整体介绍 HBase特质 连接HBase, 创建HBase执行对象 初始化…...

前端工程化:基于Vue.js 3.0的设计与实践
这里写目录标题 《前端工程化:基于Vue.js 3.0的设计与实践》书籍引言本书概述主要内容作者简介为什么选择这本书?结语 《前端工程化:基于Vue.js 3.0的设计与实践》书籍 够买连接—>https://item.jd.com/13952512.html 引言 在前端技术日…...

Linux☞进程控制
在终端执行命令时,Linux会建立进程,程序执行完,进程会被终止;Linux是一个多任务的OS,允许多个进程并发运行; Linxu中启动进程的两种途径: ①手动启动(前台进程(命令gedit)...后台进程(命令‘&’)) ②…...
mybatis离谱bug乱转类型
字符串传入的参数被转成了int: Param("online") String online<if test"online 0">and (heart_time is null or heart_time <![CDATA[ < ]]> UNIX_TIMESTAMP(SUBDATE(now(),INTERVAL 8 MINUTE)) )</if><if test"…...

视频监控管理平台LntonCVS视频汇聚平台充电桩视频监控应用方案
随着新能源汽车的广泛使用,公众对充电设施的安全性和可靠性日益重视。为了提高充电桩的安全管理和站点运营效率,LntonCVS公司推出了一套全面的新能源汽车充电桩视频监控与管理解决方案。 该方案通过安装高分辨率摄像头,对充电桩及其周边区域进…...
VS环境Python:深度探索与实用指南
VS环境Python:深度探索与实用指南 在编程领域,VS环境(Visual Studio环境)与Python的结合,为开发者们提供了一种强大而灵活的开发体验。这种结合不仅提升了开发效率,还增强了代码的可读性和可维护性。然而&…...

SpringBoot整合SpringSecurit(二)通过token进行访问
在文章:SpringBoot整合SpringSecurit(一)实现ajax的登录、退出、权限校验-CSDN博客 里面,使用的session的方式进行保存用户信息的,这一篇文章就是使用token的方式。 在其上进行的改造,可以先看SpringBoot…...
【算法训练 day50 打家劫舍、打家劫舍Ⅱ、打家劫舍Ⅲ】
目录 一、打家劫舍-LeetCode 198思路 二、打家劫舍Ⅱ-LeetCode 213思路 三.打家劫舍Ⅲ-LeeCode 337思路 一、打家劫舍-LeetCode 198 Leecode链接: leetcode 198 思路 dp数组含义为:当前数组范围下能偷到的最多的钱。递推公式为:dp[j] max(dp[j-2]nums[j],dp[j-1…...

YOLOv8改进 | 卷积模块 | 在主干网络中添加/替换蛇形卷积Dynamic Snake Convolution
💡💡💡本专栏所有程序均经过测试,可成功执行💡💡💡 蛇形动态卷积是一种新型的卷积操作,旨在提高对细长和弯曲的管状结构的特征提取能力。它通过自适应地调整卷积核的权重࿰…...
深入解析力扣183题:从不订购的客户(LEFT JOIN与子查询方法详解)
关注微信公众号 数据分析螺丝钉 免费领取价值万元的python/java/商业分析/数据结构与算法学习资料 在本篇文章中,我们将详细解读力扣第183题“从不订购的客户”。通过学习本篇文章,读者将掌握如何使用SQL语句来解决这一问题,并了解相关的复杂…...

牛客NC32 求平方根【简单 二分 Java/Go/C++】
题目 题目链接: https://www.nowcoder.com/practice/09fbfb16140b40499951f55113f2166c 思路 Java代码 import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可*** para…...

王道408数据结构CH3_栈、队列
概述 3.栈、队列和数组 3.1 栈 3.1.1 基本操作 3.1.2 顺序栈 #define Maxsize 50typedef struct{ElemType data[Maxsize];int top; }SqStack;3.1.3 链式栈 typedef struct LinkNode{ElemType data;struct LinkNode *next; }*LiStack;3.2 队列 3.2.1 基本操作 3.2.2 顺序存储…...

Angular 由一个bug说起之六:字体预加载
浏览器在加载一个页面时,会解析网页中的html和css,并开始加载字体文件。字体文件可以通过css中的font-face规则指定,并使用url()函数指定字体文件的路径。 比如下面这样: css font-face {font-family: MyFont;src: url(path/to/font.woff2…...

并查集进阶版
过关代码如下 #define _CRT_SECURE_NO_WARNINGS #include<bits/stdc.h> #include<unordered_set> using namespace std;int n, m; vector<int> edg[400005]; int a[400005], be[400005]; // a的作用就是存放要摧毁 int k; int fa[400005]; int daan[400005]…...

贪心(不相交的开区间、区间选点、带前导的拼接最小数问题)
目录 1.简单贪心 2.区间贪心 不相交的开区间 1.如何删除? 2.如何比较大小 区间选点问题 3.拼接最小数 1.简单贪心 比如:给你一堆数,你来构成最大的几位数 2.区间贪心 不相交的开区间 思路: 首先,如果有两个…...
golang循环变量捕获问题
在 Go 语言中,当在循环中启动协程(goroutine)时,如果在协程闭包中直接引用循环变量,可能会遇到一个常见的陷阱 - 循环变量捕获问题。让我详细解释一下: 问题背景 看这个代码片段: fo…...
DockerHub与私有镜像仓库在容器化中的应用与管理
哈喽,大家好,我是左手python! Docker Hub的应用与管理 Docker Hub的基本概念与使用方法 Docker Hub是Docker官方提供的一个公共镜像仓库,用户可以在其中找到各种操作系统、软件和应用的镜像。开发者可以通过Docker Hub轻松获取所…...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2
每日一言 今天的每一份坚持,都是在为未来积攒底气。 案例:OLED显示一个A 这边观察到一个点,怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 : 如果代码里信号切换太快(比如 SDA 刚变,SCL 立刻变&#…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)
目录 一、👋🏻前言 二、😈sinx波动的基本原理 三、😈波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、🌊波动优化…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...

DeepSeek源码深度解析 × 华为仓颉语言编程精粹——从MoE架构到全场景开发生态
前言 在人工智能技术飞速发展的今天,深度学习与大模型技术已成为推动行业变革的核心驱动力,而高效、灵活的开发工具与编程语言则为技术创新提供了重要支撑。本书以两大前沿技术领域为核心,系统性地呈现了两部深度技术著作的精华:…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...

Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...
Oracle实用参考(13)——Oracle for Linux物理DG环境搭建(2)
13.2. Oracle for Linux物理DG环境搭建 Oracle 数据库的DataGuard技术方案,业界也称为DG,其在数据库高可用、容灾及负载分离等方面,都有着非常广泛的应用,对此,前面相关章节已做过较为详尽的讲解,此处不再赘述。 需要说明的是, DG方案又分为物理DG和逻辑DG,两者的搭建…...