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

本文主要是介绍链表(静态/动态创建,遍历,计数,查找,在节点的前/后方插入新节点,头插法,尾插法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、前言

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

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

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

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

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

七、头插法

八、删除节点


一、前言

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

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


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

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

我们遍历数组时,要把数组的所有元素都打印出来,一个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);//打印每个节点的idhead = 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指向指定节点的nexthead->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.chinasem.cn/article/1104896

相关文章

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

csu1329(双向链表)

题意:给n个盒子,编号为1到n,四个操作:1、将x盒子移到y的左边;2、将x盒子移到y的右边;3、交换x和y盒子的位置;4、将所有的盒子反过来放。 思路分析:用双向链表解决。每个操作的时间复杂度为O(1),用数组来模拟链表,下面的代码是参考刘老师的标程写的。 代码如下: #include<iostream>#include<algorithm>#include<stdio.h>#

day-51 合并零之间的节点

思路 直接遍历链表即可,遇到val=0跳过,val非零则加在一起,最后返回即可 解题过程 返回链表可以有头结点,方便插入,返回head.next Code /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}*

深入手撕链表

链表 分类概念单链表增尾插头插插入 删尾删头删删除 查完整实现带头不带头 双向链表初始化增尾插头插插入 删查完整代码 数组 分类 #mermaid-svg-qKD178fTiiaYeKjl {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-

顺序表之创建,判满,插入,输出

文章目录 🍊自我介绍🍊创建一个空的顺序表,为结构体在堆区分配空间🍊插入数据🍊输出数据🍊判断顺序表是否满了,满了返回值1,否则返回0🍊main函数 你的点赞评论就是对博主最大的鼓励 当然喜欢的小伙伴可以:点赞+关注+评论+收藏(一键四连)哦~ 🍊自我介绍   Hello,大家好,我是小珑也要变强(也是小珑),我是易编程·终身成长社群的一名“创始团队·嘉宾”

建立升序链表

题目1181:遍历链表 时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:2744 解决:1186 题目描述: 建立一个升序链表并遍历输出。 输入: 输入的每个案例中第一行包括1个整数:n(1<=n<=1000),接下来的一行包括n个整数。 输出: 可能有多组测试数据,对于每组数据, 将n个整数建立升序链表,之后遍历链表并输出。 样例输

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

Thymeleaf:生成静态文件及异常处理java.lang.NoClassDefFoundError: ognl/PropertyAccessor

我们需要引入包: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>sp

leetcode105 从前序与中序遍历序列构造二叉树

根据一棵树的前序遍历与中序遍历构造二叉树。 注意: 你可以假设树中没有重复的元素。 例如,给出 前序遍历 preorder = [3,9,20,15,7]中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树: 3/ \9 20/ \15 7   class Solution {public TreeNode buildTree(int[] pr

学习记录:js算法(二十八):删除排序链表中的重复元素、删除排序链表中的重复元素II

文章目录 删除排序链表中的重复元素我的思路解法一:循环解法二:递归 网上思路 删除排序链表中的重复元素 II我的思路网上思路 总结 删除排序链表中的重复元素 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 图一 图二 示例 1:(图一)输入:head = [1,1,2]输出:[1,2]示例 2:(图