26考研——线性表_ 线性表的链式表示_单链表(2)

news2025/4/2 17:31:31

408答疑


文章目录

  • 三、 线性表的链式表示
    • 单链表
      • 概念
        • 单链表的结构
        • 头结点
      • 单链表上基本操作的实现
        • 单链表的初始化
          • 带头结点和不带头结点的初始化操作
          • 注意
        • 求表长操作
        • 按序号查找结点
        • 按值查找表结点
        • 插入结点操作
          • 扩展:对某一结点进行前插操作
        • 删除结点操作
          • 扩展:删除结点 *p
        • 采用头插法建立单链表
        • 采用尾插法建立单链表
        • 注意
      • 单链表的代码实操
        • 定义结点
        • 单链表的初始化
          • 带头结点的单链表初始化
          • 不带头结点的单链表初始化
        • 带头结点的求表长操作
        • 打印单链表
          • 带头结点的链表打印
          • 不带头结点的链表打印
        • 采用头插法建立带头结点的单链表
        • 采用尾插法建立单链表
          • 带头结点的链表创建
          • 不带头结点的链表创建
        • 带头结点的查找结点
          • 按序号查找结点
          • 按值查找结点
        • 插入结点
          • 在 Key 结点的后面插入 x 结点
          • 在 Key 结点的前面插入 x 结点(不带头结点)
        • 删除结点(不带头结点)
        • 带头结点的反转链表
        • 排序链表
  • 五、参考资料
    • 鲍鱼科技课件
    • 26王道考研书


三、 线性表的链式表示

  • 顺序表的存储位置可以用一个简单直观的公式表示,它可以随机存取表中任一元素,但插入和删除操作需要移动大量元素。链式存储线性表时,不需要使用地址连续的存储单元,即不要求逻辑上相邻的元素在物理位置上也相邻,它通过“链”建立元素之间的逻辑关系,因此插入和删除操作不需要移动元素,而只需修改指针,但也会失去顺序表可随机存取的优点。

单链表

概念

  • 链表是线性结构的链式实现,数据通过结点进行保存和链接。

在这里插入图片描述

单链表的结构
  • 单链表是指通过一组任意的存储单元来存储线性表中的数据元素。为了建立数据元素之间的线性关系,对每个链表结点,除存放元素自身的信息外,还需要存放一个指向其后继的指针。单链表结点结构如图所示,其中 data 为数据域,存放数据元素;next 为指针域,存放其后继结点的地址。

在这里插入图片描述

  • 利用单链表可以解决顺序表需要大量连续存储单元的缺点,但附加的指针域,也存在浪费存储空间的缺点。单链表的元素离散地分布在存储空间中,因此是非随机存取的存储结构,即不能直接找到表中某个特定结点。查找特定结点时,需要从表头开始遍历,依次查找。
头结点
  • 通常用头指针 L(或 head 等)来标识一个单链表,指出链表的起始地址,头指针为 NULL 时表示一个空表。此外,为了操作上的方便,在单链表第一个数据结点之前附加一个结点,称为头结点。头结点的数据域可以不设任何信息,但也可以记录表长等信息。单链表带头结点时,头指针 L 指向头结点,如下图(1)所示。单链表不带头结点时,头指针 L 指向第一个数据结点,如下图(2)所示。表尾结点的指针域为 NULL(用“^”表示)。

在这里插入图片描述

  • 头结点和头指针的关系:不管带不带头结点,头指针都始终指向链表的第一个结点,而头结点是带头结点的链表中的第一个结点,结点内通常不存储信息。

  • 引入头结点后,可以带来两个优点:

    1. 第一个数据结点的位置被存放在头结点的指针域中,因此在链表的第一个位置上的操作和在表的其他位置上的操作一致,无须进行特殊处理。
    2. 无论链表是否为空,其头指针都是指向头结点的非空指针(空表中头结点的指针域为空),因此空表和非空表的处理也就得到了统一。

单链表上基本操作的实现

单链表的初始化
带头结点和不带头结点的初始化操作
  • 带头结点的单链表初始化时,需要创建一个头结点,并让头指针指向头结点,头结点的 next 域初始化为 NULL
  • 不带头结点的单链表初始化时,只需将头指针 L 初始化为 NULL
注意
  • p 为指向链表结点的结构体指针,则 *p 表示结点本身,因此可用 p->data(*p).data 访问 *p 这个结点的数据域。二者完全等价。成员运算符 . 左边是一个普通的结构体变量,而指向运算符 -> 左边是一个结构体指针。通过 (*p).next 可以得到指向下一个结点的指针,因此 (*(*p).next).data 就是下一个结点中存放的数据,或者直接用 p->next->data
求表长操作
  • 求表长操作是计算单链表中数据结点的个数,需要从第一个结点开始依次访问表中每个结点,为此需设置一个计数变量,每访问一个结点,其值加 1,直到访问到空结点为止。
  • 求表长操作的时间复杂度为 O ( n ) O(n) O(n)。另需注意的是,因为单链表的长度是不包括头结点的,因此不带头结点和带头结点的单链表在求表长操作上会略有不同。
按序号查找结点
  • 从单链表的第一个结点开始,沿着 next 域从前往后依次搜索,直到找到第 i 个结点为止,则返回该结点的指针;若 i 大于单链表的表长,则返回 NULL
  • 按序号查找操作的时间复杂度为 O ( n ) O(n) O(n)
按值查找表结点
  • 从单链表的第一个结点开始,从前往后依次比较表中各结点的数据域,若某结点的 data 域等于给定值 e,则返回该结点的指针;若整个单链表中没有这样的结点,则返回 NULL
  • 按值查找操作的时间复杂度为 O ( n ) O(n) O(n)
插入结点操作
  • 插入结点操作将值为 x 的新结点插入到单链表的第 i 个位置。先检查插入位置的合法性,然后找到待插入位置的前驱,即第 i-1 个结点,再在其后插入。
  • 其操作过程如图所示。

在这里插入图片描述

  1. 首先查找第 i-1 个结点,假设第 i-1 个结点为 *p,然后令新结点 *s 的指针域指向 *p 的后继,再令结点 *p 的指针域指向新插入的结点 *s
  2. 插入时,① 和 ② 的顺序不能颠倒,否则,先执行 p->next=s 后,指向其原后继的指针就不存在了,再执行 s->next=p->next 时,相当于执行了 s->next=s,显然有误。本算法主要的时间开销在于查找第 i-1 个元素,时间复杂度为 O ( n ) O(n) O(n)。若在指定结点后插入新结点,则时间复杂度仅为 O ( 1 ) O(1) O(1)。需注意的是,当链表不带头结点时,需要判断插入位置 i 是否为 1,若是,则要做特殊处理,将头指针 L 指向新的首结点。当链表带头结点时,插入位置 i 为 1 时不用做特殊处理。
扩展:对某一结点进行前插操作
  • 前插操作是指在某结点的前面插入一个新结点,后插操作的定义刚好与之相反。在单链表插入算法中,通常都采用后插操作。以上面的算法为例,先找到第 i-1 个结点,即插入结点的前驱,再对其执行后插操作。由此可知,对结点的前插操作均可转化为后插操作,前提是从单链表的头结点开始顺序查找到其前驱结点,时间复杂度为 O ( n ) O(n) O(n)

  • 此外,可采用另一种方式将其转化为后插操作来实现,设待插入结点为 *s,将 *s 插入到 *p 的前面。我们仍然将 *s 插入到 *p 的后面,然后将 p->datas->data 交换,这样做既满足逻辑关系,又能使得时间复杂度为 O ( 1 ) O(1) O(1)

删除结点操作
  • 删除结点操作是将单链表的第 i 个结点删除。先检查删除位置的合法性,然后查找表中第 i-1 个结点,即被删结点的前驱,再删除第 i 个结点。其操作过程如图所示。

在这里插入图片描述

  1. 假设结点 *p 为找到的被删结点的前驱,为实现这一操作后的逻辑关系的变化,仅需修改 *p 的指针域。将 *p 的指针域 next 指向 *q 的下一结点,然后释放 *q 的存储空间。

  2. 同插入算法一样,该算法的主要时间也耗费在查找操作上,时间复杂度为 O ( n ) O(n) O(n)。当链表不带头结点时,需要判断被删结点是否为首结点,若是,则要做特殊处理,将头指针 L 指向新的首结点。当链表带头结点时,删除首结点和删除其他结点的操作是相同的。

扩展:删除结点 *p
  • 要删除某个给定结点 *p,通常的做法是先从链表的头结点开始顺序找到其前驱,然后执行删除操作。其实,删除结点 *p 的操作可用删除 *p 的后继来实现,实质就是将其后继的值赋予其自身,然后再删除后继,也能使得时间复杂度为 O ( 1 ) O(1) O(1)
采用头插法建立单链表
  • 该方法从一个空表开始,生成新结点,并将读取到的数据存放到新结点的数据域中,然后将新结点插入到当前链表的表头,即头结点之后,如下图所示。

在这里插入图片描述

  • 采用头插法建立单链表时,读入数据的顺序与生成的链表中元素的顺序是相反的,可用来实现链表的逆置。每个结点插入的时间为 O ( 1 ) O(1) O(1),设单链表长为 n,则总时间复杂度为 O ( n ) O(n) O(n)

  • 若单链表不带头结点,则在头部插入新结点时,每次插入新结点后,都需要将它的地址赋值给头指针 L

采用尾插法建立单链表
  • 头插法建立单链表的算法虽然简单,但生成的链表中结点的次序和输入数据的顺序不一致。若希望两者次序一致,则可采用尾插法。该方法将新结点插入到当前链表的表尾,为此必须增加一个尾指针 r,使其始终指向当前链表的尾结点,如下图所示。

在这里插入图片描述

因为附设了一个指向表尾结点的指针,所以时间复杂度和头插法的相同。

注意
  • 单链表是整个链表的基础,读者一定要熟练掌握单链表的基本操作算法。在设计算法时,建议先通过画图的方法理清算法的思路,然后进行算法的编写。

单链表的代码实操

定义结点
  • 定义单链表的结点类型,包括数据域和指针域。
typedef struct ListNode {
    ElemType data;         // 数据域
    struct ListNode *next; // 指针域
} ListNode, *LinkList;
单链表的初始化
带头结点的单链表初始化
  • 带头结点的单链表初始化时,需要创建一个头结点,并让头指针指向头结点,头结点的 next 域初始化为 NULL。
bool InitList(LinkList &L) {
    L = (ListNode*)malloc(sizeof(ListNode)); // 创建头结点
    L->next = NULL; // 头结点之后暂时还没有元素结点
    return true;
}
不带头结点的单链表初始化
  • 不带头结点的单链表初始化时,只需将头指针 L 初始化为 NULL。
bool InitList(LinkList &L) {
    L = NULL; // 头指针初始化为 NULL
    return true;
}
带头结点的求表长操作
  • 求表长操作是计算单链表中数据结点的个数,需要从第一个结点开始依次访问表中每个结点,为此需设置一个计数变量,每访问一个结点,其值加 1,直到访问到空结点为止。
int Length(LinkList L) {
    int len = 0; // 计数变量,初始为 0
    ListNode *p = L;
    while (p->next != NULL) { // 遍历链表直到最后一个结点
        p = p->next; // 移动到下一个结点
        len++; // 计数加 1
    }
    return len;
}
打印单链表
  • 从头结点或第一个数据结点开始,依次访问每个结点,打印其数据域,直到链表结束。
带头结点的链表打印
void printList_H(LinkList L) {
    ListNode *p = L->next;
    while (p != NULL) {
        printf("%d-->", p->data);
        p = p->next;
    }
    printf("Over.\n");
}
不带头结点的链表打印
void printList(LinkList L) {
    ListNode *p = L;
    while (p != NULL) {
        printf("%d-->", p->data);
        p = p->next;
    }
    printf("Over.\n");
}
采用头插法建立带头结点的单链表
  • 采用头插法建立单链表时,读入数据的顺序与生成的链表中元素的顺序是相反的,可用来实现链表的逆置。
LinkList List_HeadInsert(LinkList &L) { // 逆向建立单链表
    ListNode *s, *p;
    int x;
    L = (ListNode*)malloc(sizeof(ListNode)); // 创建头结点
    L->next = NULL; // 初始化为空链表
    scanf("%d", &x);
    while (x != 9999) { // 输入 9999 表示结束
        s = (ListNode*)malloc(sizeof(ListNode)); // 创建新结点
        s->data = x;
        s->next = L->next; // 将新结点插入表中,L 为头指针
        L->next = s;
        scanf("%d", &x);
    }
    return L;
}
采用尾插法建立单链表
带头结点的链表创建
ListNode* createList_H(ElemType ar[], int n) {
    ListNode *phead = (ListNode*)malloc(sizeof(ListNode));
    phead->data = -1;
    phead->next = NULL;

    ListNode *p = phead;
    for (int i = 0; i < n; i++) {
        ListNode *s = (ListNode*)malloc(sizeof(ListNode));
        s->data = ar[i];
        s->next = NULL;

        p->next = s;
        p = s;
    }
    return phead;
}
不带头结点的链表创建
ListNode* createList(ElemType ar[], int n) {
    ListNode *phead = (ListNode*)malloc(sizeof(ListNode));
    phead->data = ar[0];
    phead->next = NULL;

    ListNode *p = phead;
    for (int i = 1; i < n; i++) {
        ListNode *s = (ListNode*)malloc(sizeof(ListNode));
        s->data = ar[i];
        s->next = NULL;

        p->next = s;
        p = s;
    }
    return phead;
}
带头结点的查找结点
按序号查找结点
  • 从单链表的第一个结点开始,沿着 next 域从前往后依次搜索,直到找到第 i 个结点为止,则返回该结点的指针;若 i 大于单链表的表长,则返回 NULL。
ListNode* GetElem(LinkList L, int i) {
    ListNode *p = L; // 指针 p 指向当前扫描到的结点
    int j = 0;   // 记录当前结点的顺序,头结点是第 0 个结点
    while (p != NULL && j < i) { // 循环找到第 i 个结点
        p = p->next; // 移动到下一个结点
        j++;        // 结点序号加 1
    }
    return p; // 返回第 i 个结点的指针或 NULL
}
按值查找结点
  • 通过遍历链表,逐个检查每个结点的数据域,直到找到目标值或遍历完整个链表。
ListNode* LocateElem(LinkList L, ElemType e) {
    if (L == NULL) return NULL; // 检查链表是否为空
    ListNode *p = L->next; // 指向第一个数据结点
    while (p != NULL && p->data != e) { // 从第一个结点开始查找数据域为 e 的结点
        p = p->next; // 移动到下一个结点
    }
    return p; // 找到后返回该结点指针,否则返回 NULL
}
插入结点
在 Key 结点的后面插入 x 结点
ListNode* insertListBack(LinkList L, ElemType key, ElemType x) {
    ListNode *pos = findNode(L, key);
    if (pos == NULL)
        return L;

    ListNode *s = (ListNode*)malloc(sizeof(ListNode));
    s->data = x;
    s->next = pos->next;
    pos->next = s;

    return L;
}
在 Key 结点的前面插入 x 结点(不带头结点)
ListNode* insertListFront(LinkList L, ElemType key, ElemType x) {
    ListNode *p = L, *pre = NULL;
    while (p != NULL && p->data != key) {
        pre = p;
        p = p->next;
    }
    if (p == NULL)
        return L;

    ListNode *s = (ListNode*)malloc(sizeof(ListNode));
    s->data = x;

    s->next = p;
    if (pre == NULL)
        L = s;
    else
        pre->next = s;

    return L;
}
删除结点(不带头结点)
ListNode* deleteNode(LinkList L, ElemType key) {
    ListNode *p = L, *pre = NULL;
    while (p != NULL && p->data != key) {
        pre = p;
        p = p->next;
    }
    if (p == NULL)
        return L;

    if (pre == NULL)
        L = p->next;
    else
        pre->next = p->next;
    free(p);
    return L;
}
带头结点的反转链表
ListNode* reverseList(LinkList L) {
    ListNode *p = L->next;
    L->next = NULL;

    while (p != NULL) {
        ListNode *q = p->next;
        p->next = L;
        L = p;
        p = q;
    }
    return L;
}
排序链表
ListNode* sortList(LinkList L) {
    ListNode *p = L->next;
    L->next = NULL;

    while (p != NULL) {
        ListNode *q = p->next;
        ListNode *cur = L, *pre = NULL;
        while (cur != NULL && p->data > cur->data) {
            pre = cur;
            cur = cur->next;
        }

        if (pre == NULL)
            L = p;
        else
            pre->next = p;

        p->next = cur;
        p = q;
    }
    return L;
}

五、参考资料

鲍鱼科技课件

b站免费王道课后题讲解:
在这里插入图片描述

网课全程班:
在这里插入图片描述

26王道考研书

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

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

相关文章

MATLAB 控制系统设计与仿真 - 31

二次型最优控制 考虑到系统如果以状态空间方程的形式给出&#xff0c;其性能指标为&#xff1a; 其中F,Q,R是有设计者事先选定。线性二次最优控制问题简称LQ(Linear Quadractic)问题,就是寻找一个控制,使得系统沿着由指定初态出发的相应轨迹,其性能指标J取得最小值。 LQ问题分…

蓝桥杯15届JAVA_A组

将所有1x1转化为2x2 即1x1的方块➗4 然后计算平方数 记得-1 2 import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.io.PrintWriter;public class Main{static BufferedReader in new BufferedReader(new In…

deepseek v3 0324实现工作流编辑器

HTML 工作流编辑器 以下是一个简单的工作流编辑器的HTML实现&#xff0c;包含基本的拖拽节点、连接线和可视化编辑功能&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewp…

20250331-智谱-沉思

背景 收到GLM沉思的消息&#xff0c;立马试用下。感觉真的太及时了。 &#xff08;背景&#xff1a;为了客户的需求“AI辅助写作”实验了2款开源workflow&#xff0c;2款在线workflow&#xff0c;好几款多智能体框架后&#xff0c;心中无底之际。。。&#xff09; 1. GLM(开启…

Java EE(17)——网络原理——IP数据报结构IP协议解析(简述)

一.IP数据报结构 (1)版本&#xff1a;指明协议的版本&#xff0c;IPv4就是4&#xff0c;IPv6就是6 (2)首部长度&#xff1a;单位是4字节&#xff0c;表示IP报头的长度范围是20~60字节 (3)8位区分服务&#xff1a;实际上只有4位TOS有效&#xff0c;分别是最小延时&#xff0c;最…

26考研|高等代数:线性空间

线性空间这一章在整个高等代数学习过程中是非常精华的部分&#xff0c;在学习这一章的过程中会有部分的概念较为抽象&#xff0c;一定要抓紧抓牢对于概念的理解&#xff0c;反复阅读与感受&#xff0c;同时也可以根据已知的解析几何中介绍的二维空间或者三维空间进行类推比较&a…

【Linux】进程间通信(IPC)-- 无名管道、命名管道

IPC机制 实现进程间通信 在多个进程间传输数据或共享信息的机制。 数据交换&#xff0c;共享资源&#xff0c;进程同步&#xff0c;消息传递。 IPC实现原理&#xff1a;通信进程能够访问相同的内存区域。 方法&#xff1a; 管道&#xff1a;无名管道pipe、命名管道FIFO S…

每日一题-力扣-2278. 字母在字符串中的百分比 0331

字母在字符串中的百分比求解方案 | 力扣 2278 题解 问题描述 给定一个字符串 s 和一个字母 letter&#xff0c;我们需要计算 letter 在 s 中出现的百分比&#xff0c;并将结果向下取整。例如&#xff0c;如果字符串是 "foobar"&#xff0c;字母是 "o"&…

关于CodeJava的学习笔记——11

一、GUI 1、最简单的GUI 只有一个按钮的GUI import java.awt.*; import javax.swing.*; public class SimpleGUI{JFrame frame;Button bt;public SimpleGUI(){frame new JFrame("标题栏内容");bt new Button("点我啊");frame.add(bt);frame.setSize(8…

首个物业plus系列展 2025上海国际智慧物业博览会开幕

AI赋能服务升级&#xff01;首个“物业plus”系列展 2025上海国际智慧物业博览会盛大开幕 3月31日&#xff0c;2025上海国际智慧物业博览会&#xff08;简称“上海物博会”&#xff09;在上海新国际博览中心N4馆隆重开幕。本届展会由广州旭杨国际展览有限公司主办&#xff0c…

rk3586开发版新增系统调用(Android13)

一、前言 最近想学一下kernel和hal,所以买了一块板子,带了个摄像头和屏幕,1100,学习投资了。这个Android内核定一个系统调用感觉是真的麻烦&#xff0c;主要是有一层bionic C&#xff0c;一开始不熟悉的时候还是花了点时间去配置。 二、kernel修改 include/uapi/asm-generic…

OCR第三个方案:PP-OCRv4的初步探索

一、PP-OCR历史简要回顾 先请出PP-OCR官网&#xff0c;理解上有出入的&#xff0c;以官网为准。 1.1 PP-OCR系列历史 PP-OCRv1&#xff08;2020&#xff09;&#xff1a;首创3.5M超轻量模型&#xff0c;奠定两阶段架构基础&#xff08;检测方向分类识别&#xff09;PP-OCRv2…

ICLR 2025 Spotlight:让机器人实现「自主进化」,蚂蚁数科、清华提出具身协同框架 BodyGen

最近&#xff0c;全球 AI 和机器学习顶会 ICLR 2025 公布了论文录取结果&#xff1a;由蚂蚁数科与清华大学联合团队提出的全新具身协同框架 BodyGen 成功入选 Spotlight&#xff08;聚光灯/特别关注&#xff09;论文。 论文出自蚂蚁数科与清华大学兴军亮老师团队合作的科研项目…

第十九章:Python-pyttsx3 库实现文本转语音功能

前言 在开发语音交互应用或需要文本转语音功能的项目时&#xff0c;pyttsx3 是一个非常实用的 Python 库。它支持离线语音合成&#xff0c;无需联网即可将文本转换为语音。本文将详细介绍 pyttsx3 的功能、用法以及常见问题的解决方法&#xff0c;并通过示例代码帮助你快速上手…

SvelteKit 最新中文文档教程(16)—— Service workers

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

Flutter项目之构建打包分析

目录&#xff1a; 1、准备部分2、构建Android包2.1、配置修改部分2.2、编译打包 3、构建ios包3.1、配置修改部分3.2、编译打包 1、准备部分 2、构建Android包 2.1、配置修改部分 2.2、编译打包 执行flutter build apk命令进行打包。 3、构建ios包 3.1、配置修改部分 3.2、编译…

24、网络编程基础概念

网络编程基础概念 网络结构模式MAC地址IP地址子网掩码端口网络模型协议网络通信的过程&#xff08;封装与解封装&#xff09; 网络结构模式 C/S结构&#xff0c;由客户机和服务器两部分组成&#xff0c;如QQ、英雄联盟 B/S结构&#xff0c;通过浏览器与服务器进程交互&#xf…

Mentalab Explore Pro携手 Wearanize + 数据集,推动睡眠科学研究

在神经科学和睡眠研究的领域&#xff0c;精确监测大脑活动是获取深入见解的关键。传统多导睡眠监测&#xff08;PSG&#xff09;设备虽然提供了详尽的数据&#xff0c;但其操作的复杂性和成本限制了其在更广泛场景中的应用。可穿戴技术的兴起提供了一种新的数据收集方式&#x…

基于 RK3588 的 YOLO 多线程推理多级硬件加速引擎框架设计(代码框架和实现细节)

一、前言 接续上一篇文章&#xff0c;这个部分主要分析代码框架的实现细节和设计理念。 基于RK3588的YOLO多线程推理多级硬件加速引擎框架设计&#xff08;项目总览和加速效果&#xff09;-CSDN博客https://blog.csdn.net/plmm__/article/details/146542002?spm1001.2014.300…

【Yolov8部署】 VS2019+opencv+onnxruntime 环境下部署目标检测模型

文章目录 前言一、导出yolov8模型为onnx文件二、VS2019中环境配置三、源码与实际运行 前言 本文主要研究场景为工业场景下&#xff0c;在工控机与工业相机环境中运行的视觉缺陷检测系统&#xff0c;因此本文主要目的为实现c环境下&#xff0c;将yolov8已训练好的检测模型使用o…