手撕无头单链表


  • 💓 博客主页:江池俊的博客
  • ⏩ 收录专栏:数据结构探索
  • 👉专栏推荐:✅C语言初阶之路 ✅C语言进阶之路
  • 💻代码仓库:江池俊的代码仓库
  • 🔥编译环境:Visual Studio 2022
  • 🎉欢迎大家点赞👍评论📝收藏⭐

在这里插入图片描述

文章目录

  • 🚨一、什么是链表
    • 1.1 链表的概念
    • 1.2 链表的分类
  • 🚨二、单链表的结构
  • 🚨三、单链表的创建
    • 3.1 单链表的存储结构
    • 3.2 单链表的接口
  • 🚨四、接口实现(增、删、查、改)
    • 4.1 单链表的插入
      • 🔥前提:向内存申请节点空间
      • 📌尾插
      • 📌头插
      • 📌在pos节点之前插入x
      • 📌在pos节点以后插入x
    • 4.2 单链表的删除
      • ♨️尾删
      • ♨️头删
      • ♨️删除pos节点
      • ♨️删除pos的后一个节点
    • 4.3 单链表的其他接口实现
      • 🌟打印单链表
      • 🌟查找
      • 🌟单链表的销毁
  • 🚨五、源码
    • 5.1 `SList.h` 文件
    • 5.2 `SList.c` 文件
    • 5.3 `Test.h` 文件


🚨一、什么是链表

1.1 链表的概念

链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。

1.2 链表的分类

链表主要有单向、双向、带头节点、不带头节点、循环和非循环这些特点,再经过它们的互相组合就形成了 2 × \times × 2 × \times × 2 = 8种链表的结构。

此处我要讲解的是 不带头单向非循环 链表。


🚨二、单链表的结构

单向链表(又名单链表、线性链表) 是链表的一种,其特点是链表的链接方向是单向的,对链表的访问要通过从头部开始,依序往下读取。

一个单向链表的节点被分成两个部分。第一个部分保存或者显示关于节点的信息,第二个部分存储下一个节点的地址。单向链表只可向一个方向遍历。

在这里插入图片描述

前面我们学习了顺序表,这里我们先来分析一下顺序表和单链表的优缺点:

顺序表:

优点:

  1. 访问元素时,顺序表可以在常数时间内完成(O(1)),无论数据量多大。
  2. 顺序表可以利用缓存和预读取技术进行优化,以提高访问速度。
  3. 对于随机访问和快速查找操作,顺序表通常比单链表更高效。

缺点:

  1. 顺序表在插入和删除操作上较慢,因为可能需要移动大量的元素来保持数据的连续性。这些操作的平均时间复杂度为O(n),其中n是元素的数量。
  2. 顺序表通常需要连续的内存空间,因此当数据量非常大时,可能会面临内存分配的问题。
  3. 在顺序表中查找特定元素可能需要遍历整个数组,这在处理大量数据时可能会变得很慢。

单链表:

优点:

  1. 插入和删除操作在链表的前端和后端相对较快,时间复杂度为O(1)。
  2. 内存使用效率较高,因为每个节点只存储一个指向下一个节点的引用。
  3. 对于一些特定的问题,如反转链表或找到链表中倒数第k个元素等,单链表有较好的解决方案。

缺点:

  1. 访问链表的中间元素需要从头部开始遍历,时间复杂度为O(n),其中n是链表的长度。
  2. 在大规模数据中,查找操作可能比其他数据结构(如数组或哈希表)慢。
  3. 由于需要额外的空间来存储指针,所以内存使用量比顺序表大。

🚨三、单链表的创建

3.1 单链表的存储结构

typedef int SLTDataType;//定义数据类型的别名,方便后续存储元素类型改变的修改//定义结点类型 
typedef struct SListNode
{SLTDataType data;//每个节点存放一个数据元素struct SListNode* next;//结构体指针,指向下一个节点
}SLTNode;

3.2 单链表的接口

// 动态申请一个节点
SLTNode* BuySListNode(SLTDataType x);
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);
//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);
//尾删
void SLTPopBack(SLTNode** pphead);
//头删
void SLTPopFront(SLTNode** pphead);
//打印单链表
void SLTPrint(SLTNode* phead);
//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);
// 在pos节点之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);
// 在pos节点以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);
// 删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);
// 删除pos的后一个节点
void SLTEraseAfter(SLTNode* pos);
//单链表的销毁
void SLTDestroy(SLTNode** pphead);

🚨四、接口实现(增、删、查、改)

4.1 单链表的插入

  • 在插入节点之前我们首先需要动态申请一个节点来保存要插入的数据,并将此节点放在相应的位置。
  • 而申请节点的操作在所有插入函数中都需要进行,故我们可以将这个操作写成一个申请节点的函数,方便各种插入函数的调用。

🔥前提:向内存申请节点空间

// 动态申请一个节点
SLTNode* BuySListNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return;}newnode->data = x; newnode->next = NULL;return newnode;
}

在这里插入图片描述

📌尾插

注意:

  1. 特殊情况,当链表为空时,则需要更改链表的头指针的地址,使得它的指向不再是 NULL,而是插入的新的节点的地址。
  2. 这里需要修改链表的头指针的地址,所以在传参的时候需要传入链表头指针的地址,即接收它的形式参数为二级指针。
//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySListNode(x);if (*pphead == NULL) {*pphead = newnode;//改变了结构体指针,所以传二级指针}else{SLTNode* tail = *pphead; while (tail->next) { tail = tail->next; }tail->next = newnode;//改变的结构体,用结构体的指针即可}
}

📌头插

头插的算法比较简单,只需要将新节点的next指向链表的头,然后修改链表的头为新节点即可。即使链表为空时此算法依然成立。

//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySListNode(x);newnode->next = *pphead; *pphead = newnode; 
}

📌在pos节点之前插入x

这里我们需要保存 pos 节点之前那个节点的位置,所有使用一个临时结构体指针变量 prev来保存前一个节点的位置,然后将新的节点插入其中即可。

注意:

  • 特殊情况,当 pos 节点等于链表的头节点时,就需要进行头插的操作,将新的节点插入到链表的头节点之前,然后将新节点置为链表的头。
// 在pos节点之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);//要么都是空,要么都不是空 --- 当链表不为空时,pos不能为空//当链表为空,则pos必须为空//总结;pos一定要为有效节点,NULL不是有效节点//assert((!pos && !(*pphead)) || (pos && *pphead));assert(pos);//pos不为空assert(*pphead);//链表不为空SLTNode* newnode = BuySListNode(x); if (*pphead == pos){//头插newnode->next = *pphead;  *pphead = newnode; }else{SLTNode* prev = *pphead;//用来保存pos前面的那个节点while (prev->next != pos) {prev = prev->next; }prev->next = newnode; newnode->next = pos;  }
}

📌在pos节点以后插入x

因为是在 pos 之后插入,所以自动的 pos 极为插入位置的前一个节点,于是只要把新的节点插入到 pos 节点之后即可。

注意:

  • pos 不能为 NULL,因为 NULL 后面无法再插入节点
// 在pos节点以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySListNode(x); newnode->next = pos->next; pos->next = newnode;
}

4.2 单链表的删除

♨️尾删

删除节点操作,首先要确保链表不为空。其次,就是当链表中只有一个节点时,删除链表后,链表变成空,此时链表的头需要置为空。

//尾删
void SLTPopBack(SLTNode** pphead)
{assert(pphead&&*pphead);//没有节点不需要删除//1.一个节点的删除if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else//2.多个节点的删除{//第一种删除方式//SLTNode* prev = NULL; //SLTNode* tail = *pphead; //while (tail->next != NULL)//{//	prev = tail;//	tail = tail->next;//}//free(tail);//tail = NULL;//tail是局部变量,不置空也可以,因为出了作用域tail就销毁了//prev->next = NULL;//第二种删除方式	SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next; }free(tail->next);tail->next = NULL; }
}

♨️头删

头删也需要确保链表不为空,其次就是正常的删除节点的操作,当只有一个节点时,仍然满足逻辑。

//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* cur = (*pphead)->next; free(*pphead); *pphead = cur; 
}

♨️删除pos节点

  1. 首先,确保链表不为空
  2. 其次,判断链表的头节点是否为要删除的节点:
    • 如果是,则将链表的头节点置为此时头节点的 next
    • 如果不是,则用一个 prev 节点来保存 pos 节点的前一个节点的位置,通过 while 循环找到此节点。
// 删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);if (*pphead == pos){//头删*pphead = pos->next;free(pos);pos = NULL;}else{SLTNode* prev = *pphead;//用来保存pos节点之前的节点地址while (prev->next != pos) {prev = prev->next; }prev->next = pos->next; free(pos); pos = NULL; }
}

♨️删除pos的后一个节点

个操作比较简单,因为要删除的节点的位置的前一个节点即为 pos,所以在进行删除的时候只需要保存要删除的节点,再让 pos
next 指向 posnextnext ,最后 free 掉保存的这个要删除的节点即可。

注意:

  • 这里需要确保 pos 节点不为空且 posnext 也不为空。
// 删除pos的后一个节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* cur = pos->next;pos->next = cur->next;free(cur);
}

4.3 单链表的其他接口实现

🌟打印单链表

此算法只需要遍历一遍单链表,并将每个节点中存储的值打印出来即可,在循环外最好加上打印 NULL 的语句,便于直观的看出链表的结构。

//打印单链表
void SLTPrint(SLTNode* phead)
{while (phead){printf("%d->", phead->data);phead = phead->next;}printf("NULL\n");
}

🌟查找

同理,只需要遍历链表即可。

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{//空链表可以查找while (phead){if (phead->data == x){return phead; }phead = phead->next; }return NULL;//链表为空找不到
}

🌟单链表的销毁

  1. 首先,通过assert(pphead);确认传入的链表头指针不为空,如果为空则程序会中断。
  2. 然后,定义两个指针prevcur,其中prev指向当前节点的前一个节点,cur指向当前节点。初始时,prev为空,cur指向链表的头节点。
  3. 使用一个循环遍历链表。在循环中,首先将prev指向当前节点,然后将cur指向下一个节点。然后释放prev指向的节点的内存空间,并将prev置为空。
  4. 循环直到cur为空,即遍历完整个链表。此时,prev将会指向链表的最后一个节点。
  5. 最后,将链表的头指针设置为空,即*pphead = NULL;,表示链表已经销毁。然后输出"单链表销毁成功"。

整个过程就是从链表的头部开始,逐个释放节点的内存空间,直到链表的尾部,完成整个链表的销毁。

//单链表的销毁
void SLTDestroy(SLTNode** pphead)
{assert(pphead);SLTNode* prev = NULL;SLTNode* cur = *pphead;while (cur){prev = cur;cur = cur->next;free(prev);prev = NULL;}*pphead = NULL;printf("单链表销毁成功\n");
}

🚨五、源码

5.1 SList.h 文件

#pragma once#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int SLTDataType;//定义数据类型的别名,方便后续存储元素类型改变的修改//定义结点类型 
typedef struct SListNode
{SLTDataType data;//每个节点存放一个数据元素struct SListNode* next;//结构体指针,指向下一个节点
}SLTNode;// 动态申请一个节点
SLTNode* BuySListNode(SLTDataType x);//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x);//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x);//尾删
void SLTPopBack(SLTNode** pphead);//头删
void SLTPopFront(SLTNode** pphead);//打印单链表
void SLTPrint(SLTNode* phead);//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x);// 在pos节点之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);// 在pos节点以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x);// 删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos);// 删除pos的后一个节点
void SLTEraseAfter(SLTNode* pos);//单链表的销毁
void SLTDestroy(SLTNode** pphead);

5.2 SList.c 文件

#define _CRT_SECURE_NO_WARNINGS 1#include "SList.h"// 动态申请一个节点空间
SLTNode* BuySListNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");return;}newnode->data = x; newnode->next = NULL;return newnode;
}//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySListNode(x);if (*pphead == NULL) {*pphead = newnode;//改变了结构体指针,所以传二级指针}else{SLTNode* tail = *pphead; while (tail->next) { tail = tail->next; }tail->next = newnode;//改变的结构体,用结构体的指针即可}
}//头插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);SLTNode* newnode = BuySListNode(x);newnode->next = *pphead; *pphead = newnode; 
}//尾删
void SLTPopBack(SLTNode** pphead)
{assert(pphead&&*pphead);//没有节点不需要删除//1.一个节点的删除if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;}else//2.多个节点的删除{//第一种删除方式//SLTNode* prev = NULL; //SLTNode* tail = *pphead; //while (tail->next != NULL)//{//	prev = tail;//	tail = tail->next;//}//free(tail);//tail = NULL;//tail是局部变量,不置空也可以,因为出了作用域tail就销毁了//prev->next = NULL;//第二种删除方式SLTNode* tail = *pphead;while (tail->next->next != NULL){tail = tail->next; }free(tail->next);tail->next = NULL; }
}//头删
void SLTPopFront(SLTNode** pphead)
{assert(pphead && *pphead);SLTNode* cur = (*pphead)->next; free(*pphead); *pphead = cur; 
}//打印单链表
void SLTPrint(SLTNode* phead)
{while (phead){printf("%d->", phead->data);phead = phead->next;}printf("NULL\n");
}//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{//空链表可以查找while (phead){if (phead->data == x){return phead; }phead = phead->next; }return NULL;//链表为空找不到
}// 在pos节点之前插入x
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead);//要么都是空,要么都不是空 --- 当链表不为空时,pos不能为空//当链表为空,则pos必须为空//总结;pos一定要为有效节点,NULL不是有效节点//assert((!pos && !(*pphead)) || (pos && *pphead));assert(pos);//pos不为空assert(*pphead);//链表不为空SLTNode* newnode = BuySListNode(x); if (*pphead == pos){//头插newnode->next = *pphead;   *pphead = newnode;}else{SLTNode* prev = *pphead;//用来保存pos前面的那个节点while (prev->next != pos) {prev = prev->next;}prev->next = newnode;newnode->next = pos;  }
}// 在pos节点以后插入x
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{assert(pos);SLTNode* newnode = BuySListNode(x); newnode->next = pos->next; pos->next = newnode;
}// 删除pos节点
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);assert(pos);if (*pphead == pos){//头删*pphead = pos->next;free(pos);pos = NULL;}else{SLTNode* prev = *pphead;//用来保存pos节点之前的节点地址while (prev->next != pos) {prev = prev->next; }prev->next = pos->next; free(pos); pos = NULL; }
}// 删除pos的后一个节点
void SLTEraseAfter(SLTNode* pos)
{assert(pos && pos->next);SLTNode* cur = pos->next;pos->next = cur->next;free(cur);
}//单链表的销毁
void SLTDestroy(SLTNode** pphead)
{assert(pphead);SLTNode* prev = NULL;SLTNode* cur = *pphead;while (cur){prev = cur;cur = cur->next;free(prev);prev = NULL;}*pphead = NULL;printf("单链表销毁成功\n");
}

5.3 Test.h 文件

#define _CRT_SECURE_NO_WARNINGS 1#include "SList.h"void TestSLT1()
{SLTNode* plist = NULL; SLTPushBack(&plist, 2);SLTPushBack(&plist, 3);SLTPushBack(&plist, 4);SLTPushFront(&plist, 1); SLTPrint(plist);SLTNode* pos = SLTFind(plist, 3);//找到3的节点并返回其地址 SLTInsert(&plist, pos, 30);//在3前面插入30 SLTPrint(plist); SLTInsertAfter(pos, 40);//在3后面插入40 SLTPrint(plist); SLTPopBack(&plist);//尾删 SLTPrint(plist);  SLTPopFront(&plist);//头删 SLTPrint(plist); SLTEraseAfter(pos);//删除3后面的那个节点 SLTPrint(plist);  SLTErase(&plist, pos);//删除节点3 SLTPrint(plist); SLTDestroy(&plist);//销毁单链表 SLTPrint(plist); 
}int main()
{TestSLT1();return 0;
}

在这里插入图片描述


今天的内容就到这里了,后续我会给大家带来一些链表的 oj 题目,大家敬请期待👏

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

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

相关文章

【Python】jupyter notebook(学习笔记)

Jupyter Notebook初见 1、Jupyter Notebook介绍 web版的ipython 编程、写文档、记笔记、展示 格式.ipynb 2、为什么使用Jupyter Notebook? 画图方面的优势&#xff1a;图像的生成不会堵塞后面代码的执行数据展示方面的优势&#xff1a;生成的数据可以保存在文件中 3、J…

hive数仓-数据的质量管理

版本20231116 要理解数据的质量管理&#xff0c;应具备hive数据仓库的相关知识 文章目录 1.理解什么是数据的质量管理&#xff1a;2.数据质量管理的规划数据质量标准的分类 3.数据质量管理解决方案1.ods层的数据质量校验1&#xff09;首先在hive上建立一个仓库&#xff0c;添加…

oracle初步学习

先了解几个登录的方式 1.直接在cmd输入 sqlplus scott/tiger //登陆普通用户scott 2.输入sqlplus sys as sysdba 之后 紧接着让你输入口令&#xff0c;直接输入sys就行了 3.先输入sqlplus/nolog 在输入conn system/managerorcl 先在cmd窗口输入sqlplus/nolog &#x…

Linux输入设备应用编程(键盘,触摸屏,按键,鼠标)

目录 一 输入设备编程介绍 1.1 什么是输入设备呢&#xff1f; 1.2 什么是输入设备的应用编程&#xff1f; 1.3 input子系统 1.4 数据读取流程 1.5 应用程序如何解析数据 1.5.1 按键类事件&#xff1a; 1.5.2 相对位移事件 1.5.3 绝对位移事件 二 读取 struct input_e…

Swift爬虫程序

以下是一个简单的Swift爬虫程序&#xff0c;用于从前程无忧深圳地区招聘财务、会计的数据爬取数据&#xff1a; import Foundation import SwiftSoup// 创建一个请求对象&#xff0c;指定代理信息 var request URLRequest(url: URL(string: "https://www.51job.com/zh/c…

【软件安装】Centos系统中安装docker容器(华为云HECS云耀服务器)

这篇文章&#xff0c;主要介绍Centos系统中安装docker容器&#xff08;华为云HECS云耀服务器&#xff09;。 目录 一、安装docker 1.1、卸载旧版本docker 1.2、更新repo镜像 1.3、安装依赖包 1.4、添加docker-ce镜像 1.5、安装docker-ce 1.6、查看docker安装版本 1.7、…

Maven介绍及仓库配置

目录 一.Maven 1.介绍 坐标 仓库 1&#xff09;中央仓库 2&#xff09;本地仓库 3&#xff09;私服 配置国内源 配置过程 二.Maven功能 2.项目构建 3.依赖管理 Maven Help插件 安装 ​使用 一.Maven 1.介绍 坐标 唯一的&#xff0c;通过以下代码的三个键值对确…

【AI视野·今日CV 计算机视觉论文速览 第277期】Fri, 27 Oct 2023

AI视野今日CS.CV 计算机视觉论文速览 Fri, 27 Oct 2023 Totally 93 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computer Vision Papers A Coarse-to-Fine Pseudo-Labeling (C2FPL) Framework for Unsupervised Video Anomaly Detection Authors Anas Al lahham…

Spring-IoC与DI入门案例

IoC入门案例 IoC入门案例思路分析 管理什么&#xff1f;&#xff08;Service与Dao&#xff09;如何将被管理的对象告知IoC容器&#xff1f;&#xff08;配置&#xff09;被管理的对象交给IoC容器&#xff0c;如何获取到IoC容器&#xff1f;&#xff08;接口&#xff09;IoC容…

tcpdump wireshark简单使用

tcpdump工作原理 tcpdump 是 Linux 系统中非常有用的网络工具&#xff0c;运行在用户态&#xff0c;本质上是通过调用 libpcap 库的各种 api 来实现数据包的抓取功能&#xff0c;利用内核中的 AF_PACKET 套接字&#xff0c;抓取网络接口中传输的网络包。查 看 tcpdump 的 手册…

JVM实战-JVM之类加载时机

目录 JVM实战-JVM之类加载时机1 主动引用2 被动引用 JVM实战-JVM之类加载时机 Java虚拟机把描述类的数据从Class文件加载到内存&#xff0c;并对数据进行校验、转换解析和初始化&#xff0c;最终形成可以被虚拟机直接使用的Java类型&#xff0c;这个过程被称作虚拟机的类加载机…

JS 读取excel文件内容 和 将json数据导出excel文件

一、实现将json数据导出为excel文件 1、通过原生js实现 核心方法&#xff1a; function JSONToExcelConvertor(JSONData, FileName, title, filter) {if (!JSONData)return;//转化json为objectvar arrData typeof JSONData ! object ? JSON.parse(JSONData) : JSONData;va…

STM32 LL库 TIM3定时器多通道捕获输入采集

为什么不用HAL库&#xff0c;使用HAL库捕获输入一个通道还尚可&#xff0c;多通道捕获由于HAL的回调函数不符合我的要求&#xff0c;干脆直接切换到LL库。网上找了许多&#xff0c;代码处理写的不符合我的要求&#xff0c;这里记录一下我的调试过程。 TIM2输出1路PWM信号&#…

数据同步到Redis消息队列,并实现消息发布/订阅

一、假设需求&#xff1a; 某系统在MySQL某表中操作了一条数据在其他系统中&#xff0c;实时获取最新被操作数据的数据库名、数据表名、操作类型、数据内容 应用场景&#xff1a; 按最近项目的一个需求来说&#xff1a; 1.当某子系统向报警表中新增了一条报警数据&#xff1b;…

4.4.2.1 内部类

内部类 成员内部类 定义 调用内部类 访问修饰符的影响 外部类的成员变量及成员方法在内部类的使用 内部类在外部类的使用 静态内部类 静态内部类调用非静态外部类 1

英飞凌Tc275使用记录:Can邮箱号确认与Busoff寄存器设置方法

目录 1、消息后处理 2、消息暂存 3、Tc275 Busoff的寄存器手动处理 1、消息后处理 消息对象成功接收或发送帧后&#xff0c;可以通知CPU对消息对象执行后处理。MultiCAN模块的后处理由两个部分组成: 消息中断触发后处理。消息挂起寄存器将挂起的消息中断收集到一个公共结构中…

C#创建并调用dll

文章目录 1.VS2019创建C#主程序2.编译主程序3.添加类库工程&#xff0c;并添加计算逻辑4.给主程序添加引用项5.重新编译主程序6.主程序添加测试逻辑 1.VS2019创建C#主程序 2.编译主程序 debug目录下生成exe&#xff1a; 3.添加类库工程&#xff0c;并添加计算逻辑 添加计算逻…

每日一题(LeetCode)----数组--长度最小的子数组

每日一题(LeetCode)----数组–长度最小的子数组 1.题目&#xff08; 209.长度最小的子数组&#xff09; 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &…

国内领先的五大API接口供应商

API&#xff08;Application Programming Interface&#xff09;接口&#xff0c;现在很多应用系统中常用的开放接口&#xff0c;对接相应的系统、软件功能&#xff0c;简化专业化的程序开发。作者用过的国内比较稳定的API接口供应商有如下几家&#xff0c;大家可以参考选择&am…