【基础算法】二叉树相关题目

news2024/12/26 11:24:31

系列综述:
💞目的:本系列是个人整理为了秋招算法的,整理期间苛求每个知识点,平衡理解简易度与深入程度。
🥰来源:材料主要源于代码随想录进行的,每个算法代码参考leetcode高赞回答和其他平台热门博客,其中也可能含有一些的个人思考。
🤭结语:如果有帮到你的地方,就点个赞关注一下呗,谢谢🎈🎄🌷!!!
🌈数据结构基础知识总结篇


文章目录

    • 一、二叉树理论基础
      • 定义
      • 二叉树深度优先遍历
      • 二叉树广度优先遍历
      • 二叉树最大深度
      • 二叉树最小深度
      • 完全二叉树
      • 判断是否为平衡二叉树
    • 二、相关题目
      • 翻转二叉树
      • 二叉树是否对称
      • 判断是否为平衡二叉树
      • 二叉树的所有路径
      • 左叶子之和
      • 求二叉树最左下的叶子
      • 符合总和的路径
      • 106. 从中序与后序遍历序列构造二叉树
      • 654. 最大二叉树
      • 654. 最大二叉树
    • 参考博客


😊点此到文末惊喜↩︎


一、二叉树理论基础

定义

  1. 二叉树数据结构
    struct TreeNode {
        int val;
        TreeNode *left;
        TreeNode *right;
        TreeNode(int x) : val(x), left(NULL), right(NULL) {}
    };
    

二叉树深度优先遍历

  1. 递归式
    // 前序遍历
    void traversal(TreeNode* cur, vector<int>& vec) {
            if (cur == NULL) return;
            vec.push_back(cur->val);    // 中
            traversal(cur->left, vec);  // 左
            traversal(cur->right, vec); // 右
        }
    // 中序遍历
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal(cur->left, vec);  // 左
        vec.push_back(cur->val);    // 中
        traversal(cur->right, vec); // 右
    }
    // 后序遍历
    void traversal(TreeNode* cur, vector<int>& vec) {
        if (cur == NULL) return;
        traversal(cur->left, vec);  // 左
        vec.push_back(cur->val);    // 中
        traversal(cur->right, vec); // 右
    }
    // 调用示例
    vector<int> Traversal(TreeNode* root) {
        vector<int> result;
        traversal(root, result);
        return result;
    }
    
  2. 非递归:将前序、中序和后序统一化处理,将遍历核心顺序进行逆序转化
    • 算法遍历部分的逆序
    • 对于值节点的处理
    vector<int> postorderTraversal(TreeNode* root) {
        // 初始化
        vector<int> result;
        stack<TreeNode*> st;
        if (root != NULL) // 压入根节点
        	st.push(root);
        // 遍历源容器
        while (!st.empty()) {
            TreeNode* node = st.top();
            if (node != NULL) {
                st.pop();
            // 算法变化的部分,遍历的逆序
                // 中
                st.push(node);                          
                st.push(NULL);
    			// 右
                if (node->right) st.push(node->right); 
                // 左
                if (node->left) st.push(node->left);    
            } else {
            	// 对值节点的处理
                st.pop();// 弹出空结点
                node = st.top();
                st.pop();
                result.push_back(node->val);
            }
        }
        return result;
    }
    

二叉树广度优先遍历

  1. 递归法
    // 递归参数,如果需要修改要进行引用传递
    void traversal(TreeNode* cur, vector<vector<int>>& result, int depth) {
    	// 递归出口
        if (cur == nullptr) return;
        // 递归体
        if (result.size() == depth) // 扩容
        	result.push_back(vector<int>());// 原地构建数组
        result[depth].push_back(cur->val);// 顺序压入对应深度的数组中
        order(cur->left, result, depth + 1);
        order(cur->right, result, depth + 1);
    }
    vector<vector<int>> levelOrder(TreeNode* root) {
    	// 初始化:一般为递归形参
        vector<vector<int>> result;
        int depth = 0;
        // 递归调用
        traversal(root, result, depth);
        // 返回结果
        return result;
    }
    
  2. 非递归法
    vector<vector<int>> levelOrder(TreeNode* root) {
        // 初始化
        queue<TreeNode*> que;
        vector<vector<int>> result;
        if(root != nullptr) que.push(root);// 将声明队列并将根节点压入栈中
       // 迭代
        while (!que.empty()) {
            int size = que.size();// 记录每层要遍历的根节点数量
            TreeNode* node;// 
            vector<int> vec;// 层次遍历要筛选的元素
            // 不要使用que.size(),因为que.size在循环体内不断变化
            for (int i = 0; i < size; i++) {
                // 队首结点放到结构队列中
                node = que.front();
                vec.push_back(node->val);
                // 弹出队首节点,并将它的孩子结点按序压入栈中
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
            // 将每层筛选元素压入结果数组中
            result.push_back(vec);
        }
        // 输出
        return result;
    }
    

二叉树最大深度

  1. 递归法
    // 递归只考虑当前层,不要过于考虑整体
    int depth(TreeNode* root) {
        // 1. 如果当前 root 为 null,说明当前层的深度就是 0        
        if (!root) {
            return 0;
        }
        // 2. 分别计算左子树和右子树的深度
        int L = depth(root->left);
        int R = depth(root->right);
        // 3. 获取当前树的左子树和右子树深度的较大值,加 1 (本层深度)
        return max(L,R) + 1;
    }
    // 简略版
    int depth(TreeNode* cur) { //计算最大深度
        return (cur == nullptr) ? 0 : max(depth(cur->left), depth(cur->right)) + 1;
    }
    
  2. 非递归法
    int maxDepth(TreeNode* root) {
        queue<TreeNode*> q;
        if(root) q.push(root);
        int depth = 0;
    
        while(!q.empty()){
            int size = q.size();
    
            ++depth;
            for(int i = 0; i < size; ++i){
                TreeNode *cur = q.front();
                q.pop();
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
            }
        }
        return depth;
    }
    

二叉树最小深度

  1. 递归法
    • 二叉树的五种形态
      • 空二叉树
      • 只有根节点
      • 只有左子树
      • 只有右子树
      • 左右子树都有
    int minDepth(TreeNode* root) {
    	// 空二叉树
        if (root == NULL) return 0;
        // 只有左子树
        if (root->left != NULL && root->right == NULL) {
            return 1 + minDepth(root->left);
        }
        // 只有右子树
        if (root->left == NULL && root->right != NULL) {
            return 1 + minDepth(root->right);
        }
        // 左右子树都非空
        return 1 + min(minDepth(root->left), minDepth(root->right));
    }
    
    
    
  2. 非递归法
    • 找到第一个左右孩子均为空的,即为最小深度
    int minDepth(TreeNode* root) {
        if (root == NULL) return 0;
        int depth = 0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int size = que.size();
            depth++; // 记录最小深度
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
                if (!node->left && !node->right) { // 第一个左右孩子均空,为最小深度
                    return depth;
                }
            }
        }
        return depth;
    }
    

完全二叉树

  1. 递归法
    • 递归法要只考虑单层的逻辑
    int getNodesNum(TreeNode* cur) {
        if (cur == NULL) return 0;
        int leftNum = getNodesNum(cur->left);      // 左
        int rightNum = getNodesNum(cur->right);    // 右
        int treeNum = leftNum + rightNum + 1;      // 中
        return treeNum;
    }
    
  2. 非递归法
    • 找到第一个左右孩子均为空的,即为最小深度
    int countNodes(TreeNode* root) {
        queue<TreeNode*> que;
        if (root != NULL) que.push(root);
        int result = 0;
        while (!que.empty()) {
            int size = que.size();
            for (int i = 0; i < size; i++) {
                TreeNode* node = que.front();
                que.pop();
                result++;   // 记录节点数量
                if (node->left) que.push(node->left);
                if (node->right) que.push(node->right);
            }
        }
        return result;
    }
    

判断是否为平衡二叉树

  1. 递归法
    • 递归法要只考虑单层的逻辑
    int getNodesNum(TreeNode* cur) {
        if (cur == NULL) return 0;
        int leftNum = getNodesNum(cur->left);      // 左
        int rightNum = getNodesNum(cur->right);    // 右
        int treeNum = leftNum + rightNum + 1;      // 中
        return treeNum;
    }
    
  2. 非递归法
    • -1是剪枝的标志位,即如果不是平衡二叉树,
    int getHeight(TreeNode* node) {
            if (node == NULL) {
                return 0;
            }
            int leftHeight = getHeight(node->left);
            if (leftHeight == -1) return -1;
            int rightHeight = getHeight(node->right);
            if (rightHeight == -1) return -1;
            return abs(leftHeight - rightHeight) > 1 ? -1 : 1 + max(leftHeight, rightHeight);
        }
        bool isBalanced(TreeNode* root) {
            return getHeight(root) == -1 ? false : true;
        }
    

二、相关题目

翻转二叉树

  1. 翻转二叉树
    • 对于二叉树的操作都是从二叉树的遍历衍生出来的
      在这里插入图片描述
    // 前序遍历
    void traversal(TreeNode *cur){
        if(cur == nullptr)
            return ;
        swap(cur->left, cur->right);
        if(cur->left)  traversal(cur->left);
        if(cur->right)  traversal(cur->right);
    }
    // 调用函数
    TreeNode* invertTree(TreeNode* root) {
        if(root == nullptr) 
            return nullptr;
        traversal(root);
        return root;
    }
    

二叉树是否对称

  1. 101. 对称二叉树

    • 对称二叉树要比较的不是左右节点,而是根节点的左子树和右子树是否能反转
      在这里插入图片描述
    bool compare(TreeNode* left, TreeNode* right) {
        if (left == NULL && right != NULL) return false;
        else if (left != NULL && right == NULL) return false;
        else if (left == NULL && right == NULL) return true;
        else if (left->val != right->val) return false;
        else return compare(left->left, right->right) 
        && compare(left->right, right->left);
    }
    bool isSymmetric(TreeNode* root) {
        if (root == NULL) return true;
        return compare(root->left, root->right);
    }
    
    
  2. 有点东西的写法

    ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
        ListNode *A = headA, *B = headB;
        // 核心在于交换头节点
        while (A != B) {
            A = A != nullptr ? A->next : headB;
            B = B != nullptr ? B->next : headA;
        }
        return A;
    }
    

判断是否为平衡二叉树

  1. 递归
    • 由于尾递归优化,效率很高
    // 计算最大深度
    int depth(TreeNode* cur) { //计算最大深度
        return (cur == nullptr) ? 0 : max(depth(cur->left), depth(cur->right)) + 1;
    }
    bool isBalanced(TreeNode* root) {
        return (root == nullptr) ? true : 
        abs(depth(root->left) - depth(root->right)) <= 1 &&
        isBalanced(root->left) && isBalanced(root->right);
    }
    
  2. 迭代法复杂且优化困难

二叉树的所有路径

  1. 递归
    • 数字转化成字符串to_string(number)
    • 字符串后追加子串str.append(subStr)
    • 字符串删除某个位置之后的字符str.erase(position)
    // 数字型
    void dfs(TreeNode*root,vector<int>path, vector<vector<int>> &res)
    {
        if(!root) return;  //根节点为空直接返回
        // 中
        path.push_back(root->val);  //作出选择
        if(!root->left && !root->right) //如果到叶节点  
        {
            res.push_back(path);
            return;
        }
        // 左
        dfs(root->left,path,res);  //继续递归
        // 右
        dfs(root->right,path,res);
    }
    // 字符型
    void binaryTree(TreeNode* root,string path,vector<string>&res)
    {
        if(root==NULL) return ;
        path.append(to_string(root->val));
        path.append("->");
        if(root->left==NULL&&root->right==NULL{
        	path.erase(path.length()-2);
        	res.push_back(path);
        }
        binaryTree(root->left,path,res);
        binaryTree(root->right,path,res);
    }
    vector<string> binaryTreePaths(TreeNode* root) {
        string path;
        vector<string>res;
        binaryTree(root,path,res);
        return res;
    }
    

左叶子之和

  1. 求二叉树的左叶子之和
    • 遍历所有节点,对所求的特殊节点进行约束求值
    void postorder(TreeNode *root, int &result){
        if(root == nullptr) return ;
    
        if(root->left) postorder(root->left, result);
        if(root->right) postorder(root->right, result);
    	// 中
        if(root->left != nullptr 
        	&& root->left->left == nullptr 
        	&&root->left->right == nullptr
        	)
            result += root->left->val;
    }
    
  2. 有点东西的写法
    int sumOfLeftLeaves(TreeNode* root) {
    	// 初始化
        stack<TreeNode*> st;
        if(root != nullptr) st.push(root);
        int res = 0;
    	// 迭代
        while(!st.empty()){
            TreeNode* cur = st.top();
            if(cur != nullptr){
                st.pop();
                
                st.push(cur);
                st.push(nullptr);
    
                if(cur->right) st.push(cur->right);
                if(cur->left) st.push(cur->left);
    
            }else{
                st.pop();
                cur = st.top();
                st.pop();
    
                if(cur->left != nullptr 
                	&& cur->left->left == nullptr 
                	&& cur->left->right == nullptr
                	)
                    res += cur->left->val;
            } 
        }
        // 结果处理
        return res;
    }
    

求二叉树最左下的叶子

  1. 513. 找树左下角的值
    • 层次遍历最后一层的第一个,就是最左下的叶子
    int findBottomLeftValue(TreeNode* root) {
        queue<TreeNode *> q;
        if(root != nullptr)
            q.push(root);
        int res = 0;
    
        while(!q.empty()){
            int size = q.size();
    
            for(int i= 0; i < size; ++i){
                TreeNode * cur = q.front();
                q.pop();
                // 每层的第一个,即最左的节点
                if(i == 0) res = cur->val;
                if(cur->left) q.push(cur->left);
                if(cur->right) q.push(cur->right);
            }
        }
        return res;
    }
    

符合总和的路径

  1. 112. 路径总和
    • 层次遍历最后一层的第一个,就是最左下的叶子
    bool hasPathSum(TreeNode* root, int targetSum) {
        // 初始化
        stack<TreeNode*> st;
        if(root != nullptr) st.push(root);
        int sum = 0;
        // 迭代
        while(!st.empty()){
            TreeNode *cur = st.top();
            if(cur != nullptr){
                st.pop();
    
                st.push(cur);
                st.push(nullptr);
                sum += cur->val;
    
                if(cur->right) st.push(cur->right);
                if(cur->left) st.push(cur->left);
            }else{
                st.pop();
                cur = st.top();
                st.pop();
                // 节点判断
                if(sum == targetSum&& cur->left == nullptr && cur->right == nullptr){
                    return true;
                }else{// 回溯
                    sum -= cur->val;
                }
            }
        }
        return false;
    }
    

106. 从中序与后序遍历序列构造二叉树

  1. 106. 从中序与后序遍历序列构造二叉树
    • 通过始末位置指示容器范围,避免每次调用的vector创建开销
    // 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
    TreeNode* traversal (
    	vector<int>& inorder, int inorderBegin, int inorderEnd, 
    	vector<int>& postorder, int postorderBegin, int postorderEnd
    	){
    	// 每次都是先从后序找,所以后序没有即完成
        if (postorderBegin == postorderEnd) return NULL;
    	// 分界点为后序最后一个
        int rootValue = postorder[postorderEnd - 1];
        TreeNode* root = new TreeNode(rootValue);
    
        if (postorderEnd - postorderBegin == 1) return root;
    	// 查找前序序列中的分界下标
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        // 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;
    
        // 切割后序数组
        // 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
        int leftPostorderBegin =  postorderBegin;
        int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
        // 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
        int rightPostorderBegin = postorderBegin + (delimiterIndex - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 排除最后一个元素,已经作为节点了
    	// 
        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  postorder, leftPostorderBegin, leftPostorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
    
        return root;
    }
    
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        // 左闭右开的原则
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
    

654. 最大二叉树

  1. 654. 最大二叉树
    • 通过始末位置指示容器范围,避免每次调用的vector创建开销
    // 在左闭右开区间[left, right),构造二叉树
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        // 构建完成
        if (left >= right) return nullptr;
        // 分割点下标:maxValueIndex
        int maxValueIndex = left;
        for (int i = left + 1; i < right; ++i) {
            if (nums[i] > nums[maxValueIndex]) maxValueIndex = i;
        }
        // 创建节点
        TreeNode* root = new TreeNode(nums[maxValueIndex]);
        // 左闭右开:[left, maxValueIndex)
        root->left = traversal(nums, left, maxValueIndex);
        // 左闭右开:[maxValueIndex + 1, right)
        root->right = traversal(nums, maxValueIndex + 1, right);
        return root;
    }
    

654. 最大二叉树

  1. 617. 合并二叉树
    • 如果两颗树有个相同位置的节点一个为空,另一个不是。则应该直接链接过去,因为这样可以保证后面的也过去
    // 递归
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2;// 其中一个为空则返回另一个
        if (t2 == NULL) return t1;
        // 重新定义新的节点,不修改原有两个树的结构
        TreeNode* root = new TreeNode(0);
        root->val = t1->val + t2->val;
        root->left = mergeTrees(t1->left, t2->left);// 直接链接
        root->right = mergeTrees(t1->right, t2->right);
        return root;
    }
    // 迭代
    TreeNode* mergeTrees(TreeNode* t1, TreeNode* t2) {
        if (t1 == NULL) return t2;
        if (t2 == NULL) return t1;
        queue<TreeNode*> que;
        que.push(t1);
        que.push(t2);
        while(!que.empty()) {
            TreeNode* node1 = que.front(); que.pop();
            TreeNode* node2 = que.front(); que.pop();
            // 此时两个节点一定不为空,val相加
            node1->val += node2->val;
    
            // 如果两棵树左节点都不为空,加入队列
            if (node1->left != NULL && node2->left != NULL) {
                que.push(node1->left);
                que.push(node2->left);
            }
            // 如果两棵树右节点都不为空,加入队列
            if (node1->right != NULL && node2->right != NULL) {
                que.push(node1->right);
                que.push(node2->right);
            }
    
            // 当t1的左节点 为空 t2左节点不为空,就赋值过去
            if (node1->left == NULL && node2->left != NULL) {
                node1->left = node2->left;
            }
            // 当t1的右节点 为空 t2右节点不为空,就赋值过去
            if (node1->right == NULL && node2->right != NULL) {
                node1->right = node2->right;
            }
        }
        return t1;
    }
    


少年,我观你骨骼清奇,颖悟绝伦,必成人中龙凤。
不如点赞·收藏·关注一波


🚩点此跳转到首行↩︎

参考博客

  1. 代码随想录
  2. letcode

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

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

相关文章

[ICLR 2023] Token Merging: Your ViT But Faster

Contents IntroductionToken MergingExperimentsImage ExperimentsDesign choicesModel SweepComparison to Other WorksVisualizations Video ExperimentsAudio Experiments References Introduction 作者提出了一种 token 合并方法 Token Merging (ToMe)&#xff0c;能够在不…

【Tasking_IDE】-1-如何让目录下的C文件不参与编译

案例背景&#xff1a; 当您在使用Tasking TriCore Eclipse IDE集成开发环境编译时&#xff0c;是不是有时遇到这样一个问题&#xff1a;导入了一个算法/驱动文件夹&#xff0c;但文件夹里面不是所有的C文件都要参与编译&#xff0c;于是您可能想到把这些“不参与编译的文件”删…

Kafka3.0.0版本——生产者 数据去重

目录 一、数据传递语义1.1、至少一次1.2、最多一次1.3、精确一次 二、幂等性2.1、幂等性原理2.2、重复数据的判断标准2.3、如何使用幂等性 三、生产者 事务3.1、Kafka事务原理3.2、Kafka事务注意事项3.3、Kafka事务的5个API3.3.1、初始化事务API3.3.2、开启事务API3.3.3、在事务…

CMake Tutorial Step1

CMake Tutorial Step1 参考资料&#xff1a;Step 1: A Basic Starting Point — CMake 3.26.3 Documentation Tutorial工程&#xff1a;官方Tutorial工程 开发环境&#xff1a;CLion CMake简介 方便起见直接问New Bing。 为什么要学习CMake&#xff1f; CMake的最大特点和…

微服务---分布式搜索引擎 elasticsearch基础

分布式搜索引擎 elasticsearch基础 0.学习目标 1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 例如&#xff1a; 在GitH…

centos7操作yum命令失败

前言设置网卡开机自动启动设置国内dns服务器系统修改CentOS-Base.repo中的地址 前言 刚安装完的CentOS7的系统&#xff0c;发现无法使用yum命令进行更新&#xff0c;在更新的时候会出现下面这种内容&#xff0c;为此问题有以下这些解决方案可以尝试。 One of the configured r…

两段视频合成一个视频用什么软件 怎么把两段视频合成一段看不出来

两段视频合成一个视频用什么软件&#xff1f;无论是两段视频的合成&#xff0c;还是三段视频的合成&#xff0c;用视频编辑软件都能轻松搞定。但怎么把两段视频合成一段看不出来&#xff1f;这就比较考验制作者的功力了&#xff0c;不过我们还是有捷径的&#xff0c;下面一起来…

new和delete

目录 malloc: 开辟失败&#xff1a;返回值为空指针 new: 内置类型&#xff1a; 申请一个int对象&#xff08;开辟一块存储int类型数据的空间&#xff0c;只能存储一个int数据&#xff09;&#xff1a; 申请5个int对象&#xff08;开辟一块存储int类型数据的空间&#xff…

Blender3.5 边的操作

目录 1. 边操作1.1 边的细分 Subdivide1.2 边的滑移 Edge Slide1.3 边的删除1.4 边的溶解 Dissolve1.5 边线倒角 Bevel1.6 循环边 Loop Edges1.7 并排边 Ring Edges1.8 桥接循环边 1. 边操作 1.1 边的细分 Subdivide 在边选择模式&#xff0c;选中一条边&#xff0c;右键&…

JVM系列(十一) 垃圾收集器之 Concurrent Mark Sweep 并发标记清除

垃圾收集器之 Concurrent Mark Sweep 并发标记清除 上几篇文章我们讲解了单线程垃圾收集器 Serial/SerialOld ,多线程垃圾收集器 Parallel Scavenge/Old, 本文我们讲解下 Concurrent Mark Sweep 简称CMS垃圾收集器 垃圾收集器 新生代收集器&#xff1a; Serial、ParNew、Par…

图解 | 原来这就是网络

​​ 你是一台电脑&#xff0c;你的名字叫 A 很久很久之前&#xff0c;你不与任何其他电脑相连接&#xff0c;孤苦伶仃。 ​ 直到有一天&#xff0c;你希望与另一台电脑 B 建立通信&#xff0c;于是你们各开了一个网口&#xff0c;用一根网线连接了起来。 ​ 用一根网线连接起来…

[晕事]今天做了件晕事7

今天在使用iptables与grep的时候碰到一件晕事&#xff1b; 第一步添加了一条rule到OUTPUT&#xff1a; iptables -A OUTPUT --source 10.87.51.2 --destination 10.87.51.10 -p tcp --sport 5060 -j DROP 第二步使用&#xff1a;iptables -nL | grep DROP 发现这条记录跑到了FO…

玩转ESP32 PWM输出,制作炫酷呼吸灯效果

文章目录 什么是PWM软硬件使用ESP32实现PWM输出代码讲解结语 什么是PWM PWM&#xff08;Pulse Width Modulation&#xff09;是一种常用的模拟信号产生技术&#xff0c;它通过对一个定时器的计数值进行调整来改变输出信号的占空比&#xff0c;从而控制输出信号的平均电压值&am…

idea使用 ( 二 ) 创建java项目并导入依赖jar

3.创建java项目 3.1.创建普通java项目 3.1.1.打开创建向导 接 2.3.1.创建新的项目 也可以 从菜单选择建立项目 会打开下面的选择界面 3.1.2.不使用模板 3.1.3.设置项目名 Project name : 项目名 Project location : 项目存放的位置 确认创建 3.1.4.关闭tips 将 Dont s…

Spring Boot集成ShardingSphere实现数据分片(一) | Spring Cloud 40

一、背景 传统的将数据集中存储至单一节点的解决方案&#xff0c;在性能、可用性和运维成本这三方面已经难于满足海量数据的场景。 从性能方面来说&#xff0c;由于关系型数据库大多采用 B 树类型的索引&#xff0c;在数据量超过阈值的情况下&#xff0c;索引深度的增加也将使…

Mail 邮件服务

~ Postfix ~ sdskill.com 的邮件发送服务器 ~~ 支持smtps(465)协议连接,使用Rserver颁发的证书,证书路径/CA/cacert.pem ~ 创建邮箱账户“user1~user99”(共99个用户),密码为Chinaskill20!; ~ Dovecot ~ sdskill.com 的邮件接收服务器; ~ 支持imap…

6.微服务项目实战---Sleuth--链路追踪

6.1 链路追踪介绍 在大型系统的微服务化构建中&#xff0c;一个系统被拆分成了许多模块。这些模块负责不同的功能&#xff0c;组合成 系统&#xff0c;最终可以提供丰富的功能。在这种架构中&#xff0c;一次请求往往需要涉及到多个服务。互联网应用构建在不同的软件模块集上…

Docker compose-实现多服务、nginx负载均衡、--scale参数解决端口冲突问题

Docker compose-实现多服务、nginx负载均衡、--scale参数解决端口冲突问题 问题&#xff1a;scale参数端口冲突解决方法&#xff1a;nginx实现多服务、负载均衡修改docker-compose.yml配置新增nginx本地配置文件验证启动容器查看容器状态访问web应用 问题&#xff1a;scale参数…

《二》HTTP 请求报文和响应报文、请求方法、状态码

请求报文和响应报文&#xff1a; 请求报文: 客户端向服务器发送的请求信息&#xff0c;就叫做请求报文。 客户端发送一个 HTTP 请求到服务器&#xff0c;请求信息包含四部分&#xff1a;请求行、请求头、空行、请求体。 请求行&#xff1a;包含三部分&#xff0c;分别是请…

查看库文件是32位还是64位|查看lib是静态库还是导入库|判断是debug模式还是release模式

文章目录 dll位数查看lib位数查看查看lib库是静态库还是导入库dll库文件信息查看lib库文件内容查看dll库查看编译模式是debug还是release方法一方法二方法三 lib静态库查看编译模式是debug还是release方法一方法二 lib导入库查看编译模式是debug还是release查看Linux下的.a库&a…