数据结构笔记--链表经典高频题

目录

前言

1--反转单向链表

2--反转单向链表-II

3--反转双向链表

4--打印两个有序链表的公共部分

5--回文链表

6--链表调整

7--复制含有随机指针结点的链表

8--两个单链表相交问题


前言

面经:

        针对链表的题目,对于笔试可以不太在乎空间复杂度,以时间复杂度为主(能过就行,对于任何题型都一样,笔试能过就行);对于面试,时间复杂度依然处在第一位,但要力求空间复杂度最低的算法(突出亮点);

        链表题的重要技巧包括:使用额外的数据结构记录(例如哈希表等),使用快慢指针的思想;

1--反转单向链表

笔试解法:

        借助栈先进后出,可以遍历把结点存到栈中,然后不断出栈,这样结点的顺序就反转了;

        时间复杂度为O(n),空间复杂度为O(n);

#include <iostream>
#include <stack>

struct ListNode {
     int val;
     ListNode *next;
     ListNode() : val(0), next(nullptr) {}
     ListNode(int x) : val(x), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL) return head;
        std::stack<ListNode*> st;
        while(head != NULL){
            st.push(head);
            head = head->next;
        }
        ListNode *new_head = new ListNode(0);
        ListNode *tmp = new_head;
        while(!st.empty()){
            tmp->next = st.top();
            st.pop();
            tmp = tmp->next;
        }
        tmp->next = NULL;
        return new_head->next;
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(3);
    ListNode *Node4 = new ListNode(4);
    ListNode *Node5 = new ListNode(5);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;

    Solution S1;
    ListNode *res = S1.reverseList(Node1);
    while(res != NULL){
        std::cout << res->val << " ";
        res = res->next;
    }

    return 0;
}

面试解法:

        不借助栈或递归,通过迭代将空间复杂度优化为O(1);

        利用一个额外的前驱结点 pre 来存储当前结点 cur 的前一个结点,不断更新 pre 和 cur即可;

#include <iostream>
#include <stack>

struct ListNode {
     int val;
     ListNode *next;
     ListNode() : val(0), next(nullptr) {}
     ListNode(int x) : val(x), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL) return head;
        ListNode *pre = NULL;
        ListNode *cur = head;
        while(cur != NULL){
            ListNode* next = cur->next;
            cur->next = pre;
            pre = cur;
            cur = next;
        }
        return pre;
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(3);
    ListNode *Node4 = new ListNode(4);
    ListNode *Node5 = new ListNode(5);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;

    Solution S1;
    ListNode *res = S1.reverseList(Node1);
    while(res != NULL){
        std::cout << res->val << " ";
        res = res->next;
    }

    return 0;
}

2--反转单向链表-II

主要思路:

        使用三个指针,指针 pre 指向反转区域外的第一个节点,即上图中的 1;指针 cur 指向当前指针,指针 next 指向 cur 的下一个指针;

        遍历链表,每次将 next 指针头插,具体过程可以参考官方题解;

#include <iostream>

struct ListNode {
    int val;
    ListNode *next;
    ListNode() : val(0), next(nullptr) {}
    ListNode(int x) : val(x), next(nullptr) {}
    ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* reverseBetween(ListNode* head, int left, int right) {
        ListNode *dummyNode = new ListNode(-1);
        dummyNode->next = head;
        ListNode *pre = dummyNode;
        ListNode *cur;
        ListNode *next;
        // 经过循环之后,pre指向反转区域前的第一个节点
        for(int i = 0; i < left - 1; i++){
            pre = pre->next;
        }
        cur = pre->next; // cur指向反转区域的第一个节点
        for(int i = 0; i < right - left; i++){
            next = cur->next;
            cur->next = next->next; // cur指向next的下一个节点,因为next节点要头插到pre节点后面
            next->next = pre->next; // next节点头插,指向原来的第一个节点
            pre->next = next; // next节点头插到pre节点后面
        }
        return dummyNode->next;
    }
};

int main(){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(3);
    ListNode *Node4 = new ListNode(4);
    ListNode *Node5 = new ListNode(5);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;

    Solution S1;
    int left = 2, right = 4;
    ListNode *res = S1.reverseBetween(Node1, left, right);
    while(res != NULL){
        std::cout << res->val << " ";
        res = res->next;
    }

    return 0;
}

3--反转双向链表

主要思路:

        与反转单向链表类似,使用 pre,cur 和 next 指向前一个节点,当前节点和后一个节点,不断遍历更新三个指针所指向的节点即可,并修改对应的前驱指针和后驱指针;

#include <iostream>
#include <stack>

struct ListNode {
     int val;
     ListNode *pre;
     ListNode *next;
     ListNode() : val(0), pre(nullptr), next(nullptr) {}
     ListNode(int x) : val(x), pre(nullptr), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), pre(nullptr), next(next) {}
};

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        if(head == NULL) return head;
        ListNode *pre = NULL;
        ListNode *cur = head;
        while(cur != NULL){
            ListNode* next = cur->next;
            cur->next = pre;
            cur->pre = next;
            pre = cur;
            cur = next;
        }
        return pre;
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(3);
    ListNode *Node4 = new ListNode(4);
    ListNode *Node5 = new ListNode(5);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;

    Node2->pre = Node1;
    Node3->pre = Node2;
    Node4->pre = Node3;
    Node5->pre = Node4;

    Solution S1;
    ListNode *res = S1.reverseList(Node1);
    while(res != NULL){
        std::cout << res->val << " ";
        if(res->pre != NULL) std::cout << res->pre->val;
        std::cout << std::endl;
        res = res->next;
    }

    return 0;
}

4--打印两个有序链表的公共部分

        给定两个有序链表的头指针 head1 和 head2,打印两个链表的公共部分;要求时间复杂度为O(n),额外空间复杂度要求为 O(1);

主要思路:

        类似于归并排序,由于两个链表时有序的,因此可以使用两个指针 i 和 j 分别指向两个链表;

        对于小的链表节点,指针后移;

        当比较到两个指针相等时,打印节点的值,两个指针 i 和 j 同时后移;

#include <iostream>
#include <vector>

struct ListNode {
     int val;
     ListNode *next;
     ListNode() : val(0), next(nullptr) {}
     ListNode(int x) : val(x), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    std::vector<ListNode*> printlist(ListNode* head1, ListNode* head2) {
        std::vector<ListNode*> res;
        if(head1 == NULL || head2 == NULL) return res;
        ListNode *i = head1;
        ListNode *j = head2;
        while(i != NULL && j != NULL){
            // 小的后移
            if(i->val < j->val) i = i->next;
            else if(i->val > j->val) j = j->next;
            else{ // 相等同时后移
                res.push_back(i);
                i = i->next;
                j = j->next;
            } 
        }
        return res;
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(5);

    ListNode *Node4 = new ListNode(0);
    ListNode *Node5 = new ListNode(2);
    ListNode *Node6 = new ListNode(3);
    ListNode *Node7 = new ListNode(5);

    Node1->next = Node2;
    Node2->next = Node3;


    Node4->next = Node5;
    Node5->next = Node6;
    Node6->next = Node7;

    Solution S1;
    std::vector<ListNode *> res = S1.printlist(Node1, Node4);
    for(ListNode * node : res) std::cout << node->val << " ";
    return 0;
}

5--回文链表

主要思路:

        面试做法可以参考反转单向链表,将链表反转,与原链表的结点进行比较即可,当反转链表与原链表的结点不相等,表明不是回文链表;

        空间复杂度 O(n),时间复杂度 O(n);

#include <iostream>
#include <stack>

struct ListNode {
     int val;
    ListNode *next;
     ListNode() : val(0), next(nullptr) {}
     ListNode(int x) : val(x), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == NULL) return true;
        std::stack<ListNode*> st;
        ListNode *tmp = head;
        while(tmp != NULL){
            st.push(tmp);
            tmp = tmp->next;
        }
        while(!st.empty()){
            if(head->val != st.top()->val) return false;
            head = head->next;
            st.pop();
        }
        return true;
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(2);
    ListNode *Node4 = new ListNode(1);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;

    Solution S1;
    bool res = S1.isPalindrome(Node1);
    if(res) std::cout << "true" << std::endl;
    else std::cout << "false" << std::endl;
    return 0;
}

主要思路:

        笔试解法:上述解法的空间复杂度是 O(n),使用快慢指针将空间复杂度优化为 O(1);

        主要原理是将链表由 1→2→1→2→1 构建为 1→2→1←2←1 的形式,从两端遍历进行比较;

#include <iostream>

struct ListNode {
     int val;
    ListNode *next;
     ListNode() : val(0), next(nullptr) {}
     ListNode(int x) : val(x), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    bool isPalindrome(ListNode* head) {
        if(head == NULL) return true;
        ListNode *i = head;
        ListNode *j = head;
        while(j->next != NULL && j->next->next != NULL){
            i = i -> next;
            j = j -> next -> next;
        }
        j = i->next; // right part first node
        i->next = NULL;
        ListNode *tmp = NULL;
        while(j != NULL){
            tmp = j->next;
            j->next = i;
            i = j;
            j = tmp;
        }
        j = i; // 最后一个结点
        i = head;
        while(i != NULL && j != NULL){
            if(i->val != j ->val) return false;
            i = i->next;
            j = j->next;
        }
        return true;
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(1);
    ListNode *Node2 = new ListNode(2);
    ListNode *Node3 = new ListNode(2);
    ListNode *Node4 = new ListNode(1);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;

    Solution S1;
    bool res = S1.isPalindrome(Node1);
    if(res) std::cout << "true" << std::endl;
    else std::cout << "false" << std::endl;
    return 0;
}

6--链表调整

        将单向链表按某值划分成左边小、中间相等、右边大的形式;

        题目:给定一个单链表的头结点head,结点的值类型是整型,再给定一个整数pivot,实现一个调整链表的的函数,将链表调整为左部分都是值小于pivot的结点,中间部分都是值等于pivot的结点,右部分都是值大于pivot的结点;

        要求:调整后所有小于、等于或大于pivot的结点之间的相对顺序和调整前一样,时间复杂度为O(n),空间复杂度为O(1);

#include <iostream>

struct ListNode {
     int val;
    ListNode *next;
     ListNode() : val(0), next(nullptr) {}
     ListNode(int x) : val(x), next(nullptr) {}
     ListNode(int x, ListNode *next) : val(x), next(next) {}
};

class Solution {
public:
    ListNode* change(ListNode* head, int pivot) {
        if(head == NULL) return head;
        ListNode* SH = NULL; // small head
        ListNode* ST = NULL; // small tail
        ListNode* EH = NULL; // equal head
        ListNode* ET = NULL; // equal tail
        ListNode* LH = NULL; // large head
        ListNode* LT = NULL; // large tail

        ListNode* tmp;
        while(head != NULL){
            tmp = head->next; // 下一个结点
            head->next = NULL;
            // 抽每一个结点出来进行比较
            if(head->val < pivot){
                if(SH == NULL && ST == NULL){
                    SH = head;
                    ST = head;
                }
                else{
                    ST->next = head;
                    ST = ST->next;
                }
            }
            else if(head->val == pivot){
                if(EH == NULL && ET == NULL){
                    EH = head;
                    ET = head;
                }
                else{
                    ET->next = head;
                    ET = ET->next;
                }
            }
            else{
                if(LH == NULL && LT == NULL){
                    LH = head;
                    LT = head;
                }
                else{
                    LT->next = head;
                    LT = LT->next;
                }
            }
            head = tmp; // 比较下一个结点
        }
        // 首尾相连
        if(ST != NULL){// 有小于区域
            ST->next = EH;
            ET = ET == NULL ? ST : ET; // 没有等于区域,ET变成ST
        } 
        if(ET != NULL) ET->next = LH;
        return SH != NULL ? SH : (EH != NULL ? EH : LH);
    }
};

int main(int argc, char *argv[]){
    ListNode *Node1 = new ListNode(4);
    ListNode *Node2 = new ListNode(6);
    ListNode *Node3 = new ListNode(3);
    ListNode *Node4 = new ListNode(5);
    ListNode *Node5 = new ListNode(8);
    ListNode *Node6 = new ListNode(5);
    ListNode *Node7 = new ListNode(2);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;
    Node5->next = Node6;
    Node6->next = Node7;

    Solution S1;
    int pivot = 5;
    ListNode* res = S1.change(Node1, pivot);
    while(res != NULL){
        std::cout << res->val << " ";
        res = res->next;
    }

    return 0;
}

7--复制含有随机指针结点的链表

主要思路:

        笔试解法,利用哈希表存储结点,即 key 表示原来的结点,value 表示复制的结点;

        存储完毕后,遍历结点设置复制结点的 next 指针和 value 指针即可;

#include <iostream>
#include <unordered_map>

class Node {
public:
    int val;
    Node* next;
    Node* random;
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};

class Solution {
public:
    Node* copyRandomList(Node* head) {
        std::unordered_map<Node*, Node*> hash;
        Node *tmp = head;
        while(tmp != NULL){
            hash[tmp] = new Node(tmp->val);
            tmp = tmp->next;
        }
        tmp = head;
        while(tmp != NULL){
            hash[tmp]->next = hash[tmp->next];
            hash[tmp]->random = hash[tmp->random];
            tmp = tmp->next;
        }
        return hash[head];
    }
};

int main(int argc, char *argv[]){
    Node* Node1 = new Node(7);
    Node* Node2 = new Node(13);
    Node* Node3 = new Node(11);
    Node* Node4 = new Node(10);
    Node* Node5 = new Node(1);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;

    Node1->random = NULL;
    Node2->random = Node1;
    Node3->random = Node5;
    Node4->random = Node3;
    Node4->random = Node1;

    Solution S1;
    Node* res = S1.copyRandomList(Node1);
    while(res != NULL){
        std::cout << res->val << " ";
        res = res->next;
    }
    return 0;
}

主要思路:

        面试解法,将空间复杂度优化为 O(1);

        将原链表Ori_Node1 → Ori_Node2 → Ori_Node3 构造成 Ori_Node1 → New_Node1 → Ori_Node2 → New_Node2 → Ori_Node3 → New_Node3;

        接着一对一对地去遍历链表,构建 random 指针;

        最后将新旧链表分离,构建 next 指针即可;

#include <iostream>

class Node {
public:
    int val;
    Node* next;
    Node* random;
    Node(int _val) {
        val = _val;
        next = NULL;
        random = NULL;
    }
};

class Solution {
public:
    Node* copyRandomList(Node* head) {
        if (head == NULL) return NULL;
        Node* tmp = head;
        Node* next = NULL;
        while(tmp != NULL){
            next = tmp->next; // 原链表下一个结点
            tmp->next = new Node(tmp->val); // 创建新结点
            tmp->next->next = next; // 新结点指向原链表地下一个结点
            tmp = next; // 更新tmp
        }

        tmp = head; // 遍历构建random指针
        while(tmp != NULL){
            next= tmp->next->next; // 一对一对遍历
            tmp->next->random = tmp->random != NULL ? tmp->random->next : NULL;
            tmp = next;
        }

        // 分离链表并构建next指针
        tmp = head;
        Node *res = head->next;
        Node *copy;
        while(tmp != NULL){
            copy = tmp->next;
            next = tmp->next->next; // 一对一对分离
            tmp->next= next;
            copy->next = next != NULL ? next->next : NULL;
            tmp = next;
        }
        return res;
    }
};

int main(int argc, char *argv[]){
    Node* Node1 = new Node(7);
    Node* Node2 = new Node(13);
    Node* Node3 = new Node(11);
    Node* Node4 = new Node(10);
    Node* Node5 = new Node(1);

    Node1->next = Node2;
    Node2->next = Node3;
    Node3->next = Node4;
    Node4->next = Node5;

    Node1->random = NULL;
    Node2->random = Node1;
    Node3->random = Node5;
    Node4->random = Node3;
    Node4->random = Node1;

    Solution S1;
    Node* res = S1.copyRandomList(Node1);
    while(res != NULL){
        std::cout << res->val << " ";
        res = res->next;
    }
    return 0;
}

8--两个单链表相交问题

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习之用PyTorch实现逻辑回归

0.1 学习视频源于&#xff1a;b站&#xff1a;刘二大人《PyTorch深度学习实践》 0.2 本章内容为自主学习总结内容&#xff0c;若有错误欢迎指正&#xff01; 代码&#xff08;类比线性回归&#xff09;&#xff1a; # 调用库 import torch import torch.nn.functional as F#…

手把手教你快速实现内网穿透

快速内网穿透教程 文章目录 快速内网穿透教程前言*cpolar内网穿透使用教程*1. 安装cpolar内网穿透工具1.1 Windows系统1.2 Linux系统1.2.1 安装1.2.2 向系统添加服务1.2.3 启动服务1.2.4 查看服务状态 2. 创建隧道映射内网端口3. 获取公网地址 前言 要想实现在公网访问到本地的…

【CSS】说说响应式布局

目录 一、是什么 二、怎么实现 1、媒体查询 2、百分比 3、vw/vh 4、小结 三、总结 一、是什么 响应式设计简而言之&#xff0c;就是一个网站能够兼容多个终端——而不是为每个终端做一个特定的版本。 响应式网站常见特点&#xff1a; 同时适配PC 平板 手机等…

MacOS创建NetworkExtension 【保姆级流程】

MacOS创建NetworkExtension (保姆级流程) 因为自己工作中的项目&#xff0c;是运行在macos系统上&#xff0c;其中的一部分功能是通过NetworkExtension来获取系统中的流量来做相应的处理&#xff0c;所以也想自己创建一个NetworkExtension&#xff0c;三天&#xff0c;不知道踩…

Linux系统USB转串口芯片 GPIO使用教程

一、简介 WCH的多款USB转单路/多路异步串口芯片&#xff0c;除串口接口以外&#xff0c;还提供独立的GPIO接口&#xff0c;各GPIO引脚支持独立的输出输入&#xff0c;GPIO功能的使用需要与计算机端厂商驱动程序和应用软件配合使用。各芯片的默认GPIO引脚状态有所区别&#xff…

深入理解机器学习与极大似然之间的联系

似然函数&#xff1a;事件A的发生含着有许多其它事件的发生。所以我就把这些其它事件发生的联合概率来作为事件A的概率&#xff0c;也就是似然函数。数据类型的不同&#xff08;离散型和连续性&#xff09;就有不同的似然函数 极大似然极大似然估计方法&#xff08;Maximum Li…

【逗老师的PMP学习笔记】10、项目沟通管理

目录 一、规划沟通管理1、【关键工具】沟通技术2、【关键工具】沟通模型&#xff08;沟通模式&#xff09;3、【关键工具】沟通方法4、【关键工具】文化意识5、【关键输出】沟通管理计划 二、管理沟通1、【关键工具】会议管理 三、监督沟通 一、规划沟通管理 规划沟通管理是基于…

Java集合知识回顾:从分类到工具类,掌握精髓

文章目录 1. 集合的分类2. Collection 接口3. Map 接口4. 泛型5. Collections 工具类总结 在Java编程世界中&#xff0c;集合是一项极为重要的知识&#xff0c;为我们的程序设计提供了强大的数据结构和处理手段。在本篇文章中&#xff0c;我们将回顾集合的分类以及相关的重要概…

dotNet 之网络TCP

**硬件支持型号 点击 查看 硬件支持 详情** DTU701 产品详情 DTU702 产品详情 DTU801 产品详情 DTU802 产品详情 DTU902 产品详情 G5501 产品详情 ARM dotnet 编程 dotNet使用TCP&#xff0c;可以使用Socket和TcpClient 、TcpListener类 2种&#xff0c;对于高级用户&…

nbcio-boot因升级mybatis-plus到3.5.3.1和JSQLParser 到4.6引起的online表单开发的数据库导入出错解决

更多功能看演示系统 gitee源代码地址 后端代码&#xff1a; https://gitee.com/nbacheng/nbcio-boot 前端代码&#xff1a;https://gitee.com/nbacheng/nbcio-vue.git 在线演示&#xff08;包括H5&#xff09; &#xff1a; http://122.227.135.243:9888 nbcio-boot因升级…

怎样学会单片机

0、学单片机首先要明白&#xff0c;一个单片机啥也干不了&#xff0c;学单片机的目的是学习怎么用单片机驱动外部设备&#xff0c;比如数码管&#xff0c;电机&#xff0c;液晶屏等&#xff0c;这个需要外围电路的配合&#xff0c;所以学习单片机在这个层面上可以等同为学习单片…

一起学数据结构(3)——万字解析:链表的概念及单链表的实现

上篇文章介绍了数据结构的一些基本概念&#xff0c;以及顺序表的概念和实现&#xff0c;本文来介绍链表的概念和单链表的实现&#xff0c;在此之前&#xff0c;首先来回顾以下顺序表的特点&#xff1a; 1.顺序表特点回顾&#xff1a; 1. 顺序表是一组地址连续的存储单元依次存…

11_Pulsar Adaptors适配器、kafka适配器、Spark适配器

2.3. Pulsar Adaptors适配器 2.3.1.kafka适配器 2.3.2.Spark适配器 2.3. Pulsar Adaptors适配器 2.3.1.kafka适配器 Pulsar 为使用 Apache Kafka Java 客户端 API 编写的应用程序提供了一个简单的解决方案。 在生产者中, 如果想不改变原有kafka的代码架构, 就切换到Pulsar的…

sentinel核心流程源码解析

sentinel的处理槽(ProcessorSlot) 可以说&#xff0c;sentinel实现的各种功能就是由各处理槽完成的 ,ProcessorSlot定义了四个方法&#xff1a; 当进入该处理槽时触发该方法 处理完 entry方法之后触发该方法 退出该处理槽时触发该方法 exit方法处理完成时触发该方法 sentinel的…

【MySQL安装】卸载与安装MySQL 5.7.X版本

最近由于各种原因&#xff0c;需要重新安装MySQL。之前我的版本是8.0版本&#xff0c;现在装的5.7版本。记录一下自己的安装过程。 目录 1、卸载MySQL8.0 2、安装MySQL5.7 1、卸载MySQL8.0 如何彻底卸载MySQL_mysql 完全卸载_m0小麦麦的博客-CSDN博客相信不少小伙伴们在安装…

ddia(3)----Chapter3. Storage and Retrieval

However, first we’ll start this chapter by talking about storage engines that are used in the kinds of databases that you’re probably familiar with: traditional relational databases, and also most so-called NoSQL databases. We will examine two families o…

捕捉时刻:将PDF文件中的图像提取为个性化的瑰宝(从pdf提取图像)

应用场景&#xff1a; 该功能的用途是从PDF文件中提取图像。这在以下情况下可能会很有用&#xff1a; 图片提取和转换&#xff1a;可能需要将PDF文件中的图像提取出来&#xff0c;并保存为单独的图像文件&#xff0c;以便在其他应用程序中使用或进行进一步处理。例如&#xff…

pdf怎么压缩到1m?这样做压缩率高!

PDF是目前使用率比较高的一种文档格式&#xff0c;因为它具有很高的安全性&#xff0c;还易于传输等&#xff0c;但有时候当文件体积过大时&#xff0c;会给我们带来不便&#xff0c;这时候简单的解决方法就是将其压缩变小。 想要将PDF文件压缩到1M&#xff0c;也要根据具体的情…

QGIS开发五:VS使用QT插件创建UI界面

前面我们说了在创建项目时创建的是一个空项目&#xff0c;即不使用 Qt 提供的综合开发套件 Qt Creator&#xff0c;也不使用 Qt Visual Studio Tools 这类工具。 但是后面发现&#xff0c;如果我想要有更加满意的界面布局&#xff0c;还是要自己写一个UI文件&#xff0c;如果不…

世微AP2400 电动车 摩托车灯照明 汽车灯照明 手电筒照明LED灯降压恒流驱动IC

PCB 布板参考 1. 大电流路径走线要粗&#xff0c;铺铜走线比较好。 2. 大电路回路面积以最短、最宽路径完成比较好。 3. 开关切换连接点&#xff1a;电感 L、开关管漏级与续流肖特基二极管&#xff0c;走线要短与粗&#xff0c;铺铜走线比较好&#xff0c;但同时需要适当面积作…