链表(静态/动态创建,遍历,计数,查找,在节点的前/后方插入新节点,头插法,尾插法)

news2024/11/15 7:55:21

目录

一、前言

二、链表的静态创建和遍历

三、链表统计节点,查找节点是否存在

四、从指定节点的后方插入新节点

五、从指定节点的前方插入新节点

六、动态创建链表&尾插法

七、头插法

八、删除节点


一、前言

链表本质是一个结构体,结构体里不仅包含不同类型的数据,最重要的是定义了一个指向相同结构体类型的指针必须是相同类型的结构体),通过这个指针我们就可以将一个又一个的结构体链接(指针存放下一个结构体的地址)起来,每一个结构体就是链表的其中一个节点。

掌握以上概念,只要结合代码,相信手撕链表也不是什么难事,无非就是指针和地址的一些操作罢了。


二、链表的静态创建和遍历

我们使用链表的时候可以和数组类比,但两者还是有区别,数组是内存中连续的空间;而链表不一定在内存中连续。

我们遍历数组时,要把数组的所有元素都打印出来,一个for循环就能搞定,而链表的遍历也类似

struct test
{
    int id;//存放节点的编号
    struct test *next;//链接下一个节点的地址
};

/*静态创建链表*/
struct test n1 = {1,NULL};
struct test n2 = {2,NULL};
struct test n3 = {3,NULL};

/*我们先手动建立链接,n3.next为空*/
n1.next = &n2;
n2.next = &n3;

void printLink(struct test *head)
{
    while(head != NULL)
    {
        printf("%d ",head->id);//打印每个节点的id
        head = head->next;//把下个节点的地址给head,head从指向n1变成指向n2
    }
}

以上就是链表的最最基本的操作,看一下步骤:
\bullet head指向n1,打印1;
\bullet head->next是n2的地址,head指向n2,打印2;
\bullet head->next是n3的地址,head指向n3,打印3;
\bullet head->next为NULL,不进入while,结束。

遍历的核心就是 head = head->next 这个操作。


三、链表统计节点,查找节点是否存在

统计节点就很简单了,看得懂遍历就会:

int getLinkNodeNum(struct test *head)
{
    int cnt = 0;
    while(head != NULL)
    {
        cnt++;
        head = head->next;//关键
    }
    return cnt;
}

查找节点,我这里演示代码实现的功能就只是检查是否存在该id的节点,原理也是遍历:

int searchLink(struct test *head, int data)//data传入你想要找的id
{
    while(head != NULL)
    {
        if(head->id == data);
            return 1;//找到了直接退出该函数
        head = head->next;//遍历
    }
    return 0;//失败返回0
}

四、从指定节点的后方插入新节点

在指定节点的后方插入,首先还是要遍历链表,那么函数要传入头节点的地址;还要传入指定节点的id;接着传入新节点的地址因为我们这里还是使用静态创建的方法,每一个节点都要手动初始化)。来看代码:

int insertFromBehind(struct test *head, int data, struct test *new)
{
    while(head != NULL)
    {
        if(head->id == data)//指定id
        {
            new->next = head->next;//让新节点的next指向指定节点的next
            head->next = new;//指定节点的next指向新节点,完成插入
            return 1;
        }
        head = head->next;//遍历
    }
    return 0;
}

自己画图理解一下最好,你的next存的是谁的地址,就相当于你指向它,只要能理解这句话,链表的任何操作都不难。


五、从指定节点的前方插入新节点

从节点前方插入新节点,有可能是在头节点插入,而链表最重要的就是链表头的地址,那么函数的返回值就是结构体指针,需要返回头节点的地址(头节点可能会改变)

struct test* insertFromFront(struct test *head, int data, struct test *new)
{
    struct test *p = head;
    if(p->id == data)//表示想在头节点前面添加新节点
    {
        new->next = head;//新节点的next是原先的头节点
        return new;
    }
    while(p->next != NULL)
    {
        /*如果当前遍历到的节点的下一个节点是我们要找的*/
        if(p->next->id == data)
        {
            /*新节点的下一个节点是当前遍历到的节点的下一个节点*/
            new->next = p->next;
            /*当前遍历到的节点的下一个节点是新节点*/
            p->next = new;
            /*头节点不变,原样返回*/
            return head;
        }
        p = p->next;//遍历
    }
    printf("no this id\n");
    return head;
}

从指定节点前方插入新节点分两种情况:

(1)从头节点前插入新节点:
                直接让新节点的下一个节点为原先的头节点,返回新节点的地址。(一般一个链表的头节点head会定义成全局变量,如果头节点不知道,那就无从下手)

(2)除头节点外的其他节点前插入新节点:
                遍历链表,假设我们要在节点3前插入,那么遍历到节点2时:node2->next->id=3,new-> = node2->next,运行到这里,新节点的下一个节点就是节点3,但这时节点2和新节点都指向节点3,把节点2指向新节点即可。思路清晰就很简单。


六、动态创建链表&尾插法

静态创建链表还要自己一个个定义,手动建立链接,非常麻烦,而且删除节点的时候,被删除的节点无法释放内存空间,可能会造成溢出等情况,所以要动态创建链表,之前静态创建是为了方便理解一些基础操作。

/*head全局变量*/
struct test *head = NULL;

/*动态创建链表*/
struct test* createLink(struct test *head)
{
    struct test *new;
    struct test *p = head;
    while(1)
    {
        /*给新节点分配内存空间*/
        new = (struct test*)malloc(sizeof(struct test));
        
        /*用户键盘输入新节点id*/
        scanf("%d",&(new->id));
        
        /*id为0结束创建,返回头节点地址*/
        if(new->id == 0)
        {
            printf("0 quit\n");
            free(new);//释放最后建立的新节点的内存空间
            return head;
        }

        /*初始化新节点的next指针*/
        new->next = NULL;

        /*建立连接*/
        if(head == NULL)//如果头节点为NULL
        {
            /*创建头节点*/
            head = new;
        }
        else
        {
            // 遍历到最后一个节点
            p = head;
            while(p->next != NULL)
            {
                p = p->next;
            }
            // 将新节点添加到最后
            p->next = new;
        }
    }
}

使用malloc函数来为每一个新节点分配内存,如果输入的节点id为0代表结束创建,free函数释放最后建立的节点,并返回head头节点的地址。


七、头插法

struct test* insertFromHead(struct test *head)
{
    struct test *new;

    while(1)
    {
        /*和尾插法一样*/
        new = (struct test*)malloc(sizeof(struct test));
        scanf("%d",&(new->id));
        if(new->id == 0)
        {
            printf("0 quit\n");
            free(new);
            return head;
        } 

        new->next = head;
        head = new;
    }
    return head;
}

 原本我在插入节点的时候判断了head是否为空,后来发现没必要,如果不为空,直接插在头节点前面,然后更新头节点即可;如果为空,那new就是尾巴节点,new->next为NULL,这也合理,然后更新头节点。


八、删除节点

struct test* deleteNode(struct test *head, int data)
{
    struct test *p = head;
    if(p->id == data)
    {
        head = head->next;
        free(p);
        return head;
    }

    while(p->next != NULL)
    {
        if(p->next->id == data)
        {
            struct test *temp = p->next;
            /*关键操作*/
            p->next = p->next->next;
            free(temp);
            return head;
        }
        p = p->next;//遍历
    }
    return head;
}

 操作和从指定节点前方插入节点类似,判断当前p指向的节点的 next->id ,也就是下一个节点是否为要删除的节点,如果是:p->next->next 是要删除的节点的下一个,将它赋值给 p->next 就是跳过要删除的节点,要删除的节点的前一个节点指向要删除的节点的后一个节点。

至此链表的基础操作都讲完了,如果自己用画图的方式,跟着代码一步步走,手撕链表也不在话下,后面我会更新贪吃蛇小游戏,他的核心就是链表的操作,用来锻炼链表的使用能力。

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

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

相关文章

19448 算法设计与分析(第五版)习题2-7 集合划分问题

### 思路 1. **递归公式**:根据提示信息,递归公式为: - \( f(n, x) f(n-1, x-1) f(n-1, x) \times x \) - 其中,\( f(n, x) \) 表示将 \( n \) 个元素分成 \( x \) 个非空子集的方案数。 2. **边界条件**: …

【STM32】串口(异步通信部分)

经典的串口接口硬件说实话在现在的电脑上已经很难见到了,而是被USB这种通用的串行接口替代了,哪怕外部设备要以串口连接到电脑,都需要进行各种硬件转换。但不得不说,在工业领域,串口还是一个非常常用的数据传输方式。 …

LEAP模型在能源环境发展、碳排放建模预测及分析中实践应用

采用部门分析法建立的LEAP(Long Range Energy Alternatives Planning System/ Low emission analysis platform,长期能源可替代规划模型)是一种自下而上的能源-环境核算工具,由斯德哥尔摩环境研究所和美国波士顿大学联合研发。该模…

后端Web之登录校验(上篇)

目录 1.概述 2.会话技术 3.JWT令牌 1.概述 基础的登录功能实际上就是查询数据库中有没有输入的用户和密码,有就放行,没有就返回错误信息,根据三层架构进行开发: controller层: service层: mapper层&…

Visual C++ 的免费绘图库 EasyX下载安装

EasyX Graphics Library 是针对 Visual C++ 的免费绘图库,支持 VC6.0 ~ VC2022,简单易用,学习成本极低,应用领域广泛。目前已有许多大学将 EasyX 应用在教学当中。 下载地址:EasyX Graphics Library for C++ 1、应用 2、文中有很多的C++应用案例 3、编程需要的数学知识 …

19530 2的幂次方表示

### 思路 1. **分解为2的幂次方**:将输入的正整数n分解为若干个2的幂次方之和。 2. **递归表示**:使用递归的方法将每个幂次方表示为2的幂次方形式。 3. **组合结果**:将所有的幂次方表示组合成最终的结果。 ### 需要注意的点 - 需要处理幂次…

8.21 补题

六题 C 16进制世界 链接:登录—专业IT笔试面试备考平台_牛客网 来源:牛客网 题目描述 这是一个16进制的世界,比如522的16进制是20A。 在5月22日那天,有人送给Bob一些月饼,每个月饼有饱食度和幸福度两个属性。 现…

计算机网络面试真题总结(二)

文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 文章收录在网站:http://hardyfish.top/ 在浏览器中输入 URL 地址到显示主页的过程? URL解析&a…

【记录】基于Windows系统安装rust环境的过程

到官网下载安装包【入门 - Rust 程序设计语言 (rust-lang.org)】 ![[Pasted image 20240703142911.png]] 选择1,快速安装 选择编译配置,1为标准 安装完成 验证是否安装完毕 rustc --versioncargo --version验证成功!

【数据结构篇】~二叉树(堆)

【数据结构篇】~二叉树(堆) 二叉树1.树2.树的组成3.二叉树4.堆1.向上调整算法2.向下调整算法3.堆排序 4.topk问题源码 二叉树 1.树 树的概念与结构​ 树是一种非线性的数据结构,它是由 n(n>0) 个有限结点组成一个…

利用“2+1链动模式小程序AI智能名片S2B2C商城源码”优化企业参与外部社群策略

摘要:在当今数字化时代,企业参与外部社群已成为其市场扩张、品牌塑造及用户增长不可或缺的一环。然而,面对浩如烟海的社群类型,包括行业论坛、地区性论坛、特定兴趣爱好的论坛以及短视频网站等,如何精准选择并有效介入…

16.C基础_内存管理

内存分区 1、整体框图 内存分为代码区、全局区、栈区、堆区。代码区和全局区在代码编译完之后就已经确定,栈区和堆区是在程序运行时进行开辟和释放的。整体内存分区框图如下: 对于一个进程,它一共有4G的空间,其中0~3G为上述的4个…

Flask+LayUI开发手记(三):LayUI表格的后端数据分页展现

前几天写了数据表格table的前端分页展现,思路是把数据一次性取到前端,然后由前端来控制分页展现。这种做法主要目的是为了降低后端数据库读写的次数减轻服务端运行压力。但是,如果功能不单是查询还要进行增删改操作,那么一次数据提…

自制项目镜像并拉取

1.先把项目jar包拉到Linux上看能用不 mvn clean package cd target java -jar shared_battery-0.0.1-SNAPSHOT.jar 成功!!!!!!!!!!!!&…

24-8-24-读书笔记(十五)-《空谷幽兰》([法] 巴尔扎克 [译] 李玉民 )

文章目录 《空谷幽兰》([法] 巴尔扎克 [译] 李玉民 )阅读笔记记录(P112-P126)总结 《空谷幽兰》([法] 巴尔扎克 [译] 李玉民 ) 《空谷幽兰》巴尔扎克最为得意的作品,这篇主要记录一个德莫尔索夫…

SSRF漏洞实现

文章目录 SSRF题1SSRF题2fastcgi方法 入侵网站收集资产方法SSRF反弹 SSRF题1 漏洞复现平台 代码: 首先,可以用dict探测一下内网开放的端口 可以检测是否有fastcgi或者是redis,如果有fastcgi,那么就有RCE漏洞破解,如…

Adobe Animate (AN)软件安装,硬件配置(附安装包)

目录 一、Adobe An 软件简介 Adobe An 软件的特点 Adobe An 软件的优势 下载 二、Adobe An 软件安装 安装前的准备工作 安装过程中的注意事项 安装后的设置 三、Adobe An 软件使用 高级动画技巧 交互设计 优化与性能提升 四、Adobe An 软件快捷键 选择工具快捷键…

专业级推荐:2024年硬盘数据恢复软件全攻略

硬盘作为我们存储珍贵数据、工作文档、家庭照片以及个人视频的核心载体,其重要性不言而喻。然而,随着使用时间的增长或是操作不当硬盘可能会遭遇损坏。遇到这种问题我们要怎么挽救自己的数据呢,这次我就来分享下我用过的硬盘数据恢复软件。 …

基于Netty的RPC框架

RPC远程过程调用(Remote Procedure Call)是一种通信协议,它允许程序调用位于不同地址空间(通常是网络上的另一台机器)的方法,而无需程序员显式编码这个远程调用的细节。这种技术隐藏了底层的通讯细节,使得调用远程服务…

中国数据库的崛起:从本土化挑战到全球化机遇

引言 谈起中国的崛起,大家第一反应可能是“中国制造”“高铁奇迹”“电商帝国”,但今天我们要聊的,是一个比这些还要神秘的存在——中国的数据库技术。或许你平时并不会经常关注它,但这个隐身在你手机、电脑、服务器背后的无形力…