数据结构之单链表相关刷题

找往期文章包括但不限于本期文章中不懂的知识点:

个人主页:我要学编程(ಥ_ಥ)-CSDN博客

所属专栏:数据结构

数据结构之单链表的相关知识点及应用-CSDN博客 

下面题目基于上面这篇文章: 

下面有任何不懂的地方欢迎在评论区留言或者私信我哦!

题目链接: 206.反转链表

题目描述:

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

思路一:创建一个新的链表,把原链表中的节点头插到新链表中。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;//为了方便创建变量
//头插
void ListBuyNode(ListNode **newListHead, int val)
{
    ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
    if(newNode == NULL)
    {
        perror("malloc:");
        exit(1);
    }
    newNode->val = val;
    newNode->next = *newListHead;//新节点的next为前一个节点的地址
    *newListHead = newNode;//更新 新链表的头节点
}
struct ListNode* reverseList(struct ListNode* head) {
    ListNode *pcur = head;
    ListNode *newlist = NULL;//创建新的链表(链表是由节点组成)
    //当pcur指向为空时,就说明原链表中已经没有了节点
    while(pcur)
    {
        ListBuyNode(&newlist, pcur->val);//头插会改变头节点,因此传地址
        pcur = pcur->next;
    }
    return newlist;
}

思路二:用三个指针遍历,直接完成原链表的反转。

typedef struct ListNode ListNode;
struct ListNode* reverseList(struct ListNode* head) {
    //首先判断链表是否为空,如果是就直接返回,否则下面会有对空指针的解引用
    if(head == NULL)
    {
        return head;
    }
    ListNode *prev = NULL;
    ListNode *pcur = head;
    ListNode *next = head->next;
    while(pcur)
    {
        //把pcur的next指针指向改为prev
        pcur->next = prev;
        prev = pcur;
        pcur = next;
        if(next)//不为空,才能解引用
        {
            next = next->next;
        }
    }
    return prev;//刚好指向最后一个节点
}

题目链接:203.移除链表元素

题目描述:

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

思路一:在原链表的基础上把值为val的节点全部删除。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;//为了方便创建变脸
void ListErase(ListNode **head, ListNode *pcur)
{
    ListNode *phead = *head;
    if(*head == pcur)//要删除的是头节点
    {
        *head = pcur->next;//头节点 改变为 头节点的下一个节点
    }
    else
    {
        while(phead->next != pcur)//找到pcur前一个节点
        {
            phead = phead->next;
        }
        //直接把pcur的后一个节点的地址给到pcur前一个节点的next指针
        phead->next = pcur->next;
    }
}
struct ListNode* removeElements(struct ListNode* head, int val) {
    ListNode *pcur = head;
    if(head == NULL)
    {
        return head;
    }
    while(pcur)
    {
        if(pcur->val == val)
        {
            //删除该节点
            ListErase(&head, pcur);//可能是头节点,因此要传头指针的地址
        }
        pcur = pcur->next;
    }
    return head;
}

注意:这里不需要我们自己主动的去释放被删除的空间,平台自己会判断。 

思路二:创建一个新的链表,把值不为val的节点全部尾插到新的链表中。 

typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val) {
    ListNode *newHead = NULL;//头指针
    ListNode *newTail = NULL;//尾指针
    ListNode *pcur = head;
    while(pcur)
    {
        if(pcur->val != val)
        {
            //尾插该节点(这里只关注头指针和尾指针)
            if(newHead == NULL)//链表为空
            {
                newHead = newTail = pcur;//把这个节点即作为头也作为尾
            }
            else//链表不为空
            {
                //尾节点的next指针指向新的节点
                newTail->next = pcur;
                //新的尾节点诞生了
                newTail = pcur;
            }
        }
        pcur = pcur->next;
    }
    //最后一个节点的next要指向NULL,但是得提前判断是否为链表是否为空
    if(newTail)
    {
        newTail->next = NULL;
    }
    return newHead;
}

题目链接:876.链表的中间节点

题目描述:

给你单链表的头结点 head ,请你找出并返回链表的中间结点。

如果有两个中间结点,则返回第二个中间结点。

示例 1:

输入:head = [1,2,3,4,5]
输出:[3,4,5]
解释:链表只有一个中间结点,值为 3 。

示例 2:

输入:head = [1,2,3,4,5,6]
输出:[4,5,6]
解释:该链表有两个中间结点,值分别为 3 和 4 ,返回第二个结点。

有一种非常奇妙的方法:快慢指针。

原理:快指针——一次走两步;慢指针——一次走一步。所以就有了一个公式:2*慢指针 = 快指针,因此就得出了一个结论:当快指针走到结尾时,慢指针就走了快指针一半路程。也就是中间。

这个题目也就迎刃而解了。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
typedef struct ListNode ListNode;
struct ListNode* middleNode(struct ListNode* head) {
    ListNode *slow = head;
    ListNode *fast = head;
    while(fast!=NULL && fast->next!=NULL)//注意这里
    {
        slow = slow->next;//走一步
        fast = fast->next->next;//走两步
    }
    return slow;
}

这里有一个要注意的点是:链表中元素个数为奇数或者偶数时,判断循环跳出的条件不一样。但链表的元素个数为奇数时,fast->next == NULL,slow就走到了链表的中间节点;链表元素个数为偶数时,fast == NULL时,slow就走到了链表的中间节点 。因此只要上面有一个条件满足时,就要跳出循环了。

题目链接:牛客网——环形链表的约瑟夫问题

介绍: 

著名的Josephus问题

据说著名犹太 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与 Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。 然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在 第16个与第31个位置,于是逃过了这场死亡游戏。 

题目描述:

编号为 1 到 n 的 n 个人围成一圈。从编号为 1 的人开始报数,报到 m 的人离开。

下一个人继续从 1 开始报数。

n-1 轮结束以后,只剩下一个人,问最后留下的这个人编号是多少?

数据范围:1≤n,m≤10000

进阶:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

示例1:

输入:

5,2     

返回值:

3    

说明:

开始5个人 1,2,3,4,5 ,从1开始报数,1->1,2->2编号为2的人离开
1,3,4,5,从3开始报数,3->1,4->2编号为4的人离开
1,3,5,从5开始报数,5->1,1->2编号为1的人离开
3,5,从3开始报数,3->1,5->2编号为5的人离开
最后留下人的编号是3      

示例2:

输入:

1,1

返回值:

1

思路:首先,创建一个环形链表。创建一个单链表之后,让单链表的头尾相连就可以了。有了环形链表之后,就可以开始报数了,当报到了满足m时,就进行删除操作,不满足就继续往下走,直至整个链表中之有一个节点为止。

创建环形链表:因为这里没有现成的节点,所以我们就只能一个一个的创建。先写一个创建节点是函数。

//题目给了一个结构体,因此我们可以直接用
typedef struct ListNode ListNode;//重命名一下
//创建节点
ListNode* ListBuyNode(int n)//n是用来存放节点里储存的数据的
{
    ListNode *node = (ListNode*)malloc(sizeof(sizeof(ListNode)));//创建节点
    if (node == NULL) 
    {
        perror("malloc:");
        exit(1);
    }
    //初始化节点的内容
    node->val = n;
    node->next = NULL;
    return node;
}

当有一个一个的节点之后就可以开始创建一个链表了。

//创建带环链表
ListNode* createCircle(int n)
{
    //创建节点(1~n)  
    //创建头节点
    ListNode *head, *tail;
    for(int i=1; i<=n; i++)
    {
        ListNode *ret = ListBuyNode(i);
        if(ret->val == 1)//判断是否为头节点
        {
            head = ret;
            tail = ret;
        }
        else //更新尾节点
        {
            tail->next = ret;
            tail = tail->next;
        }
    }
    //开始创建环(头尾相连)
    tail->next = head;
    return tail;//返回尾节点
}

这里我们为什么要返回尾节点呢?因为我们最后来报数时,是要通过两个指针来遍历,如果返回头节点的话,就找不到尾节点;而返回尾节点,还是可以找到头节点。

下面就是要开始报数了。

满足报到了m的情况:

不满足报到了m的情况:

int ysf(int n, int m ) {
    //创建一个带环链表
    ListNode *prev = createCircle(n);
    //开始执行约瑟夫条件
    ListNode *pcur = prev->next;//这里相当于已经开始报数了
    int count = 1;//用于计数
    //不管怎么样最终只会剩下一个
    while(pcur->next != pcur)//当pcur->next指向自己时,就说明现在只剩下自己了
    {
        //当报数的结果满足m
        if(count == m)
        {
            //删除节点,开始重新实现带环链表,并重新开始计数
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
        }
        else 
        {
            //持续计数
            prev = pcur;
            pcur = pcur->next;
            count++;
        }
    }
    int ret = pcur->val;
    //动态开辟的空间要提前释放掉
    free(pcur);
    pcur = NULL;
    return ret;

}

完整代码(注释较少):

#include <stdlib.h>
typedef struct ListNode ListNode;
//创建节点
ListNode* ListBuyNode(int n)
{
    ListNode *node = (ListNode*)malloc(sizeof(sizeof(ListNode)));//创建节点
    if (node == NULL) 
    {
        perror("malloc:");
        exit(1);
    }
    //初始化节点的内容
    node->val = n;
    node->next = NULL;
    return node;
}
//创建带环链表
ListNode* createCircle(int n)
{
    //创建节点(1~n)  
    //创建头节点
    ListNode *head, *tail;
    for(int i=1; i<=n; i++)
    {
        ListNode *ret = ListBuyNode(i);
        if(ret->val == 1)//判断是否为头节点
        {
            head = ret;
            tail = ret;
        }
        else //更新尾节点
        {
        tail->next = ret;
        tail = tail->next;
        }
    }
    //开始创建环
    tail->next = head;
    return tail;
}

int ysf(int n, int m ) {
    //创建一个带环链表
    ListNode *prev = createCircle(n);
    //开始执行约瑟夫条件
    ListNode *pcur = prev->next;//这里相当于已经开始报数了
    int count = 1;//用于计数
    //不管怎么样最终只会剩下一个
    while(pcur->next != pcur)
    {
        //当报数的结果满足m
        if(count == m)
        {
            prev->next = pcur->next;
            free(pcur);
            pcur = prev->next;
            count = 1;
        }
        else 
        {
            prev = pcur;
            pcur = pcur->next;
            count++;
        }
    }
    int ret = pcur->val;
    free(pcur);
    pcur = NULL;
    return ret;
}

题目链接:21.合并两个有序链表

题目描述:

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

示例 1:

输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []
输出:[]

示例 3:

输入:l1 = [], l2 = [0]
输出:[0]

思路:创建一个新的链表,比较两个链表中节点的数据的大小,分别尾插到这个新链表中。

typedef struct ListNode ListNode;
void ListPopBack(ListNode **newHead, ListNode **newTail, ListNode *list)
{
    if(*newHead == NULL)//没有节点
    {
        *newHead = list;
        *newTail = list;
    }
    else
    {
        (*newTail)->next = list;
        *newTail = (*newTail)->next;
    }
}
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    //当两个链表都为空时,也就代表着list1也为空,可以返回list2
    //当list1为空时,就返回list2
    if(list1 == NULL)
    {
        return list2;
    }
    //当list2为空时,就返回list1
    if(list2 == NULL)
    {
        return list1;
    }
    //创建一个新的链表
    ListNode *newHead = NULL;
    ListNode *newTail = NULL;
    //开始比较
    while(list1 && list2)//当链表中还有节点时
    {
        if(list1->val > list2->val)
        {
            ListPopBack(&newHead, &newTail, list2);//尾插,注意是&
            list2 = list2->next;
        }
        else
        {
            ListPopBack(&newHead, &newTail, list1);
            list1 = list1->next;
        }
    }
    //还有一个有剩余
    if(list1)//l1剩余,因为链表已经是有序的了,因此就可以直接尾插
    {
        newTail->next = list1;
    }
    if(list2)//l2剩余
    {
        newTail->next = list2;
    }
    return newHead;
}

优化:这里在创建链表时,可以创建一个带头的链表,这样就不需要每次判断链表是否为空。

创建带头链表:

//创建一个带头链表
ListNode *head = (ListNode*)malloc(sizeof(ListNode));
ListNode *tail = head;
......
......
......
//
//在返回时要返回头节点的next指针,返回前要把动态开辟的内存释放掉
ListNode *ret = head->next;
free(head);
head = NULL;
return ret;

题目链接:面试题 02.04.分割链表

题目描述:

给你一个链表的头节点 head 和一个特定值 x ,请你对链表进行分隔,使得所有 小于 x 的节点都出现在 大于或等于 x 的节点之前。

你不需要 保留 每个分区中各节点的初始相对位置。

示例 1:

输入:head = [1,4,3,2,5,2], x = 3
输出:[1,2,2,4,3,5]

示例 2:

输入:head = [2,1], x = 2
输出:[1,2]

思路一:在原链表的基础上进行修改,通过双指针遍历,left指针找节点数据大于x的值,right指针找节点数据小于x的,然后再进行交换,直至right == left 停止循环。

这个思路写出来的代码非常复杂。

思路二:在原链表的基础上进行修改,通过一个指针进行遍历,节点数据大于x的就尾插到原链表中,直至这个指针找到原链表的尾节点。

这个代码也比较复杂。

思路三:创建一个新的链表,通过一个指针遍历原链表, 节点数据大于x的就尾插到新链表,节点数据小于x的就头插到新链表。

这个代码就比较好办,但还不是最简方法。

最简思路: 创建两个带头链表,根据题目给出的x,来遍历判断大小,分别存入大链表和小链表中,最后把小链表尾节点的next指针指向大链表的头指针,这样就完成了链表的分割。

typedef struct ListNode ListNode;
void ListPopBack(ListNode **Tail, ListNode *pcur)
{
    //因为我们创建的是带头链表,因此不需要判断是否为空链表
    (*Tail)->next = pcur;
    (*Tail) = (*Tail)->next;
}
struct ListNode* partition(struct ListNode* head, int x){
    //如果节点个数小于等于1个,就不需要分割了
    if(head == NULL || head->next == NULL)
    {
        return head;
    }
    //创建两个带头链表
    ListNode *lessHead = (ListNode*)malloc(sizeof(ListNode));
    ListNode *lessTail = lessHead;
    ListNode *greatHead = (ListNode*)malloc(sizeof(ListNode));
    ListNode *greatTail = greatHead;
    //开始判断大小,分割链表
    ListNode *pcur = head;
    while(pcur)
    {
        if(pcur->val < x)
        {
            //尾插到小链表中
            ListPopBack(&lessTail, pcur);
        }
        else
        {
            //尾插到大链表中
            ListPopBack(&greatTail, pcur);
        }
        pcur = pcur->next;
    }
    //开始链接大小链表
    lessTail->next = greatHead->next;
    //要有停止打印的节点,否则就会陷入死循环
    greatTail->next = NULL;
    //不能返回哨兵位,一个返回哨兵位的next指针
    return lessHead->next;
}

但是上面的代码还是会报错。

因为当输入的数据一致时,大链表没有效节点(哨兵位除外),而我们会对大链表解引用。

因此我们就需要判断大链表是否有有效节点,怎么判断呢?只需要把哨兵位的next指针赋值为NULL,再去判断这个位置是否为NULL。如果是就说明没有有效数据,就直接返回lessHead->next就行了;反之,就需要判断。

typedef struct ListNode ListNode;
void ListPopBack(ListNode **Tail, ListNode *pcur)
{
    //因为我们创建的是带头链表,因此不需要判断是否为空链表
    (*Tail)->next = pcur;
    (*Tail) = (*Tail)->next;
}
struct ListNode* partition(struct ListNode* head, int x){
    //如果节点个数小于等于1个,就不需要分割了
    if(head == NULL || head->next == NULL)
    {
        return head;
    }
    //创建两个带头链表
    ListNode *lessHead = (ListNode*)malloc(sizeof(ListNode));
    ListNode *lessTail = lessHead;
    ListNode *greatHead = (ListNode*)malloc(sizeof(ListNode));
    ListNode *greatTail = greatHead;
    greatHead->next = NULL;
    //开始判断大小,分割链表
    ListNode *pcur = head;
    while(pcur)
    {
        if(pcur->val < x)
        {
            //尾插到小链表中
            ListPopBack(&lessTail, pcur);
        }
        else
        {
            //尾插到大链表中
            ListPopBack(&greatTail, pcur);
        }
        pcur = pcur->next;
    }
    //开始链接链表之前,先判断一下
    if(greatHead->next == NULL)
    {
        return lessHead->next;
    }
    lessTail->next = greatHead->next;
    //要有停止打印的节点,否则就会陷入死循环
    greatTail->next = NULL;
    //不能返回哨兵位,一个返回哨兵位的next指针
    return lessHead->next;
}

 好啦!本期有关单链表的刷题之旅就到此结束啦!我们下一期再一起学习吧!

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

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

相关文章

OpenAI CEO山姆·奥特曼推广新AI企业服务,直面微软竞争|TodayAI

近期&#xff0c;OpenAI的首席执行官山姆奥特曼在全球多地接待了来自《财富》500强公司的数百名高管&#xff0c;展示了公司最新的人工智能服务。在旧金山、纽约和伦敦的会议上&#xff0c;奥特曼及其团队向企业界领袖展示了OpenAI的企业级产品&#xff0c;并进行了与微软产品的…

ansible的常见用法

目录 ##编辑hosts文件 ##copy模块##复制过去 ##fetch模块##拉取 ##shell模块 ##好用 ##command模块## ##file模块### ##cron模块### ##crontab 计划任务 ##下载好时间插件 ##script模块 ##yum模块## ##yum下载源配置文件 /etc/yum.repos.d/CentOS-Base.repo ##ser…

【opencv】示例-minarea.cpp 如何寻找一组随机生成的点的最小外接矩形、三角形和圆...

// 包含OpenCV库的高GUI模块和图像处理模块的头文件 #include "opencv2/highgui.hpp" #include "opencv2/imgproc.hpp"// 包含标准输入输出流的头文件 #include <iostream>// 使用命名空间cv和std&#xff0c;这样我们就可以直接使用OpenCV和标准库的…

Vitis HLS 学习笔记--ap_int.h / ap_fixed.h(1)

目录 目录 1. 概述 2. 简要规则 3. 浮点运算的复杂性 2.1 对阶 3.2 尾数运算 3.3 规格化和舍入 3.4 特殊值的处理 4. 示例&#xff08;ap_fixed.h&#xff09; 5. 量化模式&#xff08;ap_fixed.h&#xff09; 5.1 AP_SAT* 模式会增加资源用量 1. 概述 ap_int.h 和…

【网站项目】摄影竞赛小程序

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

【opencv】示例-opencv_version.cpp 输出OpenCV的版本和构建配置的示例

#include <opencv2/core/utility.hpp> // 引入OpenCV核心工具库 #include <iostream> // 引入标准输入输出流库// 定义一个包含命令行参数的字符串 static const std::string keys "{ b build | | print complete build info }" // 定义参数b&#xff…

2024年大唐杯官网模拟题

单选(出题角度很奇怪&#xff0c;不用太纠结&#xff09; 5G NR系统中&#xff0c;基于SSB的NR同频测量在measconfig里最多可以配置&#xff08; &#xff09;个SMTC窗口。 A、3 B、4 C、1 D、2 答案&#xff1a;D 2个 5G 中从BBU到AAU需要保证&#xff08; &#xff09;Gbps…

千视电子携NDI 6前沿技术,亮相北京CCBN展呈现轻量化媒体解决方案

千视携NDI 6技术闪耀2024 CCBN展会&#xff0c;呈现轻量化媒体解决方案 2024年4月24日至26日&#xff0c;北京首钢会展中心将举办第三十届中国国际广播电视网络技术展览会&#xff08;CCBN2024&#xff09;。这是中国广播电视行业的一项重要盛会&#xff0c;将有国内外超600家…

Linux硬件管理

文章目录 Linux硬件管理1.查看磁盘空间 df -h2.查看文件的磁盘占用空间 du -ah3.查看系统内存占用情况 htop Linux硬件管理 1.查看磁盘空间 df -h 语法 df [选项][参数]选项 -a或–all&#xff1a;包含全部的文件系统&#xff1b; –block-size<区块大小>&#xff1a;…

Unity打包出来的apk安装时提示应用程式与手机不兼容,无法安装应用程式

1、遇到的问题 * 2、解决办法 这是因为你在Unity中导出来的apk手机安装包是32位的&#xff0c;才导致上述问题发生&#xff0c;要解决这个办法&#xff0c;需要在Unity中导出64位的手机安装包。 32位跟64位的区别&#xff0c;以及如何区分打出来的手机安装包是否是32位或者是…

Centos服务器安装MySQL

Centos服务器安装MySQL 利用闲置服务器安装MySQL&#xff0c;用于项目练手 Linux版本&#xff1a;Centos7.9 MySQL版本&#xff1a;8.0.36 一、下载MySQL 从Oracle官网下载最新版本的MySQL wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.36-1.el7.x86_64.rp…

【OTA】STM32新能源汽车OTA技术ymodem协议PC串口升级过程

【OTA】STM32新能源汽车OTA技术ymodem协议PC串口升级过程 文章目录 前言一、实验工具1.串口USB线——烧录APP2生成的BIN文件2.STLINK——烧录BOOT代码和APP1代码3.烧录工具——将BIN文件烧录到单片机中4.FLYMCU——清除芯片FLASH 二、硬件绘制1.原理图2.PCB 三、软件配置1.BOOT…

zookeeper和kafka消息队列

zookeeper zookeeper介绍 Zookeeper是一个开源的分布式的&#xff0c;为分布式框架提供协调服务的Apache项目 zookeeper特点 zookeeper是由一个领导者(leader)&#xff0c;多个跟随者(follower)组成的集群 Zookeepe集群中只要有半数以上节点存活&#xff0c;Zookeeper集群…

express服务器 authorization 前端获取不到的问题

服务器生成token 设置在响应头&#xff0c;但是前端获取不到 const token JWT.generate({ id: new Date().getTime(), userName }, 10s) res.header(Authorization, token) axios.interceptors.response.use((response) > {console.log(response);if (response.data?.co…

关于Zookeeper+Kafka集群

文章目录 一、Zookeeper1、Zookeeper定义2、Zookeeper工作机制3、Zookeeper特点4、Zookeeper数据结构5、Zookeeper应用场景5.1 统一命名服务5.2 统一配置管理5.3 统一集群管理5.4 服务器动态上下线5.5 软负载均衡 6、Zookeeper 选举机制6.1 第一次启动选举机制6.2 非第一次启动…

ccframe系统的链路追踪,用户ID追踪的实现

需求 之前ccframe cloud V1用的是springcloud微服务&#xff0c;只需要在header将jwttoken一直传下去就没事&#xff0c;最近弄V2转dubbo发现用户id没有自动保存进数据库表。于是开始研究dubbo如何追踪&#xff0c;顺便把链路追踪ID的问题给一并解决掉。 理论 MDC MDC&…

Sonar下启动发生错误,elasticsearch启动错误

Download | SonarQube | Sonar (sonarsource.com) 1.首先我的sonar版本为 10.4.1 &#xff0c;java版本为17 2.sonar启动需要数据库,我先安装了mysql, 但是目前sonar从7.9开始不支持mysql&#xff0c;且java版本要最少11,推荐使用java17 3.安装postsql,创建sonar数据库 4.启…

海洋信息管理系统:守护蓝色星球,促进海洋经济新发展

海洋&#xff0c;覆盖地球表面超过七成的广阔水域&#xff0c;是生命之源&#xff0c;也是经济发展的重要空间。然而&#xff0c;随着人类活动的增加&#xff0c;海洋生态环境面临严峻挑战&#xff0c;海洋资源的可持续利用成为全球关注的焦点。在这样的背景下&#xff0c;构建…

爱奇艺APP Android低端机性能优化

01 背景介绍 在智能手机市场上&#xff0c;高端机型经常备受瞩目&#xff0c;但低端机型亦占据了不可忽视的份额。众多厂商为满足低端市场的需求&#xff0c;不断推出低配系列手机。另外过去几年的中高端机型&#xff0c;随着系统硬件的快速迭代&#xff0c;现已经被归类为低端…

NPM 命令备忘单

NPM 简介 Node Package Manager (NPM) 是 Node.js 环境中不可或缺的命令行工具&#xff0c;充当包管理器来安装、更新和管理 Node.js 应用程序的库、包和模块。对于每个 Node.js 开发人员来说&#xff0c;无论他们的经验水平如何&#xff0c;它都是一个关键工具。 NPM 的主要…