【习题】几道二叉树题目,进来看看你会不?

news2024/9/28 1:20:53

几道二叉树题目解析

  • 前言
  • 正式开始
    • 1. 根据二叉树创建字符串(力扣606)
      • 题目描述
      • 解析
      • 代码
    • 2. 二叉树的层序遍历1(力扣102)
      • 题目描述
      • 解析
      • 代码
    • 3. 二叉树的层序遍历2(力扣107)
      • 代码
    • 4. 二叉树的最近公共祖先(力扣236)
      • 题目描述
      • 解析
        • 解法一
        • 解法二
      • 代码
        • find查找解法
        • 双栈解法
      • 本题的一点拓展
        • 如果该树是一棵二叉搜索树
        • 如果该树结构为三叉链
    • 5. 二叉搜索树与双向链表(牛客JZ36)
      • 题目描述
      • 解析
      • 代码
    • 6. 从前序与中序遍历序列构造二叉树(力扣105)
      • 题目描述
      • 解析
      • 代码
    • 7. 从中序与后序遍历序列构造二叉树(力扣106)
      • 题目描述
      • 解析
      • 代码
    • 8. 非递归实现二叉树的前序遍历(力扣144)
      • 题目描述
      • 解析
      • 代码
    • 9. 非递归实现二叉树的中序遍历(力扣94)
      • 题目描述
      • 解析
      • 代码
    • 10. 非递归实现二叉树的后序遍历(力扣145)
      • 题目描述
      • 解析
      • 代码

在这里插入图片描述

前言

这里给出如下题目,各位可以先点击链接看看你是否会做:

  1. 根据二叉树创建字符串(力扣606)
  2. 二叉树的层序遍历1(力扣102)
  3. 二叉树的层序遍历2(力扣107)
  4. 二叉树的最近公共祖先(力扣236)
  5. 二叉搜索树与双向链表(牛客JZ36)
  6. 从前序与中序遍历序列构造二叉树(力扣105)
  7. 从中序与后序遍历序列构造二叉树(力扣106)
  8. 非递归实现二叉树的前序遍历(力扣144)
  9. 非递归实现二叉树的中序遍历(力扣94)
  10. 非递归实现二叉树的后序遍历(力扣145)

如果上面这些题不是全会的话,建议看看我的解析,我尽量讲的详细一点。
如果上面这些题都会的话,也可以看看我的解析,看看你的做法和我的做法都一样不。

那么下面就挨着讲。

正式开始

每道题都是先给题目描述,然后给解析,最后给代码。

1. 根据二叉树创建字符串(力扣606)

在这里插入图片描述

题目描述

题目想让我们将二叉树的每个节点的根和左子树右子树建立一一对应的关系,并将这些关系用括号表示,并最终以字符串的形式返回。

并不是所有的左右节点都需要加括号,分情况:

  1. 左右子树的根节点都不为空时,二者都需要加括号。
  2. 左子树根节点为空,右子树根节点不为空时,二者都需要加括号。
  3. 左子树根节点不为空,右子树根节点为空时,不需要给右边加括号。
  4. 左右子树根节点都为空时,不需要给二者加括号。

解释一下第二点,当左为空右不为空时,如果给左括号省略了,就不能判断出左右节点的位置了。

比如:
在这里插入图片描述

解析

题目中的示例其实也提示了,我们可以先都加上括号,然后分情况省略掉不需要加括号的:
在这里插入图片描述

总结一下上面的四种情况,省略掉括号的应该是如下情况:

  1. 左右都为空,省略掉左右的括号
  2. 左不为空右为空,省略掉右括号

那么想要先都加上括号的话,就可写出如下代码:
在这里插入图片描述
不断递归就能得到都加上括号的字符串。

然后我们再来省略不需要加括号的情况,也就是需要留下括号的情况,再总结下上面的总结:

  1. 左不为空 或者 左为空且右不为空 时,左括号就要留下。
  2. 右不为空 时,右括号就要留下。

故可写出如下代码:
在这里插入图片描述

代码

class Solution {
public:
    string tree2str(TreeNode* root) {
        if(root == nullptr)
            return string();
        
        string res;
        res += to_string(root->val);

        if(root->left || (root->left == nullptr && root->right))
        {
            res += '(';
            res += tree2str(root->left);
            res += ')';
        }

        if(root->right)
        {
            res += '(';
            res += tree2str(root->right);
            res += ')';   
        }
        
        return res;
    }
};

2. 二叉树的层序遍历1(力扣102)

在这里插入图片描述

题目描述

本题需要我们将二叉树的层序遍历中每一层的遍历结果放到数组中。

解析

如果是单纯的层序遍历的话,我们可以用队列来实现。

但是这里有了限制条件,需要我们将每层的遍历结果放到数组中。

我们就可仍然用队列来实现层序遍历,并通过限制条件来按层的遍历,控制队列由原来的一个一个的出变为一层一层的出。

这里给出图解方便理解:
在这里插入图片描述

那么就可写下如下代码:
在这里插入图片描述

代码

class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        vector<vector<int>> vv;
        if(root == nullptr) // root为空,直接返回空数组
            return vv;

        queue<TreeNode*> q;
        // 先入根节点        
        q.push(root); 

        // q不为空说明内部还有下一层的节点,需要继续遍历下一层
        // q为空就是遍历完了
        while(!q.empty())
        {
            // tmp用来记录每一层的节点
            vector<int> tmp;
            // sz表示每一层的节点个数,也就是要遍历几个节点
            int sz = q.size();
            while(sz--)
            {
                TreeNode* front = q.front();
                q.pop();
                
                // 记录每个节点
                tmp.push_back(front->val);
                
                // 左不为空,入队
                if(front->left)
                    q.push(front->left);

                // 右不为空,入队
                if(front->right)
                    q.push(front->right);
            }

            // 将每一层记录
            vv.push_back(tmp);
        }

        return vv;
    }
};

其实这道题还可以用双队列,一个存放节点,一个存放每层的非空节点个数,然后通过控制第二个队列来控制第一个队列每次的出队个数,思想和刚刚的方法是一样的。这里就不写了,感兴趣的同学可以自己尝试写一写。

3. 二叉树的层序遍历2(力扣107)

本题和前面的那道题一样的,只不过是让存储的数组顺序变一下。

那我们直接在最后用个reverse就好了,不需要再搞复杂了,直接给代码:

代码

class Solution {
public:
    vector<vector<int>> levelOrderBottom(TreeNode* root) {
        vector<vector<int>> vv;
        if(root == nullptr) // root为空,直接返回空数组
            return vv;

        queue<TreeNode*> q;
        // 先入根节点        
        q.push(root); 

        // q不为空说明内部还有下一层的节点,需要继续遍历下一层
        // q为空就是遍历完了
        while(!q.empty())
        {
            // tmp用来记录每一层的节点
            vector<int> tmp;
            // sz表示每一层的节点个数,也就是要遍历几个节点
            int sz = q.size();
            while(sz--)
            {
                TreeNode* front = q.front();
                q.pop();
                
                // 记录每个节点
                tmp.push_back(front->val);
                
                // 左不为空,入队
                if(front->left)
                    q.push(front->left);

                // 右不为空,入队
                if(front->right)
                    q.push(front->right);
            }

            // 将每一层记录
            vv.push_back(tmp);
        }


        // 翻转一下就好
        reverse(vv.begin(), vv.end());
        return vv;
    }
};

4. 二叉树的最近公共祖先(力扣236)

在这里插入图片描述

这道题还是比较重要的,在剑指offer的最后的面试那块就提到了这道题。

题目描述

先说什么是祖先节点,就是从当前节点到根节点的所有节点都是其祖先节点。比如说:

在这里插入图片描述

这道题让我们求两个节点的最近公共祖先节点。就比如说上面的7和4,最近的公共祖先为2。

解析

题目中的二叉树就是一颗普通的二叉树,没有什么特殊的地方。

我们可以先来列举一些场景。

刚刚的7和4:
在这里插入图片描述

6和7
在这里插入图片描述

4和0
在这里插入图片描述

2和1
在这里插入图片描述

上面的都是一些普通场景,我们可以发现,最近的两个节点的最近祖先节点一定是在祖先节点的左右子树上。所以通过这一点就能做了。

但是还有特殊场景:

4和5
在这里插入图片描述

3和7
在这里插入图片描述

上面这种场景,当两个节点中的某一个是祖先节点的话,那么这个节点就是最近的祖先节点。

然后就没有什么特殊情况了,开始写代码,先用递归来写:

解法一

首先要写出查询节点的函数,用来查节点的左右子树:
在这里插入图片描述

然后再用findNode来实现找最近公共祖先。

在这里插入图片描述

解法二

用两个栈来存放路径。

先序遍历,一个栈存放从根到p的路径,一个栈存放从根到q的路径。

遍历到一个节点时,如果该节点为空,返回false,说明当前路径已经找到末尾。
如果不是空,先入栈。
然后再判断当前节点是否为要找的节点,如果是,直接返回true。
如果不是,递归判断其左,为真表明路径在左树中,并已经找到,返回true。
当左为空,递归判断其右,为真表明路径在右树中,并已经找到,返回true。
当左右都为空,就将其从栈中pop掉并返回false,表明当前路径已走完,需要换一条路径。

看图解:
在这里插入图片描述

在这里插入图片描述

此处即得到从根到p的路径,为3,5,6。

在这里插入图片描述

此处即得到从根到q的路径,即3,5,2,7。
在这里插入图片描述

所以p和q的路径都有了,找最近的公共祖先节点就更简单了,就类似于链表相交问题。
栈大的先pop两栈的大小差次,然后同时pop,直到二者栈顶元素相同。

写出如下代码。

先写一个用栈来记录路径的函数:
在这里插入图片描述

将p和q的路径找到,在栈中对比二者路径,直到找到最进祖先节点即可。
在这里插入图片描述

代码

find查找解法

class Solution {
public:
    bool findNode(TreeNode* root, TreeNode* p)
    {
        if(root == nullptr)
            return false;
        
        return root == p 
        || findNode(root->left, p)
        || findNode(root->right, p);
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        if(root == nullptr)
            return nullptr;
        
        // p || q 一个为root,root就是最近祖先节点
        if(root == p || root == q)
            return root;
        
        // p 在左树
        bool pL = findNode(root->left, p);
        bool pR = !pL;

        // q 在左树
        bool qL = findNode(root->left, q);
        bool qR = !qL;

        // 二者一左一右,当前节点为最近祖先节点
        if((pL && qR) || (qL && pR))
            return root;
        
        // 都在左,去左树找
        if(pL && qL)
            return lowestCommonAncestor(root->left, p, q);
        
        // 都在右,去右树找
        if(pR && qR)
            return lowestCommonAncestor(root->right, p, q);
        
        return nullptr;
    }
};

双栈解法

class Solution {
public:
    bool roadRecord(TreeNode* root, TreeNode* node, stack<TreeNode*>& st)
    {
        // 当前节点为空,说明当前路径已经找到结尾
        if(root == nullptr)
            return false;
        
        // 节点先入栈
        st.push(root);
        
        // 如果当前节点为要找的节点,就返回true,说明已经找到,即为当前节点
        if(root == node)
            return true;

        // 当前节点未找到,去左树中找节点
        // 左树中找到了,也即路径也找到了,返回true
        if(roadRecord(root->left, node, st))
            return true;        

        // 左树中未找到节点,去右树中找
        // 右树中找到了,也即路径也找到了,返回true
        if(roadRecord(root->right, node, st))
            return true;

        // 当前节点不是,左右树中都未找到,将栈顶元素pop掉,返回false
        // 表示换一条路径
        st.pop();
        return false;
    }

    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
        stack<TreeNode*> pRoad;
        stack<TreeNode*> qRoad;

        // 记录p和q的路径
        roadRecord(root, p, pRoad);
        roadRecord(root, q, qRoad);

        // 让两栈大小相同
        while(pRoad.size() > qRoad.size()) 
            pRoad.pop();
    
        while(qRoad.size() > pRoad.size())
            qRoad.pop();

        // 找到栈顶相同为止
        while(pRoad.top() != qRoad.top())
        {
            pRoad.pop();
            qRoad.pop();
        }

        // 返回任意一个栈的栈顶即可
        return pRoad.top();
    }
};

本题的一点拓展

如果说,我再往树中加点条件。

如果该树是一棵二叉搜索树

那么find那种解法就不需要再写find函数了。
直接根据二叉搜索树的特性,左<根<右,就可判断出节点是否在左树还是右树。

如果该树结构为三叉链

意思就是树节点中还有一个节点指向其父节点。

那么这道题做起来就更简单了,光用指向父节点的指针,直接可以做成链表相交的那道题。

5. 二叉搜索树与双向链表(牛客JZ36)

在这里插入图片描述

题目描述

本题让我们把一棵二叉搜索树转换为双向链表。注意是转换。

题目中有一个要求:我们不能创建新的节点。
那么想中序遍历二叉树然后一个一个new链表节点再push到后面的话,就不满足题目要求了。题目是想让我们使得原树节点左指向按照中序遍历顺序的当前节点前一个节点,右指向后一个节点。

解析

有什么好方法呢?

我们可以定义一个prev用来表示上一次遍历到的节点。
中序遍历,让当前节点的左指向prev,让prev的右指向当前节点,这样就解决了。但是要注意一下边界条件。

看看图解:
在这里插入图片描述

我们可以先写一个改变指针指向的函数(这段代码有问题,等会说):
在这里插入图片描述

将二叉树转变为链表后再找到最左边的节点返回即可:
在这里插入图片描述

但是上面的代码出现了经典的问题,就是prev一直是传值,我所画的图中,prev只有一个。

但是上面的传值,会导致每一层调用的时候都是那一层初始情况下的值,不会影响其他递归调用的prev,所以就会导致有多个prev。

所以运行起来后就出错了。

我们可以在指针的后面加个引用,这样就能使得整个过程中只有一个prev了。
在这里插入图片描述

注意这里的prev相当于一个TreeNode*的别名。

代码

class Solution {
public:
	void changePtr(TreeNode* root, TreeNode* prev)
	{
		if(root == nullptr)
			return;
		
		changePtr(root->left, prev);
		
		root->left = prev;
		if(prev)
			prev->right = root;

		prev = root;

		changePtr(root->right, prev);
	}

    TreeNode* Convert(TreeNode* pRootOfTree) 
	{
		if(pRootOfTree == nullptr)
			return nullptr;

        TreeNode* prev = nullptr;
		changePtr(pRootOfTree, prev);
		
		TreeNode* cur = pRootOfTree;
		while(cur->left)
			cur = cur->left;

		return cur;
    }
};

6. 从前序与中序遍历序列构造二叉树(力扣105)

在这里插入图片描述

题目描述

本题中给了你二叉树的前序遍历和中序遍历的顺序,并存放在了数组中,让你通过这两个数组还原出对应的二叉树。

解析

这道题解法很像一道题,那道题大概就是给你一段字符串让你用这个字符串构建一棵二叉树
,我这里就不找那道题了。

主要用前序遍历来构建树。

题目中所给的前序遍历,是用来定根的。遍历前序数组,遍历一个为一个根节点。

定完了树的根之后,从中序遍历的数组中找到根的值,并记录下标i,然后将数组中i的左边分为左树节点区间,将数组中i的右边分为右树节点区间。

创建根节点,然后再递归到左右区间中创建树即可。

这里就不画图了,就跟各位平时学校书里面让你们写这种题的做法一样,相信各位也是会画图的。

用一个子函数来创建树,方便记录二者的下标:
在这里插入图片描述
上面preorder的下标prei要用引用,和上面的那道题一样,preorder是挨个走的,每次都是只有一个,如果有想不通的同学,可以自己搞个例子画画图,就明白了。

代码

class Solution {
public:
    TreeNode* creatTree(vector<int>& preorder, vector<int>& inorder, int& prei, int left, int right)
    {
        if(left > right)
            return nullptr;
        TreeNode* root = new TreeNode(preorder[prei++]);
        int ini = 0;
        for(ini = left; ini <= right; ++ini)
            if(inorder[ini] == root->val) break;
        root->left = creatTree(preorder, inorder, prei, left, ini - 1);
        root->right = creatTree(preorder, inorder, prei, ini + 1, right);
        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int i = 0;
        return creatTree(preorder, inorder, i, 0, inorder.size() - 1);
    }
};

7. 从中序与后序遍历序列构造二叉树(力扣106)

在这里插入图片描述

题目描述

这道题和上面的那道不一样的就是把前序换成了中序。

解析

一样,通过后续来确定根节点。倒着走就行。

不过注意要先构建右子树再构建左子树。

在这里插入图片描述

代码

class Solution {
public:
    TreeNode* _buildTree(vector<int>& inorder, vector<int>& postorder, int& posti, int inleft, int inright)
    {
        if(inleft > inright)
            return nullptr;

        TreeNode* root = new TreeNode(postorder[posti--]);
        int ini = 0;
        for(ini = inleft; ini <= inright; ++ini)
            if(inorder[ini] == root->val) break;
        root->right = _buildTree(inorder, postorder, posti, ini + 1, inright);
        root->left = _buildTree(inorder, postorder, posti, inleft, ini - 1);

        return root;
    }
    
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder)
    {
        int i = postorder.size() - 1;
        return _buildTree(inorder, postorder, i, 0, inorder.size() - 1);
    }
};

8. 非递归实现二叉树的前序遍历(力扣144)

在这里插入图片描述

题目描述

很简单,就是前序遍历,但是不用递归的方法,题目最后也说了迭代,我们这里就用非递归来实现前序遍历。

不要觉得没什么用,有的厂面试的时候会考。

解析

怎么做呢,用栈。

前序遍历顺序为:根左右。

先访问再左右,如果我们画出图的话,可以找一个规律。

就是一个节点访问完后,访问其所有的左路节点,什么叫左路节点呢?
看图:
在这里插入图片描述
然后6没有右子节点,但是5有。

在这里插入图片描述
同理:
在这里插入图片描述

我们可总结如下:

遍历到一个节点时

  1. 先访问该节点
  2. 访问其左路节点
  3. 访问左路节点的右子树

右子树重复上述过程。

用栈的图解:

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

代码实现:
在这里插入图片描述

代码

class Solution {
public:
    vector<int> preorderTraversal(TreeNode* root) {
        vector<int> v;
        TreeNode* cur = root;
        stack<TreeNode*> st;
        // cur不为空,包括初始情况下的root,还有左路节点中的右子树
        while(cur || !st.empty())
        {
            // 访问左路节点
            while(cur)
            {
                st.push(cur);
                v.push_back(cur->val);

                cur = cur->left;
            }

            // 得到栈顶节点,即左路节点
            TreeNode* top = st.top();
            st.pop();

            // 去左路节点的右子树中找
            cur = top->right;
        }    
        return v;
    }
};

9. 非递归实现二叉树的中序遍历(力扣94)

在这里插入图片描述

题目描述

这道题和前一道代码一样,就是有的地方顺序调换了一下,各位还没解析的试着用上面那道题的思路来写写这道题。

解析

上面的那倒是前序遍历,后面的这道题是中序遍历,左根右。

思路一样,也是栈,不过是访问的时机变了一下。变成了从栈中弹出的时候再访问,因为当左路节点从栈中弹出的时候说明这个节点的左路节点已经访问过了,接下来就是访问根了。

就不画图了,好麻烦,直接给代码了:
在这里插入图片描述

代码

class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur = root;

        while(cur || !st.empty())
        {
            while(cur)
            {
                st.push(cur);
                cur = cur->left;
            }

            TreeNode* top = st.top();
            st.pop();
            
            // 访问时机发生改变,其余都不变
            v.push_back(top->val);

            cur = top->right;
        }
        return v;
    }
};

10. 非递归实现二叉树的后序遍历(力扣145)

在这里插入图片描述

题目描述

这里是非递归后序遍历。
跟上面两道稍微有点出入,有的地方绕一点。

解析

还是栈,但是细节要比前两道多一点点。

首先,后序遍历,左右根。

还是访问的时机要变一下,最后的时候再访问。
前序的可以直接访问,中序的栈弹出的时候再访问,后序怎么办?

左右都访问过了再访问,更准确点是右访问过了再访问。那么怎么记录这一点呢?

当左路节点从栈中弹出的时候说明这个节点的左路节点已经访问过了,接下来就是访问右了。

我们可以搞一个prev用来表示前一个访问到的节点,左右根,当要访问根的时候,前一个访问过的节点就是右。

我们可以访问根时分两种情况,一种是根的右为空,一种是根的右是prev。当访问到了当前节点后就将prev更新为当前访问到的节点。

来个图解:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
然后给代码:
在这里插入图片描述

代码

class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode*> st;
        vector<int> v;
        TreeNode* cur = root;

        // prev节点,用来记录前一次访问的节点
        TreeNode* prev = nullptr;

        while(cur || !st.empty())
        {
            // 左路节点入栈
            while(cur)
            {
                st.push(cur);
                cur = cur->left;
            }

            TreeNode* top = st.top();

            // 当前节点右树为空和右树等于prev可以访问
            if(prev == top->right || top->right == nullptr)
            {
                v.push_back(top->val);
                prev = top;
                cur = nullptr;
                st.pop();
            }
            else // 否则就访问当前节点的右树
            {
                cur = top->right;
            }
        }

        return v;
    }
};

这十道题对于没有做过的同学来说,还是有点强度的,做过的同学可能也有点。

反正都是经典好题,各位好好琢磨琢磨。

到此结束。。。

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

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

相关文章

接口测试之json中的key获取

在很多情况下我们在进行接口测试的时候都会有获取上个接口返回的json数据中的某个key值&#xff0c;然后下个接口调用这个key值。今天给大家讲解一下针对不同类型的json获取某个key的值。 一、首先是单纯object格式key值获取 获取图中的token的值&#xff0c;首先这是一个响应…

SSM(Vue3+ElementPlus+Axios+SSM前后端分离)【四】

文章目录 SSM(Vue3ElementPlusAxiosSSM前后端分离)--基础环境搭建【四】项目介绍项目功能/界面● SSM 整合项目界面 创建表&#xff0c;使用逆向工程生成Bean、XxxMapper 和XxxMapper.xml1. 创建furns_ssm 数据库和furns 表使用MyBatis Generator 逆向工程生成bean mapper 接口…

基于Jonswap谱的随机波高及波压力生成

内容目录 基于Jonswap谱的随机波高及波压力生成基于Jonswap谱的随机波高及波压力生成 海面高程可视为是平稳高斯随机过程,可通过对波浪谱确定的一系列分量波进行叠加得到。JONSWAP谱是在海洋结构设计和分析中常用的波浪频谱,可以用其来模拟随机波浪。 式中:有义波高H1/3和…

GPIO简介

一、GPIO GPIO&#xff08;General-purpose input/output&#xff09;即通用型输入输出&#xff0c;GPIO可以控制连接在其之上的引脚实现信号的输入和输出 芯片的引脚与外部设备相连&#xff0c;从而实现与外部硬件设备的通讯、控制及信号采集等功能 LED实验步骤 实验步骤 以L…

1. CUDA中的grid和block

1. CUDA中的grid和block基本的理解 Kernel: Kernel不是CPU&#xff0c;而是在GPU上运行的特殊函数。你可以把Kernel想象成GPU上并行执行的任务。当你从主机&#xff08;CPU&#xff09;调用Kernel时&#xff0c;它在GPU上启动&#xff0c;并在许多线程上并行运行。 Grid: 当你…

C高级【day2】

思维导图&#xff1a; 递归实现&#xff0c;输入一个数&#xff0c;输出这个数的每一位&#xff1a; #include<myhead.h>//递归函数 void fun(int num){//num没值不再递归if(0 num){return;}//输出数的最后一位printf("%d\t", num%10);//递归fun(num/10);}…

AI Chat 设计模式:11. 状态模式

本文是该系列的第十一篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 你知道状态模式吗A.1Q.2 它与有限状态机有什么联系吗&#xff1f;A.2Q.3 知道了&…

Spring:IOC技术、Bean、DI

前言 Spring是一个开源的项目&#xff0c;并不是单单的一个技术&#xff0c;发展至今已形成一种开发生态圈。也就是说我们可以完全使用Spring技术完成整个项目的构建、设计与开发。Spring是一个基于IOC和AOP的架构多层j2ee系统的架构。 SpringFramework&#xff1a;Spring框架…

ROS2学习(四)进程,线程与节点的关系

节点与节点执行器 节点&#xff0c;英文是node,在ROS2中&#xff0c;节点是一个抽象的实体&#xff0c;它可以代表某种或某类特定功能的抽象集合体&#xff0c;它可以存在于进程中&#xff0c;也可以存在于线程中。所有ROS2的基础功能最基础的载体是节点&#xff0c;所有的通信…

mysql的InnoDB和myISAM引擎对比:插入数据

mysql主流引擎是InnoDB和myISAM。两者简单来说&#xff0c;InnoDB是行锁&#xff0c;支持事务&#xff1b;myISAM是表锁&#xff0c;不支持事务。具体理论上的区别&#xff0c;网上有很多说法&#xff0c;我这里不多说了。 这里做了一个试验&#xff0c;插入100w条数据&#x…

redis+token+分布式锁确保接口的幂等性

目录 1.幂等性是什么&#xff1f; 2.如何实现幂等性呢&#xff1f; 1.新增管理员&#xff0c;出弹窗的同时&#xff0c;请求后台。 2.后端根据雪花算法生成唯一标识key&#xff0c;以雪花数为key存到redis。并返回key给前端。 3.前端保存后端传过来的key。 4.前端输入完成…

使用事件侦听器和 MATLAB GUI 查看 Simulink 信号研究

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

异或运算详解

异或运算详解 定义特性用途总结 定义 参与运算的两个数据,按二进制位进行 ^ 运算,如果两个相对应为值相同结果为0,否则为1 1 ^ 0 1 0 ^ 1 1 0 ^ 0 0 1 ^ 1 0特性 异或^运算只能用于数值(整数) x ^ 0 x x ^ x 0用途 两个值交换,而不用使用临时变量 a a ^ b; b b ^…

2023年08月数据库流行度最新排名

点击查看最新数据库流行度最新排名&#xff08;每月更新&#xff09; 2023年08月数据库流行度最新排名 TOP DB顶级数据库索引是通过分析在谷歌上搜索数据库名称的频率来创建的 一个数据库被搜索的次数越多&#xff0c;这个数据库就被认为越受欢迎。这是一个领先指标。原始数…

vue videojs视频播放插件 动态资源

概览&#xff1a;使用vediojs第三方视频播放插件&#xff0c;视频加载有两种方式&#xff0c;第一种是html方式&#xff0c;类似于img标签的src&#xff0c;写在video标签内的<source src>&#xff1b;第二种方式是js方式&#xff0c;实例化一个videojs对象并且赋值src。…

anaconda创建虚拟环境在D盘

【看一看就行&#xff0c;又是挺水的一期&#xff08;每一季都掺和一点子水分也挺好&#xff09;】 一、创建&#xff1a; conda create --prefixD:\python37\py37 python3.7 这下就在D盘了&#xff1a; 二、激活刚刚那个环境&#xff1a; activate D:\pyhton37\py37​ &…

Zebec APP:构建全面、广泛的流支付应用体系

目前&#xff0c;流支付协议 Zebec Protocol 基本明确了生态的整体轮廓&#xff0c;它包括由其社区推动的模块化 Layer3 构架的公链 Nautilus Chain、流支付应用 Zebec APP 以及 流支付薪酬工具 Zebec payroll 。其中&#xff0c;Zebec APP 是原有 Zebec Protocol 的主要部分&a…

高校陆续拥抱chatgpt,人工智能会给学术带来什么变化会有什么影响

在当今信息爆炸的时代&#xff0c;人工智能在各行各业都发挥着越来越重要的作用&#xff0c;高校教育领域也不例外。最近&#xff0c;越来越多的高校开始陆续拥抱chatgpt&#xff08;Chatbot GPT&#xff09;这一人工智能技术&#xff0c;在学术领域会带来了怎样的变化与影响&a…

小研究 - 领域驱动设计DDD在IT企业内部网站开发中的运用(二)

在企业内部网站的建设过程中&#xff0c;网站后端最初采用传统的表模式的开发方式。这种方式极易导致站点的核心业务逻辑和业务规则分布在架构的各个层和对象中&#xff0c;这使得系统业务逻辑的复用性不高。为了解决这个问题&#xff0c;作者在后期的开发过程中引入了领域驱动…

电缆故障检测仪技术参数

一、电缆故障测试仪的技术参数 1.采样方法&#xff1a;低压脉冲法、冲击闪络法、速度测量法 2.电缆长度&#xff1a;50m、300m、1km、2km、5km、10km、30km、60km 3.波速设置&#xff1a;交联乙烯、聚氯乙烯、油浸纸、不滴油和未知类型自设定 4.冲击高压&#xff1a;35kV及以下…