链表算法速成计划

链表算法速成计划

1.准备工作

1.1创建链表节点结构体

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

1.2 在IDE中创建链表代码

ListNode* createRandomLinkedList(int length)
{
	if (length <= 0) return NULL;

	// 设置随机数种子

	std::random_device rd; // 随机数种子
	std::mt19937 gen(rd()); // Mersenne Twister 随机数引擎
	std::uniform_int_distribution<> dis(0, 99); // 随机数分布

	// 创建头节点,数据为0到99之间的随机值
	ListNode* head = NULL;

	// 循环创建其他节点
	for (int i = 1; i < length; ++i)
	{
		ListNode* newListNode = new ListNode(dis(gen) % 100);
		newListNode->next = head;
		head = newListNode;
	}


	return head;
}

1.3 打印链表和释放链表代码

// 打印链表的函数
void printLinkedList(ListNode* head)
{
	ListNode* current = head;
	while (current != NULL)
	{
		std::cout << current->val << " -> ";
		current = current->next;
	}
	std::cout << "NULL" << std::endl;
}
// 释放链表内存的函数
void freeLinkedList(ListNode* head)
{
	ListNode* current = head;
	while (current != NULL)
	{
		ListNode* nextListNode = current->next;
		delete current;
		current = nextListNode;
	}
}

1.4 示例代码

#include <iostream>
#include <random>

using namespace  std;
struct ListNode {
	int val;
	ListNode* next;
	ListNode() : val(0), next(NULL) {}
	ListNode(int x) : val(x), next(NULL) {}
	ListNode(int x, ListNode* next) : val(x), next(next) {}
};

ListNode* createRandomLinkedList(int length)
{
	if (length <= 0) return NULL;

	// 设置随机数种子

	std::random_device rd; // 随机数种子
	std::mt19937 gen(rd()); // Mersenne Twister 随机数引擎
	std::uniform_int_distribution<> dis(0, 99); // 随机数分布

	// 创建头节点,数据为0到99之间的随机值
	ListNode* head = NULL;

	// 循环创建其他节点
	for (int i = 1; i < length; ++i)
	{
		ListNode* newListNode = new ListNode(dis(gen) % 100);
		newListNode->next = head;
		head = newListNode;
	}


	return head;
}

// 打印链表的函数
void printLinkedList(ListNode* head)
{
	ListNode* current = head;
	while (current != NULL)
	{
		std::cout << current->val << " -> ";
		current = current->next;
	}
	std::cout << "NULL" << std::endl;
}

// 释放链表内存的函数
void freeLinkedList(ListNode* head)
{
	ListNode* current = head;
	while (current != NULL)
	{
		ListNode* nextListNode = current->next;
		delete current;
		current = nextListNode;
	}
}


int main() {

	// 创建链表
	for (int i = 1; i <= 5; i++)
	{
		ListNode* head = createRandomLinkedList(10);
		cout << "第" << i << "次样例:";
		printLinkedList(head);
		//本区域填写你的函数!!!!

		//ListNode* newhead = 你的函数(head);

		cout << "第" << i << "次结果:";
		printLinkedList(head);
		// 释放链表内存
		freeLinkedList(head);
	}
	return 0;
}

在这里插入图片描述

2. 基本操作(必须熟练默写!)

2.1 头插

ListNode* head_insert(ListNode* head, ListNode* node) //head为链表,ListNode为待插入节点
{
	//本代码正常head为NULL,也就是空链表
	node->next = head; //ListNode指向head
	head = node; //让ListNode作为新的头
	return head;
}

示例

int main() {
    ListNode* head = NULL;
    for (int i = 1; i <= 5; i++)
    {
        ListNode* newhead = new Node(i);
        head = head_insert(head, newhead);
        cout << "第" << i << "次插入结果:";
        printLinkedList(head);
    }

    return 0;
}

在这里插入图片描述

2.2 头删

ListNode* head_delete(ListNode* head) //head为链表
{
	if (head == NULL)return head; //为空就直接返回
	ListNode* cur = head; //记录待删除节点
	head = head->next; //头结点只想下一个
	free(cur); //释放cur结点
	return head;
}

示例

int main() {
    ListNode* head = NULL;
    for (int i = 1; i <= 5; i++)
    {
        Node* newhead = new Node(i);
        head = head_insert(head, newhead);
        cout << "第" << i << "次插入结果:";
        printLinkedList(head);
    }
    for (int i = 1; i <= 5; i++)
    {
        head = head_delete(head);
        cout << "第" << i << "次删除结果:";
        printLinkedList(head);
    }

    return 0;
}

在这里插入图片描述

2.3 中间节点插入(包括尾插)

ListNode* middle_insert(ListNode* head, int val, ListNode* node) //本代码理解意思即可,也就是说先查找到val值的节点,然后在其后面插入ListNode,尾插也可以用这个思想!
{
	ListNode* pre = head; //pre指插入位置的前一个节点也就是val值的节点
	while (pre)
	{
		if (pre->val != val) //如果没有找到val就继续找
			pre = pre->next;
		else //找到val后进行插入
		{
			node->next = pre->next;
			pre->next = node;
			break; //插入后退出循环
		}
	}
	return head; //返回链表头节点
}

示例

int main() {
    
    ListNode* head = NULL;
    for (int i = 1; i <= 5; i++)
    {
        ListNode* newhead = new ListNode(i);
        head = head_insert(head, newhead);
        cout << "第" << i << "次插入结果:";
        printLinkedList(head);
    }

    //在1后面插入10
	ListNode* newhead = new Node(10);
    middle_insert(head, 1, newhead);
    cout << "插入结果:";
    printLinkedList(head);

    //在5后面插入20
	newhead = new Node(20);
    middle_insert(head, 5, newhead);
    cout << "插入结果:";
    printLinkedList(head);
    return 0;
}

在这里插入图片描述

2.4 删除中间节点(包括尾删)

ListNode* middle_delete(ListNode* head, int val) //先查找到val对应的节点,然后删除该节点
{
	ListNode* pre = NULL; //pre是需要删除节点的前一个位置,注意:在删除节点中前一个位置很重要,因为你只有通过前一个结点才能将链表连接起来!
	if (head->val != val) //如果需要删除的是第一个节点,那么他没有前一个节点,所以你得判断一下,如果删除的不是第一个节点,那么就可以将head赋值给pre,然后进行查找
	{
		pre = head;
	}
	else //如果要删除的是第一个节点也就是头删!
	{
		head = head_delete(head);
		return head;
	}
	while (pre->next) //pre->next就是我们要查找的待删除节点,所以这个一定不是NULL的,故while条件是这个
	{
		if (pre->next->val != val) //如果不等就往下一个查找
		{
			pre = pre->next;
		}
		else //如果查到
		{
			ListNode* cur = pre->next; //记录待删除节点
			pre->next = cur->next; //连接前后节点
			free(cur);
			break;
		}
	}
	return head;
}

示例

int main() {
    
    ListNode* head = NULL;
    for (int i = 1; i <= 5; i++)
    {
        ListNode* newhead = new ListNode(i);
        head = head_insert(head, newhead);
        cout << "第" << i << "次插入结果:";
        printLinkedList(head);
    }
    head = middle_delete(head,4);
    cout << "删除4后结果:";
    printLinkedList(head);

    head = middle_delete(head, 5);
    cout << "删除5后(也就是删除第一个位置)结果:";
    printLinkedList(head);

    head = middle_delete(head, 1);
    cout << "删除1后(也就是删除最后个位置)结果:";
    printLinkedList(head);
    return 0;
}

在这里插入图片描述

3. 力扣代码练习

3.1 合并两个有序链表

/**
 * Definition for singly-linked list.
 * 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* mergeTwoLists(ListNode* list1, ListNode* list2) {
        ListNode* newhead=new ListNode(-1);//创建哨兵头节点
        ListNode* tail=newhead;//永远指向新链表的尾部的节点
        while(list1&&list2)
        {
            if(list1->val<list2->val)//如果list1头节点小就让list1头节点尾插到newhead
            {
                ListNode* cur=list1;//cur是指向该头节点
                list1=list1->next;//然后list1就指向他的下一个节点,也就是丢弃了之前的头节点
                tail->next=cur;//newhead尾节点指向cur节点
                tail=tail->next;//tail更新到下一个节点
            }else
            {//同上
                ListNode* cur=list2;
                list2=list2->next;
                tail->next=cur;
                tail=tail->next;
            }
        }
        if(list1!=nullptr)//到这一步就是会出现要么list1还剩余节点,list2没有,要么list2还剩余节点,list1没有,这个时候只需要将整条链接到newhead尾巴后面
        {
            tail->next=list1;
        }
        if(list2!=nullptr)
        {
            tail->next=list2;
        }
        return newhead->next;//返回头节点(要范围next,应为newhead是哨兵)
    }
};

3.2 删除排序链表中的重复元素

/**
 * Definition for singly-linked list.
 * 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* deleteDuplicates(ListNode* head) {
        ListNode* pre=head;//pre指向要删除节点的前一个位置,也就是说pre是指第一个出现该数字的节点,之前后的相同节点都要被删除
        while(pre&&pre->next)//这里也要保证pre->next不是空,因为可能pre是最后一个节点,那么就没有意义了,也就是说这个循环条件是运行到倒数第二个节点
        {
            if(pre->val==pre->next->val)//如果相等这删除这个节点,然后继续循环
            {
                //ListNode* cur=pre->next;
                pre->next=pre->next->next;
                //free(cur);//考试的时候需要这样写,也就是要释放结点,但是OJ不给你释放所以我就屏蔽掉这两行代码!
    
            }
            else//如果不相等就pre指向下一个节点,  如果不懂自己根据样例画图看看
            {
                pre=pre->next;
            }
        }
        return head;
    }
};

3.3 环形链表

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    bool hasCycle(ListNode *head) {
        //本题需要特殊技巧:快慢指针
        ListNode*fast=head;
        ListNode*slow=head;
        while(fast&&fast->next)//这里的判断条件是防止fast走到NULL,出现空指针异常  因为fast每次要走两步,所以要保证fast可以走到第二步,也就是说fast和fast->next都不能为空
        {
            fast=fast->next->next;//fast走两步
            slow=slow->next;//slow走一步
            if(fast==slow)return true;//如果是循环链表,那么fast一定会追上slow,然后就返回true
        }
        return false;//走到这一步是因为head不是循环链表,fast走到尾巴了,故跳出循环
    }
};

3.4 移除链表元素

/**
 * Definition for singly-linked list.
 * 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* removeElements(ListNode* head, int val) {
        ListNode* newhead=new ListNode(-1);//创建一个哨兵,处理特殊情况(删除第一个也就是头删要特殊处理比较麻烦)
        newhead->next=head;
        ListNode* pre=newhead;//需要删除节点的前一个
        while(pre&&pre->next)//pre->next是可能需要删除的结点,故他一定要存在
        {
            if(pre->next->val==val)//如果pre->next和val相同则要删除该节点
            {
                pre->next=pre->next->next;
            }
            else//否则pre往下遍历
            {
                pre=pre->next;
            }
        }
        return newhead->next;
    }
};

3.5 反转链表

class Solution {
public:
    ListNode* reverseList(ListNode* head) {
        //头插的应用
        ListNode* newhead=NULL;
        while(head)
        {
            ListNode* cur=head;//记录需要头插的结点
            head=head->next;//head往下遍历
            cur->next=newhead;//cur指向头插链表的头
            newhead=cur;//cur作为 新 头插链表的头节点
        }
        return newhead;
    }
};

3.6 链表的中间结点

class Solution {
public:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow=head;
        ListNode* fast=head;
        while(fast&&fast->next)//查找链表中间节点,快指针走到结束,慢指针正好到中间
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        return slow;
    }
};

3.7 回文链表

class Solution {
public:
    bool isPalindrome(ListNode* head) {//算法思路:找到中间节点,将后面一半反转,然后对比
        ListNode* fast=head;
        ListNode* slow=head;
        while(fast&&fast->next)
        {
            fast=fast->next->next;
            slow=slow->next;
        }
        //这个时候slow应该是中间节点
        //但是这个时候有两个情况
        //1. A->B->C  链表长度为奇数时 fast不为空,slow是中间那个节点
        //2. A->B->C->D 链表偶数时,fast为空,slow是中间元素上取整,也就是C
        //所以这里要分情况

        if(fast)
        {
            slow=slow->next;//这里对应第一种情况,让slow到下一个节点,这样就可以让两种情况的判断过程一样
        }

        //反转链表:模板,本质就是头插 理解背上
        ListNode* newhead=NULL;
        while(slow)
        {
            ListNode* cur=slow;
            slow=slow->next;
            cur->next=newhead;//头插
            newhead=next;
        }
        while(newhead)//这样就得到两个链表,head和newhead,但是这里newhead肯定是后面半部分,所以我们使用newhead为空来判断是否结束,每次都判断对应节点是否相等,不相等就不是回文串,相等就都往下一个遍历,直到遍历结束那就是回文串
        {
            if(newhead->val!=head->val)
            {
                return false;
            }
            newhead=newhead->next;
            head=head->next;
        }
        return true;
        
    }
};

3.8 删除链表的倒数第 N 个结点

    ListNode* removeNthFromEnd(ListNode* head, int n) {
        //算法思想:让cur先走n个节点,然后让pre从头开始和cur一起走,cur走到结束了,那么pre就走到要删除节点的前一个(题目翻译就是说让pre少走n个节点)

        // 分析样例:1->2->3->4->5->NULL n=2,也就是说我们要删除4,那么我们要找到3这个位置(也就是5-2=3这个位置,那么我们只需要走两次就可以走到3),我们让cur先走2次,然后让pre和cur一起走,一直让cur走到最后一个节点的时候,pre就是要删除节点的前一个位置
        ListNode* cur=head;
        for(int i=0;i<n;i++)
        {
            if(cur==NULL)//这个是用来判断n是否合理的,比如说我长度一个是4个,你n给我5那我在遍历head的时候就会出现cur走到结束了,这个时候就什么不要操作直接返回head
                return head;
            cur=cur->next;
        }

        if(cur==NULL) return head->next;//这里如果cur走到了尾巴,那么就相当于头插,我们只需要返回头的下一个节点,还是以:1->2->3->4->5->NULL n=5为例,这个时候cur从头5个节点那么就会跑到尾巴,那么这个时候相当于头删
        //删除算法中头删和中间删除(尾删)要分别处理,我给你的代码模板中也说了
        ListNode* pre=head;
        while(cur->next)//cur走到后一个节点
        {
            cur=cur->next;
            pre=pre->next;
        }
        pre->next=pre->next->next;//删除中间的结点方法
        return head;

    }
};

3.9 排序链表(本题OJ需要nlogn,但是我们考试写出n^2复杂度就够用,所以使用插入排序思想)

/**
 * Definition for singly-linked list.
 * 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* sortList(ListNode* head) {
        //对链表进行排序,使用插入排序思想
        ListNode* newhead=NULL;//排序后的头结点
        while(head)
        {
            ListNode* cur=head;//将要插入到新链表的结点
            head=head->next;//原来链表头结点到下一个
            if(newhead==NULL||cur->val<newhead->val)//如果一开始为空,或者cur比第一个新链表头结点小,那么只能头插
            {
                cur->next=newhead;
                newhead=cur;
            }
            else
            {
                ListNode *pre=newhead;//指向将要插入位置的前一个节点
                while(pre)
                {
                    if(pre->next==NULL||cur->val<pre->next->val)//pre->next==null是查找到尾巴了,只能插入到最后一个位置,cur->val<pre->next->val是cur比pre->next节点值小,所以就要插入到pre结点后面
                    // 比如插入1   插入到-1->0->1->2->3  那么根据插入排序思想就是要插入到第一个比自己大的结点前面
                    {
                        cur->next=pre->next;
                        pre->next=cur;
                        break;//插入成功就跳出循环
                    }
                    pre=pre->next;//否则pre就一直往后查找
                }
            }
        }
        return newhead;//返回新链表头结点
    }
};

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

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

相关文章

iPhone或iPad接收的文件怎么找?怎样删除?

因为iOS系统和iPadOS系统的特殊性&#xff0c;在使用AirDroid传输文件之后&#xff0c;往往存在“找文件”的难题。本篇文章一次性解释清楚。 文件传输到iPhone/iPad之后&#xff0c;怎样才能找到&#xff1f; iPhone/iPad接收到的全部文件都可以在AirDroid右上角的【时钟】按钮…

猎板 HDI 多阶工艺:高密度互连的核心技术

一、猎板HDI引言 随着电子设备不断向小型化、高性能化和多功能化发展&#xff0c;PCB&#xff08;印刷电路板&#xff09;的设计与制造面临着前所未有的挑战。HDI&#xff08;高密度互连&#xff09;技术应运而生&#xff0c;而其中的多阶工艺更是满足了对更高布线密度、更小尺…

VUE 的前置知识

一、JavaScript----导图导出 1. JS 提供的导入导出机制&#xff0c;可以实现按需导入 1.1 在html页面中可以把JS文件通过 <script src"showMessage.js"></script> 全部导入 1.2 通过在JS文件中写export关键字导出通过 <script src"showMessage…

---Arrays类

一 java 1.Arrays类 1.1 toString&#xff08;&#xff09; 1.2 arrays.sort( )-----sort排序 1&#xff09;直接调用sort&#xff08;&#xff09; Arrays.sort() 方法的默认排序顺序是 从小到大&#xff08;升序&#xff09;。 2&#xff09;定制排序【具体使用时 调整正负…

【H2O2|全栈】JS进阶知识(六)ES6(2)

目录 前言 开篇语 准备工作 Set和Map 基本概念 Set 相互转化 常见属性和API 数组去重 并集、交集和差集 Map 转化 常见的属性和API Set和Map的区别 This的指向 function函数 箭头函数 修改this 使用方式 三种方式的异同 案例 更改this指向为obj 求数组数…

Node基本使用

1. 创建自定义全局指令 1.1 新建一个空的文件夹, 创建一个cli.js文件 1.2 在cli.js写入内容 /usr/bin/env就是让系统使用node来执行你的脚本文件。 #! /usr/bin/env node1.3 执行终端指令 // 在文件夹 node-project 的终端下执行指令npm init执行完后package.json结构如下,…

Python编程技巧:多变量赋值的优雅艺术

在Python编程的世界里&#xff0c;有许多令人惊叹的语法特性&#xff0c;而多变量赋值就像是一颗闪耀的明珠&#xff0c;它不仅让代码更优雅&#xff0c;还能提升程序的执行效率。今天我们就深入探讨这个看似简单却蕴含深意的编程技巧。 基础认识 传统的变量赋值方式&#xff…

Transformer架构笔记

Attention is All You Need. 3.Model Architecture 3.1 整体架构如图 3.2 Encoder与Decoder Encoder&#xff1a;由 N 6 N6 N6个相同的Block/Layer堆叠而成。每个Block有两个子层sub-layer&#xff1a;多头注意力和MLP&#xff08;FFN&#xff0c;前馈神经网络&#xff09;&…

网络安全简单入门与扫描

网络安全简单入门 内容大纲 策略制定安全工具其他 1、安全策略 1.1、安全三要素 要全面地认识一个安全问题,我们有很多种办法,但首先要理解安全问题的组成属性。前人通过无数实践,最后将安全的属性总结为安全三要素,简称CIA。 安全三要素是安全的基本组成元素,分别是机密性…

在WPF程序中实现PropertyGrid功能

使用C#开发过Windows Forms的都知道&#xff0c;在Windows Forms程序中&#xff0c;有一个PropertyGrid控件&#xff0c;可以用于显示对象的属性&#xff0c;在WPF中并没有默认提供此功能的控件&#xff0c;今天以一个简单的小例子&#xff0c;简述在WPF中借助WinForm的Propert…

大模型时代的具身智能系列专题(十四)

冯晨团队 冯晨是纽约大学的副教授。他对通过多学科使用启发研究实现机器人主动和协作感知和学习感兴趣&#xff0c;这些研究源自建筑、制造和运输领域。在纽约大学之前&#xff0c;冯晨是马萨诸塞州剑桥市三菱电机研究实验室 (MERL) 计算机视觉小组的研究科学家&#xff0c;专…

力扣-Hot100-栈【算法学习day.40】

前言 ###我做这类文档一个重要的目的还是给正在学习的大家提供方向&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非常非常高滴&am…

RT_Thread内核源码分析(三)——线程

目录 1. 线程结构 2. 线程创建 2.1 静态线程创建 2.2 动态线程创建 2.3 源码分析 2.4 线程内存结构 3. 线程状态 3.1 线程状态分类 3.2 就绪状态和运行态 3.3 阻塞/挂起状态 3.3.1 阻塞工况 3.4 关闭状态 3.4.1 线程关闭接口 3.4.2 静态线程关闭 3.4.3 动态线程关…

043 商品详情

文章目录 详情页数据表结构voSkuItemVo.javaSkuItemSaleAttrVo.javaAttrValueAndSkuIdVo.javaSpuAttrGroupVo.javaGroupAttrParamVo.java pom.xmlSkuSaleAttrValueDao.xmlSkuSaleAttrValueDao.javaAttrGroupDao.xmlAttrGroupServiceImpl.javaSkuInfoServiceImpl.javaSkuSaleAtt…

硬件知识 cadence16.6 原理图输出为pdf 网络名下划线偏移 (ORCAD)

1. cadence原理图输出为PDF网络名下划线偏移 生这种情况的原因 1. 设计的原理图图纸大小比正常的 A4图纸大。 2. 打印为PDF 的时候&#xff0c;打印机的设置有问题。 2.cadence原理图输出为 PDF网络名下划线偏移的情况 可以看到上图&#xff0c;网络名往上漂移。 3. 解决办法 …

Spring-boot3.4最新版整合swagger和Mybatis-plus

好家伙,今天终于开始用spring-boot3开始写项目了&#xff0c;以后要彻底告别1.x和2.x了&#xff0c;同样的jdk也来到了最低17的要求了,废话不多说直接开始 这是官方文档的要求jdk最低是17 maven最低是3.6 一. 构建工程,这一步就不需要给大家解释了吧 二. 整合Knife4j 1.大于 …

从零开始:如何使用第三方视频美颜SDK开发实时直播美颜平台

开发一个具有实时美颜功能的直播平台&#xff0c;能够显著提高用户体验和内容质量。而利用第三方视频美颜SDK可以大大简化开发过程&#xff0c;加快产品上市速度。本篇文章&#xff0c;小编将从零开始&#xff0c;详细讲解如何使用第三方视频美颜SDK开发一个实时直播美颜平台。…

ROS入门学习ONE

ros入门玩法1&#xff1a;控制小龟龟 终端1输入 sudo apt install ros-noetic-rqt-steering 新建终端2&#xff08;快捷键CtrlAltT)&#xff0c;打开控制台 roscore //启动ros系统 回到原终端 rosrun rosrun rqt_robot_steering rqt_robot_steering 新建终端3&#xff0c;…

shell脚本(二)

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

简单理解下基于 Redisson 库的分布式锁机制

目录 简单理解下基于 Redisson 库的分布式锁机制代码流程&#xff1a;方法的调用&#xff1a;具体锁的实现&#xff1a;riderBalance 方法&#xff1a;tryLock 方法&#xff08;重载&#xff09;&#xff1a;tryLock 方法&#xff08;核心实现&#xff09;&#xff1a; 简单理解…