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

数据结构:链式二叉树初阶

目录

一.链式二叉树的逻辑结构

1.链式二叉树的结点结构体定义

2.链式二叉树逻辑结构

二.链式二叉树的遍历算法

1.前序遍历

2.中序遍历

3.后序遍历 

4.层序遍历(二叉树非递归遍历算法)

层序遍历概念:

层序遍历算法实现思路: 

层序遍历代码实现:

三.链式二叉树遍历算法的运用

1.前序遍历算法的运用

相关练习: 

2.后序遍历算法的运用

3.层序遍历算法的运用

问题来源:

四.链式二叉树其他操作接口的实现

1. 计算二叉树结点个数的接口

2.计算二叉树叶子结点的个数的接口

3.计算二叉树第k层结点个数的接口

4.二叉树的结点查找接口(在二叉树中查找值为x的结点)


一.链式二叉树的逻辑结构

1.链式二叉树的结点结构体定义

  • 树结点结构体定义:
    ​
    typedef int BTDataType;
    typedef struct BinaryTreeNode
    {BTDataType data;                //数据域struct BinaryTreeNode* left;    //指向结点左孩子的指针struct BinaryTreeNode* right;   //指向结点右孩子的指针
    }BTNode;​

2.链式二叉树逻辑结构

  • 这里先暴力"创建"一颗二叉树:
    //在内存堆区上申请结点的接口
    BTNode* BuyNode( BTDataType x)
    {BTNode* tem = (BTNode*)malloc(sizeof(BTNode));assert(tem);tem->data = x;tem->left = NULL;tem->right = NULL;return tem;
    }
    int main ()
    {BTNode* node1 = BuyNode(1);BTNode* node2 = BuyNode(2);BTNode* node3 = BuyNode(3);BTNode* node4 = BuyNode(4);BTNode* node5 = BuyNode(5);BTNode* node6 = BuyNode(6);node1->left = node2;node1->right = node4;node2->left = node3;node4->left = node5;node4->right = node6;//其他操作return 0;
    }
  • 树的逻辑结构图示:

  1. 每个树结点都有其左子树和右子树

  2. 因此关于链式二叉树的递归算法的设计思路是:关于树T的问题可以分解为其左子树和右子树的问题,树T的左子树和右子树的问题又可以以同样的方式进行分解,因此就形成了递归

  3. 关于链式二叉树递归算法的核心思维:左右子树分治思维

二.链式二叉树的遍历算法

遍历二叉树的递归框架:

  1. 函数的抽象意义完成整棵树的遍历
  2. 为了完成整棵树的遍历我们先要完成该树的左子树的遍历右子树的遍历
  3. 左子树和右子树的遍历又可以以相同的方式进行问题拆分,于是便形成了递归(数学上的递推迭代)
//递归遍历二叉树的基本函数结构
void Order(BTNode* root)
{if (NULL == root){return;}对当前结点进行某种处理的语句位置1(前序);Order(root->left);  //遍历左子树的递归语句对当前结点进行某种处理的语句位置2(中序);Order(root->right); //遍历右子树的递归语句对当前结点进行某种处理的语句位置3(后序);
}
  • 通过这个递归函数,我们可以遍历二叉树的每一个结点:(假设根结点的地址为root)
  • 根据函数中对当前的root结点进行某种处理的代码语句位置可将遍历二叉树的方式分为前序遍历(位置1),中序遍历(位置2),后序遍历(位置3)三种

1.前序遍历

//二叉树前序遍历
void PreOrder(BTNode* root)
{if (NULL == root){printf("NULL->");//为了方便观察我们将空结点打印出来return;}printf("%d->", root->data); //当前结点处理语句PreOrder(root->left);       //向左子树递归PreOrder(root->right);      //向右子树递归
}

  • 以图中的树为例调用前序遍历函数:
    PreOrder(root); //root为树根地址

    递归函数执行过程中函数栈帧的逻辑结构分布以及代码语句执行次序图示:

    递归函数执行过程中函数栈帧的物理结构分布:

  1. 当递归执行到图中的第4步是函数栈帧的物理结构:

  2. 当递归执行到图中的第10步是函数栈帧的物理结构: 

  3. 当递归执行到图中的第14步是函数栈帧的物理结构: 

  4. 当递归执行到图中的第22步是函数栈帧的物理结构: 

  • 递归函数执行过程中同一时刻开辟的函数栈帧的最大个数取决于树的高度:因此递归遍历二叉树的空间复杂度为:O(logN);

2.中序遍历

//二叉树中序遍历
void InOrder(BTNode* root)
{if (NULL == root){printf("NULL->");   //为了方便观察我们打印出空结点return;}InOrder(root->left);        //向左子树递归printf("%d->", root->data); //打印结点值(root处理语句)InOrder(root->right);       //向右子树递归
}
  •  递归函数执行过程分析方法与前序遍历类似
  • 对于图中的二叉树,中序遍历结点值打印次序为:

3.后序遍历 

//二叉树后序遍历
void BackOrder(BTNode* root)
{if (NULL == root){printf("NULL->");       //为了方便观察我们打印出空结点return;}BackOrder(root->left);      //向左子树递归BackOrder(root->right);     //向右子树递归printf("%d->", root->data); //打印结点值(root处理语句)
}
  •  递归函数执行过程分析方法与前序遍历类似
  • 对于图中的二叉树,后序遍历结点值打印次序为:

4.层序遍历(二叉树非递归遍历算法)

层序遍历概念:

  • 二叉树的层序遍历借助结点指针队列循环实现的二叉树遍历算法

  • 树结点的遍历次序从低层到高层,同一层从左到右进行遍历的:

层序遍历算法实现思路: 

  • 创建一个队列,将树的根结点地址插入队列中;(队列中的数据先进先出,数据从队尾入队从队头出队)
  • 接着开始执行循环语句
  • 每一次循环,取出队头的一个指针,对其进行处理(打印数值等等处理),若队头指针不为空指针,则将队头指针指向的结点左右孩子指针插入队列中,重复循环直到队列为空为止.
  • 树结点指针入队次序图示:
  • 经过分析可知:队列中的树结点地址就是按照树结点的层序逻辑顺序进行排列的(从根结点开始,前一层结点指针出队后带入下一层结点的指针),因此该算法可以完成二叉树的层序遍历
  • 算法gif图示:

层序遍历代码实现:

  • 为了方便我们直接使用C++STL的queue类模板 (VS2022的queue对象数据入队(尾插)接口为push,数据出队(头删)接口为pop)(不同编译器接口命名可能不同)
  • 如果要使用C语言则需要自己手动实现队列
void LevelOrder(BTNode* root)
{queue<BTNode*> NodeStore;			//创建一个队列用于存储结点指针NodeStore.push(root);				//将根结点指针插入队列中while (!NodeStore.empty())			//若队列不为空则循环继续{BTNode* tem = NodeStore.front();//保存队头指针NodeStore.pop();				//队头指针出队if (nullptr != tem){cout << (tem->data)<<' ';	//处理出队的结点(这里是打印其结点值)}if (nullptr != tem)				//若出队结点不为空,则将其孩子结点指针带入队列{NodeStore.push(tem->left);  //将出队结点的左孩子指针带入队列NodeStore.push(tem->right); //将出队结点的右孩子指针带入队列}}cout << endl;
}

三.链式二叉树遍历算法的运用

1.前序遍历算法的运用

前序遍历递归:

  1. 先处理根
  2. 向左子树递归
  3. 向右子树递归
  • 由于根处理语句前序递归函数中是首先执行的,因此我们可以利用前序遍历递归框架来实现链式二叉树的递归构建(在前序递归的框架下我们可以实现先创建根结点,再创建根结点的左右子树,中序和后序递归无法完成树的递归构建)

相关练习: 

二叉树遍历_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/4b91205483694f449f94c179883c1fef?tpId=60&&tqId=29483&rp=1&ru=/activity/oj&qru=/ta/tsing-kaoyan/question-ranking(本题源自清华大学OJ)

问题描述:

编一个程序,读入用户输入一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。

例如:先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。

(输入的字符串,长度不超过100.)

示例:

  • 输入:abc##de#g##f###
  • c b e g d f a 

问题分析:

  • 以字符串"abc##de#g##f###"为例,先分析一下在先序遍历的逻辑顺序下字符串所对应的二叉树结构:如果按照中序逻辑顺序打印这颗树结果为:c-->b-->e-->g-->d-->f-->a;下面给出各个#所代表的空树在树中的逻辑位置:
  • 递归构建分析:
  • 进一步分析可知:给定的字符串序列必须满足二叉树的前序序列逻辑,不然该字符串序列便无法被转换成一颗完整的二叉树
  • 借助递归分析我们可以实现二叉树的递归构建代码
  1. 为了方便理解, 先给出主函数测试代码,熟悉递归函数调用方式:
    int main() 
    {char arr[101] = {0};scanf("%s",arr);                        //输入待转换的字符串int ptr = 0;                            //用于遍历字符串的下标变量TreeNode * root = CreateTree(arr,&ptr); //调用建树函数InOrder(root);                          //对树进行中序遍历return 0;
    }
  2. 建树递归函数首部:

    TreeNode * CreateTree(char * input,int* ptr)

  • input是待转换的字符串的首地址

  • ptr是用于遍历字符串的下标变量的地址,这里一定要传址,因为我们要在不同的函数栈帧中修改同一个字符数组下标变量

  • 函数实现:

    TreeNode * CreateTree(char * input,int* ptr)
    {if('#'==input[*ptr])            //#代表空树,直接将空指针返回给上层结点即可{++*ptr;return nullptr;}TreeNode * root = new TreeNode;     //申请新结点root->word = input[*ptr];           //结点赋值 ++*ptr;                             //字符数组下标加一处理下一个字符root->left = CreateTree(input,ptr); //向左子树递归root->right = CreateTree(input,ptr);//向右子树递归return root;                        //将本层结点地址返回给上一层结点(或返回给根指针变量)
    }
  • 整体题解代码:

    #include <iostream>
    #include <string>
    using namespace std;struct TreeNode  //树结点结构体
    {char word;TreeNode * left;TreeNode * right;
    };//ptr是字符串数组下标的地址,这里一定要传址,因为我们要在不同的函数栈帧中修改同一个字符数组下标变量
    TreeNode * CreateTree(char * input,int* ptr)
    {if('#'==input[*ptr])            //#代表空树,直接将空指针返回给上层结点即可{++*ptr;return nullptr;}TreeNode * root = new TreeNode;     //申请新结点root->word = input[*ptr];           //结点赋值 ++*ptr;                             //字符数组下标加一处理下一个字符root->left = CreateTree(input,ptr); //向左子树递归root->right = CreateTree(input,ptr);//向右子树递归return root;                        //将本层
    }void InOrder(TreeNode * root)           //中序遍历递归
    {if(nullptr == root){return;}InOrder(root->left);printf("%c ",root->word);InOrder(root->right);
    }int main() 
    {char arr[101] = {0};scanf("%s",arr);int ptr = 0;TreeNode * root = CreateTree(arr,&ptr);InOrder(root);return 0;
    }

2.后序遍历算法的运用

后序遍历算法:

  1. 先向左子树递归
  2. 再向右子树递归
  3. 完成左右子树的处理后再处理根

后序遍历算法的思想刚好可以适用于二叉树的销毁过程. (前序和中序算法不能完成二叉树的销毁,因为一旦我们释放了当前结点便无法再向左右子树进行递归(地址丢失))

  • 二叉树销毁接口:
    // 二叉树销毁
    void BinaryTreeDestory(BTNode* root)
    {if (NULL == root){return;}BinaryTreeDestory(root->left);BinaryTreeDestory(root->right);free(root);						//释放到当前结点的内存空间}
  • 二叉树销毁过程图示:

3.层序遍历算法的运用

层序遍历算法可以用于检验一颗二叉树是否为完全二叉树;

问题来源:

958. 二叉树的完全性检验 - 力扣(Leetcode)icon-default.png?t=N176https://leetcode.cn/problems/check-completeness-of-a-binary-tree/问题描述:

给定一个二叉树的 root ,确定它是否是一个完全二叉树 。

在一个 完全二叉树中,除了树的最后一层以外,其他层是完全被填满的,并且最后一层中的所有结点都是靠左排列的。

958. 二叉树的完全性检验 - 力扣(Leetcode)

题解接口:

class Solution 
{
public:bool isCompleteTree(TreeNode* root) {}
};

 关于完全二叉树的结构特点参见青菜的博客:http://t.csdn.cn/6qEroicon-default.png?t=N176http://t.csdn.cn/6qEro

问题分析:

  • 完全二叉树的结构特点是各层结点连续排列(各结点编号是连续的)
  • 因此层序遍历完全二叉树,各结点指针在队列中都是连续排列的(即各结点指针之间不会出现空指针)
  • 根据完全二叉树的结构特点,一旦层序遍历完全二叉树的过程中遍历到了空指针,则说明已经遍历到了二叉树的最后一层
  • 我们可以利用层序遍历算法遍历二叉树,当遇到第一个出队的空指针时,检验后续出队的指针中是否还存在非空结点指针,如果后续出队的指针中存在非空指针说明该树不是完全二叉树,否则说明该树是一颗完全二叉树。
  • 算法图示:

 

题解代码: 

class Solution 
{
public:bool isCompleteTree(TreeNode* root) {queue<TreeNode*> ans;ans.push(root);        //将根结点指针插入队列while(!ans.empty())    //队列不为空则循环继续{TreeNode* tem = ans.front();ans.pop();         //取出队头指针存入tem变量中if(nullptr == tem) //遇到第一个出队的空指针,停止循环进行下一步判断{break;}else{ans.push(tem->left);   //将出队指针的孩子结点指针带入队列ans.push(tem->right);}}while(!ans.empty()){TreeNode* tem = ans.front();ans.pop();         //取出队头指针存入tem变量中if(nullptr != tem) //第一个出队的空指针后续存在非空结点指针,说明该树不是完全二叉树{return false;}}return true;           //所有结点指针完成入队出队则验证了该树是完全二叉树}
};

 

四.链式二叉树其他操作接口的实现

链式二叉树的众多递归接口都是通过左右子树分治递归的思想来实现的

 树结点结构体定义:

typedef int BTDataType;
typedef struct BinaryTreeNode
{BTDataType data;                //数据域struct BinaryTreeNode* left;    //指向结点左孩子的指针struct BinaryTreeNode* right;   //指向结点右孩子的指针
}BTNode;

1. 计算二叉树结点个数的接口

函数首部:

int BinaryTreeSize(BTNode* root)
  • 将接口函数抽象为某颗树的结点个数A(T)
  • 抽象出递推公式: A(T) = A(T->right) + A(T->left) + 1;
  • 递推公式的含义是: 树T的结点总个数 = 树T左子树的结点总个数 + 树T右子树的结点总个数 + 1个树T的树根(本质上是左右子树分治思想)
  • 由此可以设计出递归函数:
    int BinaryTreeSize(BTNode* root)
    {//空树则返回0if (NULL == root){return 0;}//化为子问题进行分治return BinaryTreeSize(root->left) + BinaryTreeSize(root->right) + 1;
    }
    

    将下图中的树的根结点地址传入递归函数:

    递归函数执行过程的简单图示: 

     

2.计算二叉树叶子结点的个数的接口

函数首部:

int BinaryTreeLeafSize(BTNode* root)
  • 将接口函数抽象为某颗树的叶子结点的个数A(T)
  • 可以抽象出递推公式:A(T) = A(T->left) + A(T->right)
  • 递推公式的含义是: 树T的叶子总数 = T的左子树的叶子总数 + T的右子树的叶子总数
  • 由此可以设计出递归函数:
    int BinaryTreeLeafSize(BTNode* root)
    {if (NULL == root)                                      //空树不计入个数{return 0;}else if (NULL == root->left && NULL == root->right)   //判断当前树是否为树叶(是树叶则返回1,计入叶子结点个数){return 1;}//化为子问题进行分治return BinaryTreeLeafSize(root->left) + BinaryTreeLeafSize(root->right);
    }

    将下图中的树的根结点地址传入递归函数:

     递归函数执行过程的简单图示: 

3.计算二叉树第k层结点个数的接口

函数首部:

int BinaryTreeLevelKSize(BTNode* root, int k)
  • 将接口函数抽象为某颗树的第k层结点个数A(T,k)
  • 可以抽象出递推公式: A(T,k) = A(T->left,k-1) + A(T->right,k-1)
  • 递推公式的含义是: 树T的第k层结点个数 = 树T左子树的第k-1层结点数 + 树T右子树的第k-1层结点数
  • 由此可以设计出递归函数:
    int BinaryTreeLevelKSize(BTNode* root, int k)
    {assert(k >= 1);//树为空返回0if (NULL == root){return 0;}else if (root && k == 1)	//问题分解到求子树的第一层结点(即求树根的个数,树根的个数为1){return 1;}else{return BinaryTreeLevelKSize(root->left, k - 1) + BinaryTreeLevelKSize(root->right, k - 1);}
    }

    将下图中的树的根结点地址传入递归函数:

    递归函数执行过程的简单图示: 

     

4.二叉树的结点查找接口(在二叉树中查找值为x的结点)

 函数首部:

BTNode* BinaryTreeFind(BTNode* root, BTDataType x)

递归的思路:

  • 若当前树不为空树(若为空树则直接返回空指针),先判断树根是不是要找的结点
  • 若树根不是要找的结点,则往左子树递归查找
  • 若左子树找不到最后再往右子树递归查找
  • 若最后左右子树中都找不到待找结点则返回空指针
  • 设计递归函数:
    BTNode* BinaryTreeFind(BTNode* root, BTDataType x)
    {//寻找到空树则返回空(说明在某条连通路径上不存在待找结点)if (NULL == root){return NULL;}//判断树根是否为待找结点,若判断为真则返回该结点地址else if (root->data == x){return root;}//若树根不是要找的结点, 则往左子树找BTNode* leftret = BinaryTreeFind(root->left, x);if (leftret){return leftret;}//若左子树中不存在待找结点,则往右子树找BTNode* rightret = BinaryTreeFind(root->right, x);if (rightret){return rightret;}//若左右子树中都找不到则说明不存在待找结点,返回空return NULL;
    }
    

    将下图中的树的根结点地址传入递归函数:

    递归函数执行过程的简单图示: 

分治递归的思想是核心哦!!!! 

相关文章:

数据结构:链式二叉树初阶

目录 一.链式二叉树的逻辑结构 1.链式二叉树的结点结构体定义 2.链式二叉树逻辑结构 二.链式二叉树的遍历算法 1.前序遍历 2.中序遍历 3.后序遍历 4.层序遍历(二叉树非递归遍历算法) 层序遍历概念: 层序遍历算法实现思路: 层序遍历代码实现: 三.链式二叉树遍历算…...

公式编写1000问9-12

9.问: 买入&#xff1a;日线创100日新高 ,周线(5周&#xff09;BIAS>10 卖出&#xff1a;2日收盘在30线下方 注&#xff1a;买卖都只要单一信号即可&#xff0c;不要连续给出信号 我今天才开始学习编写&#xff0c;可是没有买入信号&#xff0c;不知道哪错了&#xff1f; B1…...

C++11:类的新功能和可变参数模板

文章目录1. 新增默认成员函数1.1 功能1.2 示例2. 类成员变量初始化3. 新关键字3.1 关键字default3.2 关键字delete补充3.3 关键字final和override4. 可变参数模板4.1 介绍4.2 定义方式4.3 展开参数包递归展开参数包优化初始化列表展开参数包逗号表达式展开参数包补充5. emplace…...

【Java学习笔记】15.Java 日期时间(1)

Java 日期时间 java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象。 第一个构造函数使用当前日期和时间来初始化对象。 Date( )第二个构造函数接收一个参数&#xff0c;该参数是从 1970 年 1 月 1 日起的毫秒数。 Date(long …...

在ROS2中,通过MoveIt2控制Gazebo中的自定义机械手

目前的空余时间主要都在研究ROS2&#xff0c;最终目的是控制自己用舵机组装的机械手。 由于种种原因&#xff0c;先控制Gazebo的自定义机械手。 先看看目前的成果 左侧是rviz2中的moveit组件的机械手&#xff0c;右侧是gazebo中的机械手。在moveit中进行路径规划并执行后&#…...

Java-线程池 原子性 类

Java-线程池 原子性 类线程池构造方法调用Executors静态方法创建调用方法直接创建线程池对象原子性volatile-问题出现原因:volatile解决原子性AtomicInteger的常用方法悲观锁和乐观锁synchronized(悲)和CAS(乐)的区别并发工具类Hashtable集合ConcurrentHashMap原理:CountDownLa…...

力扣sql简单篇练习(二十五)

力扣sql简单篇练习(二十五) 1 无效的推文 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # Write your MySQL query statement below SELECT tweet_id FROM Tweets WHERE CHAR_LENGTH(content)>151.3 运行截图 2 求关注者的数量 2.1 基本题目内…...

计算机网络:OSPF协议和链路状态算法

OSPF协议 开放最短路经优先OSPF协议是基于最短路径算法SPF,其主要特征就是使用分布式的链路状态协议OSPF协议的特点&#xff1a; 1.使用泛洪法向自治系统中的所有路由器发送信息&#xff0c;即路由器通过输出端口向所有相邻的路由器发送信息&#xff0c;而每一个相邻的路由器又…...

利用表驱动法+策略模式优化switch-case

1.前言 我有一个需求&#xff1a;有四个系统需要处理字段&#xff0c;一开始利用switch-case进行区分编码&#xff0c;后期字段处理越来越多&#xff0c;导致switch-case代码冗余&#xff0c;不太好&#xff0c;然后想通过java单继承多实现的性质进行优化。 2.实现 2.1定义S…...

SpringBoot创建和使用

目录 什么是SpringBoot SpringBoot的优点 SpringBoot项目的创建 1、使用idea创建 2、项目目录介绍和运行 Spring Boot配置文件 1、配置文件 2、配置文件的格式 3、properties 3.1、properties基本语法 3.2、读取配置文件 3.3、缺点 4、yml 4.1、优点 4.2、yml基本…...

which、whereis、locate文件查找命令

Linux下查找文件的命令有which、whereis、locate和find&#xff0c;find命令因要遍历文件系统&#xff0c;导致速度较慢&#xff0c;而且还会影响系统性能&#xff0c;而且命令选项较多&#xff0c;就单独放一篇介绍&#xff0c;可参见find命令——根据路径和条件搜索指定文件_…...

Uipath Excel 自动化系列14-SaveExcelFile(保存Excel)

活动描述 SaveExcelFile 保存Excel:保存工作簿&#xff0c;在修改 Excel 文件的用户界面自动化活动之后使用此活动&#xff0c;以保存对文件的更改 SaveExcelFile As 另存Excel : 将workbook 另存为文件 SaveExcelFile As PDF &#xff1a;将Excel 另存为PDF文件。该三个活…...

MyBatis学习

MyBatis优点 轻量级&#xff0c;性能出色 SQL 和 Java 编码分开&#xff0c;功能边界清晰。Java代码专注业务、SQL语句专注数据 开发效率稍逊于HIbernate&#xff0c;但是完全能够接受 补充&#xff1a;POJO 一&#xff1a;什么是POJO POJO的名称有多种&#xff0c;pure old…...

高速PCB设计指南系列(二)

第三篇 高速PCB设计 &#xff08;一&#xff09;、电子系统设计所面临的挑战   随着系统设计复杂性和集成度的大规模提高&#xff0c;电子系统设计师们正在从事100MHZ以上的电路设计&#xff0c;总线的工作频率也已经达到或者超过50MHZ&#xff0c;有的甚至超过100MHZ。目前…...

uniapp项目打包上线流程

平台&#xff1a;h5小程序app &#xff08;安卓&#xff09;小程序打包上线流程第一步&#xff1a;登录小程序公众平台第二步&#xff1a;hbuilderx打包小程序1.在mainfest.json文件中进行相关配置2.需要将项目中的网络请求改为https协议做为生产环境&#xff08;配置项目的环境…...

垃圾回收:垃圾数据如何自动回收

有些数据被使用之后&#xff0c;可能就不再需要了&#xff0c;我们把这种数据称为垃圾数据。如果这些垃圾数据一直保存在内存中&#xff0c;那么内存会越用越多&#xff0c;所以我们需要对这些垃圾数据进行回收&#xff0c;以释放有限的内存空间 不同语言的垃圾回收策略 通常…...

苹果笔不用原装可以吗?Apple Pencil平替笔推荐

近些年来&#xff0c;不管是学习还是画画&#xff0c;都有不少人喜欢用ipad。而ipad的用户&#xff0c;也是比较重视它的实用价值&#xff0c;尤其是不少人都想要好好利用来进行学习记笔记。事实上&#xff0c;有很多替代品都能替代Apple Pencil&#xff0c;仅仅用于记笔记就没…...

uniCloud基础使用-杂文

获取openID云函数use strict; exports.main async (event, context) > {//event为客户端上传的参数console.log(event : , event)// jscode2session 微信小程序登录接口&#xff0c;获取openidconst {code} event;// 云函数中如需要请求其他http服务&#xff0c;则使用uni…...

vector的模拟实现

文章目录vector的模拟实现vector 结构定义1. vector的迭代器的实现2. vector四个默认成员函数2.1 构造函数2.1.1 无参2.1.2 n个val初始化2.1.3 迭代器初始化2.2 析构函数2.3 拷贝构造函数2.3.1 传统写法2.3.2 现代写法2.4 赋值重载运算符3. 管理数组相关接口3.1 reserve3.2 res…...

【无标题】compose系列教程-4.相对布局ConstraintLayout的使用

相对布局在Compose中被称为ConstraintLayout&#xff0c;它可以让您以相对于其他元素的方式放置元素。 以下是使用ConstraintLayout实现相对布局的示例代码&#xff1a; Composable fun ConstraintLayoutExample() { ConstraintLayout(modifier Modifier.fillMaxSize()…...

JavaEE简单示例——Bean管理

简单介绍&#xff1a; 在这一章节我们会比较详细的介绍我们在之前的测试类中以及Bean管理XML配置文件中所使用到的类和方法&#xff0c;以及XML中配置的属性所代表的详细含义。以及之前我们反复提到但是一直没有详细的讲解的一个东西&#xff1a;容器。我们可以大致的有一个概…...

react+antdpro+ts实现企业级项目四:注册页面实现及useEmotionCss的介绍

创建文件路径并注册register路由 在pages/User下创建Register文件夹并创建index.tsx文件 然后在config/routes创建register注册路由。注册完后&#xff0c;当在登陆页面点击注册按钮时就可以跳转到此注册页面而不会报404了。 export default [{path: /user,layout: false,rou…...

Shifu基础功能:数据采集

数据采集 我们可以通过HTTP/gRPC与deviceShifu进行通信&#xff0c;deviceShifu会将我们发送的请求转换成设备所支持协议的形式&#xff0c;并发送给设备。 当设备接收到指令之后&#xff0c;数据会传输到deviceShifu中&#xff0c;之后deviceShifu将数据作为我们请求的返回值…...

代码随想录算法训练营day54 | 动态规划之子序列 392.判断子序列 115.不同的子序列

day54392.判断子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺序5.举例推导dp数组115.不同的子序列1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义2.确定递推公式3.dp数组如何初始化4.确定遍历顺…...

MCAL知识点(三):Port与Dio配置

目录 1、概述 2、 Port的EB-tresos配置 2.1、创建模块 2.2 General配置 2.3、PortCnfigSet 2.4、Port的属性...

初识C++需要了解的一些东西(1)

目录&#x1f947;命名空间&#x1f3c5;存在原因&#x1f3f5;命名空间定义&#x1f3a7;命名空间的3种使用方式&#x1f3c6;C输入和输出&#x1f31d;缺省参数&#x1f31c;缺省参数概念⭐️缺省参数分类☀️函数重载&#x1f525;引用&#x1f31a;引用概念&#x1f313;引…...

友元函数的使用大全

概述 我们知道&#xff0c;C的类具有封装和信息隐藏的特性。一般情况下&#xff0c;我们会封装public的成员函数供用户调用&#xff0c;而将成员变量设置为private或protected。但在一些比较复杂的业务情况下&#xff0c;可能需要去访问对象中大量的private或protected成员变量…...

QT学习笔记-QT多项目系统中如何指定各项目的编译顺序

QT学习笔记-QT多项目系统中如何指定各项目的编译顺序背景环境解决思路具体操作背景 为了更好的复用程序功能以及更优雅的管理程序&#xff0c;有经验的程序员通常要对程序进行分层和模块化设计。在QT/C这个工具中同样可以通过创建子项目的方式对程序进行模块化&#xff0c;在这…...

JWT令牌解析及刷新令牌(十一)

写在前面&#xff1a;各位看到此博客的小伙伴&#xff0c;如有不对的地方请及时通过私信我或者评论此博客的方式指出&#xff0c;以免误人子弟。多谢&#xff01;如果我的博客对你有帮助&#xff0c;欢迎进行评论✏️✏️、点赞&#x1f44d;&#x1f44d;、收藏⭐️⭐️&#…...

Hibernate学习(一)

Hibernate学习&#xff08;一&#xff09; Hibernate框架的概述&#xff1a; 一&#xff1a;什么是框架&#xff1a;指软件的半成品&#xff0c;已经完成了部分功能。 二&#xff1a;EE的三层架构&#xff1a; 1.EE的三层经典架构&#xff1a; 我在这里主要学的是ssh框架。 三…...

Go的 context 包的使用

文章目录背景简介主要方法获得顶级上下文当前协程上下文的操作创建下级协程的Context场景示例背景 在父子协程协作过程中, 父协程需要给子协程传递信息, 子协程依据父协程传递的信息来决定自己的操作. 这种需求下可以使用 context 包 简介 Context通常被称为上下文&#xff…...

微服务为什么要用到 API 网关?

本文介绍了 API 网关日志的价值&#xff0c;并以知名网关 Apache APISIX 为例&#xff0c;展示如何集成 API 网关日志。 作者程小兰&#xff0c;API7.ai 技术工程师&#xff0c;Apache APISIX Contributor。 原文链接 什么是微服务 微服务架构&#xff08;通常简称为微服务&a…...

SWUST OJ 1042: 中缀表达式转换为后缀表达式【表达式转逆波兰表达式】

题目描述 中缀表达式是一个通用的算术或逻辑公式表示方法&#xff0c;操作符是以中缀形式处于操作数的中间&#xff08;例&#xff1a;3 4&#xff09;&#xff0c;中缀表达式是人们常用的算术表示方法。后缀表达式不包含括号&#xff0c;运算符放在两个运算对象的后面&#…...

Matlab基础知识

MATLAB批量读入文件和导出文件一、 批量读入文件1.若文件名称有序&#xff0c;则按照文件名称规律循环读取文件(1)读入不同的excelfor i1:1:10strstrcat(F:\数据\v,int2str(i),.xlsx); %连接字符串形成文件名Axlsread(str); end注&#xff1a;变量i为整数时&#xff0c;可以用i…...

动手学深度学习【2】——softmax回归

动手学深度学习网址&#xff1a;动手学深度学习 注&#xff1a;本部分只对基础知识进行简单的介绍并附上完整的代码实现&#xff0c;更多内容可参考上述网址。 前言 前面一节我们谈到了线性回归&#xff0c;它解决的是预测某个值的问题。但是在日常生活这&#xff0c;除了预测…...

深入理解Activity的生命周期

之前学习安卓的时候只是知道生命周期是什么&#xff0c;有哪几个&#xff0c;但具体的详细的东西却不知道&#xff0c;后来看过《Android开发艺术探索》和大量博客之后&#xff0c;才觉得自己真正有点理解生命周期&#xff0c;本文是我对生命周期的认识的总结。废话少说先上图。…...

Go语言刷题常用数据结构和算法

数据结构 字符串 string 访问字符串中的值 通过下标访问 s1 : "hello world"first : s[0]通过切片访问 s2 : []byte(s1) first : s2[0]通过for-range循环访问 for i, v : range s1 {fmt.Println(i, v) }查询字符是否属于特定字符集 // 判断字符串中是否包含a、b、…...

深入vue2.x源码系列:手写代码来模拟Vue2.x的响应式数据实现

前言 Vue响应式原理由以下三个部分组成&#xff1a; 数据劫持&#xff1a;Vue通过Object.defineProperty()方法对data中的每个属性进行拦截&#xff0c;当属性值发生变化时&#xff0c;会触发setter方法&#xff0c;通知依赖更新。发布-订阅模式&#xff1a;Vue使用发布-订阅…...

Linux线程控制

本篇我将学习如何使用多线程。要使用多线程&#xff0c;因为Linux没有给一般用户直接提供操作线程的接口&#xff0c;我们使用的接口&#xff0c;都是系统工程师封装打包成原生线程库中的。那么就需要用到原生线程库。因此&#xff0c;需要引入-lpthread&#xff0c;即连接原生…...

【LeetCode】剑指 Offer(20)

目录 题目&#xff1a;剑指 Offer 38. 字符串的排列 - 力扣&#xff08;Leetcode&#xff09; 题目的接口&#xff1a; 解题思路&#xff1a; 代码&#xff1a; 过啦&#xff01;&#xff01;&#xff01; 写在最后&#xff1a; 题目&#xff1a;剑指 Offer 38. 字符串的…...

FutureTask中的outcome字段是如何保证可见性的?

最近在阅读FutureTask的源码是发现了一个问题那就是源码中封装结果的字段并没有使用volatile修饰&#xff0c;源码如下&#xff1a;public class FutureTask<V> implements RunnableFuture<V> {/*** 状态变化路径* Possible state transitions:* NEW -> COMPLET…...

直播回顾 | 聚焦科技自立自强,Bonree ONE 助力国产办公自动化平稳替代

3月5日&#xff0c;两会发布《政府工作报告》&#xff0c;强调科技政策要聚焦自立自强。 统计显示&#xff0c;2022年金融信创项目数同比增长300%&#xff0c;金融领域信创建设当前已进入发展爆发期&#xff0c;由国有大型银行逐渐向中小型银行、非银金融机构不断扩展。信创云…...

深入理解Linux进程

进程参数和环境变量的意义一般情况下&#xff0c;子进程的创建是为了解决某个问题。那么解决问题什么问题呢&#xff1f;这个就需要进程参数和环境变量来进行决定的。子进程解决问题需要父进程的“数据输入”(进程参数 & 环境变量)设计原则&#xff1a;3.1 子进程启动的时候…...

Vue3之组件间的双向绑定

何为组件间双向绑定 我们都知道当父组件改变了某个值后&#xff0c;如果这个值传给了子组件&#xff0c;那么子组件也会自动跟着改变&#xff0c;但是这是单向的&#xff0c;使用v-bind的方式&#xff0c;即子组件可以使用父组件的值&#xff0c;但是不能改变这个值。组件间的…...

Java语法基础(一)

目录 代码注释方法 编码规范 基本数据类型及取值范围 变量和常量的声明与赋值 变量 常量 标识符 基本数据类型的使用 整数类型的使用 浮点类型的使用 布尔类型的使用 字符类型的使用 代码注释方法 单行注释&#xff1a;使用“//”进行单行注释多行注释&#xff1a;使…...

优思学院|零质量控制是什么概念?

零质量控制&#xff08;Zero Quality Control&#xff09;是指一个理想的系统&#xff0c;可以生产没有任何缺陷的产品&#xff0c;因此不需要频繁的检查&#xff0c;从而节省时间和金钱。那些追求过程优化并致力于持续过程改进的组织将零质量控制&#xff08;Zero Quality Con…...

2023-03-09 CMU15445-Query Execution

摘要: CMU15445, Project #3 - Query Execution 参考: Project #3 - Query Execution | CMU 15-445/645 :: Intro to Database Systems (Fall 2022) https://github.com/cmu-db/bustub 要求: OVERVIEW At this point in the semester, you have implemented the internal co…...

vuedraggable的使用

Draggable为基于Sortable.js的vue组件&#xff0c;用以实现拖拽功能。 特性 支持触摸设备 支持拖拽和选择文本 支持智能滚动 支持不同列表之间的拖拽 不以jQuery为基础 和视图模型同步刷新 和vue2的国度动画兼容 支持撤销操作 当需要完全控制时&#xff0c;可以抛出所有变化 可…...

双馈风力发电机-900V直流混合储能并网系统MATLAB仿真

MATLAB2016b主体模型&#xff1a;双馈感应风机模块、采用真实风速数据。混合储能模块、逆变器模块、转子过电流保护模块、整流器控制模块、逆变器控制模块。直流母线电压&#xff1a;有功、无功输出&#xff08;此处忘记乘负一信号输出&#xff09;&#xff0c;所以是负的。蓄电…...

leader选举过程

启动electionTimer&#xff0c;进行leader选举。 一段时间没有leader和follower通信&#xff0c;就会超时&#xff0c;开始选举leader过程。有个超时时间&#xff0c;如果到了这个时间&#xff0c;就会触发一个回调函数。具体如下: private void handleElectionTimeout() {boo…...