【数据结构-单链表】(C语言版本)

今天分享的是数据结构有关单链表的操作和实践(图解法,图变化更利于理解)

记录宗旨📝: 眼(脑)过千遍,不如手过一遍。

我们都知道单链表是一种常见的链表数据结构,由一系列节点组成。每个节点包含两部分:数据域和指针域。

  • 数据域:用于存储节点中的数据。
  • 指针语:用于指向下一个节点的地址。

每个节点的指针域指向链表中的下一个节点,最后一个节点的指针域指向NULL,表示链表的结束。

链表的头节点是链表中的第一个节点。通过头节点,可以访问整个链表。

相比于数组,链表具有动态性,可以根据需要动态地插入和删除节点,而无需预先分配固定大小的内存空间。

Node1       Node2       Node3       Node4
+------+   +------+   +------+   +------+
| data |   | data |   | data |   | data |
+------+   +------+   +------+   +------+
| next |-->| next |-->| next |-->| NULL |
+------+   +------+   +------+   +------+

在上面的示例中,每个节点包含一个数据域(data)和一个指针域(next)。节点1、节点2、节点3和节点4依次连接,形成一个链表。节点4的指针域指向NULL,表示链表的结束。

通过遍历链表,可以访问链表中的所有节点,并执行相应的操作。例如,可以在链表中插入新节点、删除节点或查找特定节点等。

因此以下主要进行单链表的操作进行分析和实践

单链表的结构

在这里插入图片描述

其中head为头节点,head -> length: 链表的长度, head -> next:指向首元节点(储存首元节点的地址)。一次前一个节点指向后一个节点,尾节点最后一个NULL

头文件

#include <stdio.h> // 输入输出
#include <stdlib.h> // malloc相关库使用
#include <stdbool.h> // 工具类

声明链表结构体

通过typedef声明结构体, 并给int类型起别名,便于数据类型变更的维护。

typedef int ElementType;

typedef struct s_node
{
    // 声明节点数据域
    ElementType data;
    // 声明下一个节点的指针域
    struct s_node* next;
} ListNode;

单链表的创建–头插法创建

目前有一条数据,{1,2,3,4,5}。 然后依次添加到链表中,如图:

image.png

在这里插入图片描述

...

在这里插入图片描述

我们可以看到上面的头插法就是将数据每一个新的插入在头节点head的后面,依次往复。

// 头插法创建链表, arr: 需要插入的数据, size: 需要创建链表的长度
ListNode* topInsertList(int arr[], int size) {
    ListNode* head = (ListNode*)malloc(sizeof(ListNode));
    head -> next = NULL;
    ListNode* node;
    for (int i = 0; i < size; i++)
    {
        // 为每次新增数据节点创建空间
        node = (ListNode*)malloc(sizeof(ListNode));
        // 将数据内容分别给到新创建的空间
        node -> data = arr[i];
        // 当前数据的下一个节点为插入前头节点的下一个节点地址
        node -> next = head -> next;
        // 将头节点重新赋值为当前节点
        head -> next = node;
    }
    // 返回头节点
    return head;
}

输出: 5,4,3,2,1, 可以看出来和输入数据相反。

头插法只需要操作两个节点,当前元素指向头节点的指向,并修改头节点指向当前节点。

单链表的创建–尾插法创建

目前有一条数据,{1,2,3,4,5}。 然后依次添加到链表中,如图:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

尾插法更加直接,相当于在一条线的尾巴上进行追加链接数据。

/*
    创建一个新的链表
    arr: 创建链表的数据
    size: 创建的大小
    尾插法
    思想: 首先将新插入的节点设置成一个完整的链表节点格式,然后将头节点复制给一个临时节点,每次将临时节点都指向下一个新插入节点,保证节点的移动和链接
*/;
ListNode* rInsertList(int arr[], int size) {
    ListNode *head = (ListNode*)malloc(sizeof(ListNode));
    // node为新插入的节点。 middle为链表最后节点,当第一次创建链表时指向头节点
    ListNode *node, *middle;
    // head -> next = NULL;
    // middle临时当作头节点
    middle = head;
    for (int i = 0; i < size; i++)
    {
       node = (ListNode*)malloc(sizeof(ListNode));
       node -> data = arr[i];
       node -> next = NULL;
       middle -> next = node;
       middle = node;
    }
    middle -> next = NULL;
    return head;
}

输出: 1,2,3,4,5。 输入和输出一样。

尾插法因为需要获取到当前最后一个节点,故需要设置三个节点:头节点,当前节点,动态变化的尾节点。

遍历链表

可以将上面新创建的链表打印输出:

//打印链表
void disList(ListNode *list) {
    //(1)、当遍历链表没有head头节点的时候使用第一条:
    ListNode *node = list; // ndoe指向首节点
    
    // (2)、当遍历链表由头节点的时候选择第二条
    //ListNode *node = list -> next; // 头节点指向首元节点
    while(node != NULL) {
        printf("%d====", node -> data);
        node = node -> next;
    }
    printf("\n");
}

按照上面方式创建的链表,可以使用这个方法打印输出链表的内容。

获取链表长度

int isLength(ListNode *list) {
    //(1)、当遍历链表没有head头节点的时候使用第一条:
    ListNode *node = list;
    
    // (2)、当遍历链表由头节点的时候选择第二条
    //ListNode *node = list -> next; // 头节点指向首元节点
    // p = p-> next;
    int n = 0;
    while(node != NULL) {
        n++;
        node = node->next;
    };
    printf("长度:%d\n", n);
    return n;
}

判断是否为空

// 检查线性链表是否为空
int isEmpty(ListNode* list) {
    return list == NULL;
}

删除链表中指定元素

删除链表中的指定元素,首先需要查找当前元素所在链表中的位置,然后将该节点赋值给一个临时指针,方便修改前后指针的指向:

在这里插入图片描述

// 删除指定元素, 传入的时候,list传入需要传入链表的地址
bool deleteNode(ListNode **list, ElementType key) {
    // 声明临时指针
    ListNode *temp;
    // 判断是否为头节点
    if ((*list) -> data == key) {
        // 将头节点复制给临时指针
        temp = *list;
        // 并将头节点的指针指向后一个节点
        *list = (*list) -> next;
        // 删除头节点空间
        free(temp);
        return true;
    } else {
        // 将头节点复制给临时
        ListNode *pre = *list;
        while(pre -> next != NULL) {
            if (pre -> next -> data == key) {
                // 将temp备份为待删除节点
                temp = pre -> next;
                pre -> next = pre -> next -> next;
                free(temp);
                return true;
            } else {
                pre = pre -> next;
            }
        }
        return false;
    }
}

例如输入:{1,2,3,4,5}, 删除2,结果变成{1,3,4,5}。

可以清晰看到删除操作,在声明指针的时候,声明了三个指针,并且传入的链表头节点采用的双指针,这是为什么呢?

首先声明的临时指针用于存放当前需要删除的节点指针,如果直接删除当前节点,后续节点还未将数据节点指向头节点或者前一个节点,这会导致整个链表后续的节点丢失。当前链表就断开了,这是不允许的。 因此增加临时指针,用于过渡。

反转一个链表

  • 把当前节点的next存起来,next = curr -> next
  • 把当前节点的next指向前一个节点, curr -> next = prev
  • 前指针后移prev = curr
  • 当前指针后移curr = next
ListNode* reversList(ListNode *list) {
    ListNode *curr = list -> next;
    ListNode *prev = NULL;
    while(curr != NULL) {
        ListNode * next = (ListNode*)malloc(sizeof(ListNode));
        next = curr -> next;
        curr -> next = prev;
        prev = curr;
        curr = next;
    }
    return prev; // 返回反转后的首元节点
}

反转链表的思想就是:指定一个指针,每次给当前指针的下一个值赋值给一个临时变量,防止链表断开从而找不到后续节点;并将当前节点的的下一个指针指向赋值为新设置的节点,第一次新设置的节点为NULL,后续并将操作完的当前节点赋值给设置的节点,保证下次节点的移动从而遍历链表中的数据,依次反转元素。

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

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

相关文章

关于标准那些事——第六篇 四象之“白虎”(要素的编写)

两仪生四象——东方青龙&#xff08;木&#xff09;、西方白虎&#xff08;金&#xff09;、南方朱雀&#xff08;火&#xff09;、北方玄武&#xff08;水&#xff09; 分别对应标准编写之四象——层次的编写、要素的编写、要素的表述、格式的编排。 今天来分享一下 要素的编…

【零基础入门TypeScript】TypeScript - 环境设置

目录 本地环境设置 文本编辑器 TypeScript 编译器 安装 Node.js 在 Windows 上安装 在 Mac OS X 上安装 IDE支持 视觉工作室代码 在 Windows 上安装 在 Mac OS X 上安装 在 Linux 上安装 括号 括号的 TypeScript 扩展 var message:string "Hello World"…

如何使用Node.js快速创建本地HTTP服务器并实现公网访问服务端

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

WPF+Halcon 培训项目实战(8-9):WPF+Halcon初次开发

文章目录 前言相关链接项目专栏运行环境匹配图片WPF Halcon组件HSmartWindowControlWPF绑定读取图片运行代码运行结果 抖动问题解决运行结果 绘制矩形绘制图像会消失 绘制对象绑定事件拖动事件 前言 为了更好地去学习WPFHalcon&#xff0c;我决定去报个班学一下。原因无非是想…

试用了所有热门的报表工具,终于找到这款好用的报表工具,太赞了

经常有朋友向我咨询&#xff0c;有没有哪个报表工具既简单易上手&#xff0c;又适合绝大多数普通职场人使用。经过我的一番研究&#xff0c;我发现大家在选择报表工具时&#xff0c;主要关注以下3点&#xff1a; 1. 简单易上手&#xff1a;大家希望报表工具的学习门槛低&#…

怎样才能找到合适的产品说明书模板?方法献上

制作一份专业而吸引人的产品手册对于企业来说至关重要。然而&#xff0c;对于许多企业和个人而言&#xff0c;制作产品手册可能是一个挑战&#xff0c;因为需要一定的设计和排版能力。为了帮助大家更轻松地制作出优质的产品手册&#xff0c;下面将向大家推荐三款优秀的产品手册…

杭州默医宠物医院:猫咪应激,铲屎官一定要重视!

“猫咪应激”铲屎官们都略有耳闻&#xff0c;甚至自家猫主子也有出现过&#xff0c;但很多铲屎官对猫咪应激不重视。猫咪应激的程度可能远超出我们的想象。 一、猫应激的原因有以下方面&#xff1a; ①外出 ②搬家 ③洗澡 ④猫群不合 ⑤强迫猫咪做某些行为 ⑥主人的一惊…

jenkins+pytest+allure

jenkinspytestallure allure下载地址 Releases allure-framework/allure2 GitHub allure环境变量配置 allure --version 查看版本(确定是否配置完成) python安装allure插件 pip install allure-pytest pytest的运行指令 pytest -sv test_demo.py 开发完毕后将代码上传到…

算法训练day56|动态规划part16

583. 两个字符串的删除操作 逆向思路&#xff1a;求最长公共子序列&#xff0c;在用总长度-2*公共子序列长度 正向思路&#xff1a;删除多少 1. dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]&#xff1a;以i-1为结尾的字符串word1&#xff0c;和以j-1位结…

重读VIT:深入探索细节与影响

1. 模型架构 提起一个新模型&#xff0c;我想大家最关心的事就是&#xff1a;它到底长什么样&#xff1f;输入输出是什么&#xff1f;我要怎么用&#xff1f;所以&#xff0c;我们先来看模型架构。 1.1 Bert结构 前面说过&#xff0c;VIT几乎和Bert一致&#xff0c;我们来速扫…

隐退三年,身价4800亿元的Google创始人出面只为给他写代码?

随着 Google 发布迄今为止最强大、最通用、最灵活的大模型 Gemini 以此正面叫板 ChatGPT 之际&#xff0c;近日不少人开始细细研读 Gemini 背后的技术详解论文&#xff08;https://arxiv.org/abs/2312.11805&#xff09;&#xff0c;这一看不打紧&#xff0c;竟有许多令人意外的…

mac中excel条件格式找到每一列的最大值并标红

假设现在excel有A1:R24组数据&#xff0c;最终效果如下 先选择要处理数据的第一列&#xff0c;然后点击【条件格式】-【新建规则】 style选择【classic】以及【Use a formula to determine which cells to format】&#xff0c;输入规则【C3MAX(C$3:C$24)】 注意这里C$3前面没…

ARM CCA机密计算硬件架构之内存管理

实施了TrustZone安全扩展的Arm A-profile处理器呈现两个物理地址空间(PAS): 非安全物理地址空间安全物理地址空间Realm管理扩展增加了两个PAS: Realm物理地址空间Root物理地址空间下图显示了这些物理地址空间以及如何在工作系统中实施这些空间: 正如表格所示,根状态能够访…

干洗店洗鞋店小程序核心功能有哪些?

在繁忙的生活中&#xff0c;我们的鞋子常常承载着风尘仆仆的故事。而洗鞋小程序&#xff0c;就是那个让您的鞋子焕然一新的魔法师。通过这个小程序&#xff0c;您可以在线预约、支付&#xff0c;查询洗鞋订单&#xff0c;并与洗鞋店铺进行互动&#xff0c;轻松享受专业的洗鞋服…

【嵌入式学习笔记-01】什么是UC,操作系统历史介绍,计算机系统分层,环境变量(PATH),错误

【嵌入式学习笔记】什么是UC&#xff0c;操作系统历史介绍&#xff0c;计算机系统分层&#xff0c;环境变量&#xff08;PATH&#xff09;&#xff0c;错误 文章目录 什么是UC?计算机系统分层什么是操作系统&#xff1f; 环境变量什么是环境变量&#xff1f;环境变量的添加&am…

Redis:原理+项目实战——Redis实战1(session实现短信登录(并剖析问题))

&#x1f468;‍&#x1f393;作者简介&#xff1a;一位大四、研0学生&#xff0c;正在努力准备大四暑假的实习 &#x1f30c;上期文章&#xff1a;Redis&#xff1a;原理速成项目实战——Redis的Java客户端 &#x1f4da;订阅专栏&#xff1a;Redis速成 希望文章对你们有所帮助…

Apache Doris (五十八): Doris - Join优化原理

🏡 个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Clickhouse 技术-CSDN博客 🚩 私聊博主:加入大数据技术讨论群聊,获取更多大数据资料。 🔔 博主个人B栈地址:豹哥教你大数据的个人空间-豹哥教你大数据个人主页-哔哩哔哩视频 目录 1. Runtime Filter Join优…

台阶仪的原理与应用指南

引言&#xff1a; 表面特征是材料、化学等领域不可或缺的主要研究内容&#xff0c;合理地评价表面形貌、表面特征等&#xff0c;对于相关材料的评定、性能的分析和加工条件的改善都具有重要的意义。本文将介绍一种常用的表面测量技术——台阶仪的原理及其在各个领域的应用。 …

polar CTF WEB-veryphp

1、题目 <?php error_reporting(0); highlight_file(__FILE__); include("config.php"); class qwq {function __wakeup(){die("Access Denied!");}static function oao(){show_source("config.php");} } $str file_get_contents("ph…