当前位置: 首页 > news >正文

【数据结构】单链表的基本操作(节点建立、插入删除)

  • 1. 单链表的基本操作
    • 1.1. 链表的定义
    • 1.2. 链表的创建(初始化)
      • 1.2.1. 不带头结点的链表
      • 1.2.2. 带头结点的链表
    • 1.3. 链表的插入和删除
      • 1.3.1. 按位序插入
        • 1.3.1.1. 带头结点
        • 1.3.1.2. 不带头结点
      • 1.3.2. 指定节点的后插操作
      • 1.3.3. 指定元素的前插操作
      • 1.3.4. 按位序删除
        • 1.3.4.1. 带头结点
        • 1.3.4.2. 不带头结点
      • 1.3.5. 指定元素的删除操作

1. 单链表的基本操作

链表是一种基本的数据结构,在很多数据结构中都会使用链表的方式进行建立,所以将链表学会学通透很有必要。

1.1. 链表的定义

链表的定义是基于结构体之上的,一个链表一般需要定义两方面的东西,一个是链表的节点,一个是链表的指针。一个链表的定义示例如下:

typedef struct ListNode {int data;struct ListNode *next;
}LNode,*List;

上述代码中的val是数据域,用来存放数据,next是指针域,用来存放下一个节点的地址。
并且该代码采用了typedef定义了一个别名LNode,用来指代链表的节点,List是链表的指针,用来指向链表的第一个节点。

1.2. 链表的创建(初始化)

链表的创建有两种方式,一种是带头结点的,另一种是不带头节点的。

1.2.1. 不带头结点的链表

不带头结点的链表的创建方式如下:

void InitList(List *L)
{L=NULL;
}

即使得链表的下一个节点为空。

1.2.2. 带头结点的链表

带头结点的链表的创建方式如下:

void InitList(List *L)
{L=(List)malloc(sizeof(LNode));if(L==NULL){return ;//此时表示创建头结点失败}L->next=NULL;//头结点指向的下一个节点为空
}

头结点的好处就在于,当我们需要对链表进行一个操作的时候,不需要专门对链表的第一个节点进行特殊操作,我们只需要对所有的代码编写一个固定的函数,通过传递不同的值就可以实现特定高度功能。

1.3. 链表的插入和删除

1.3.1. 按位序插入

1.3.1.1. 带头结点

链表的插入,需要先找到要插入位置的前后节点,然后创建一个指针,使得前一个节点指向这个指针,这个指针再指向下一个节点。

在按位序插入的过程中,我们需要输入链表的头结点(供遍历寻找目标位置),要插入的位置和元素。
示例代码如下:

bool ListInsert(List *L,int i,int e)
{if(i<1){return false;}LNode *p; //p表示当前指向的是哪个节点int j=0; //j表示的是当前指向节点的位置p=L; //目前先让p指向头节点while(p!=NULL&&j<i-1) //循环找到要插入节点的前一个节点{p=p->next;j++;}LNode *s=(LNode *)malloc(sizeof(LNode));s.data=e;s->next=p->next;p->next=s;return true;
}
1.3.1.2. 不带头结点

不带头结点的插入与带头结点的插入类似,但是相对带头节点来说更加繁琐。

bool ListInsert(List *L,int i,int e)
{if(i<1){return false;}if(i==1){LNode *q=(LNode *)malloc(sizeof(LNode));q->data=e;q->next=L;L=q;}LNode *p; //p表示当前指向的是哪个节点int j=0; //j表示的是当前指向节点的位置p=L; //目前先让p指向头节点while(p!=NULL&&j<i-1) //循环找到要插入节点的前一个节点{p=p->next;j++;}LNode *s=(LNode *)malloc(sizeof(LNode));s.data=e;s->next=p->next;p->next=s;return true;
}

同样传入的是第一个节点的地址,要加入节点的位置和要加入的元素,区别就在于加入要在第一个位置插入元素,就需要特别处理一下。

1.3.2. 指定节点的后插操作

在给定节点后插入节点的操作相对简单,示例代码如下:

bool InsertNextNode(LNode *p,int x)
{if(p==NULL){return false;}LNode *s=(LNode *)malloc(sizeof(LNode));s->next=p->next;p->next=s;s=>data=x;return true;
}

1.3.3. 指定元素的前插操作

在指定元素之前要插入一个元素,最容易想到的办法是将整个链表遍历一遍,之后找到这个元素的前驱节点,转换成后插操作。但是这种办法实现起来较为复杂,所以我们转换一种思维方式,采取新的方法。

我们尝试在指定节点之后先插入一个节点,然后把指定节点的值赋给新节点,之后再把要插入的值赋给旧节点。总而言之就是现在之后插入节点,然后把两个节点的值互换,就相当于将前后节点互换了。示例代码如下:

bool InsertPriorNode(LNode *p,int x)
{if(p==NULL){return false;}LNode *s=(LNode *)malloc(sizeof(LNode));s->next=p->next;p->next=s;s->data=p->data;p->data=x;return true;
}

1.3.4. 按位序删除

1.3.4.1. 带头结点

在带头结点的删除节点操作中,我们需要给函数传递链表的第一个节点的位置,要删除的位置和一个变量用来存储删除节点的元素值。

删除的主要操作是创建一个指针(不分配内存空间)指向要删除的节点,然后让要删除指针前一个节点指向要删除指针的后一个节点,然后将要删除的指针释放内存,从而达到目的。

示例代码如下:

bool ListDelete(List L,int i,int x)
{if(i<1){return false;}LNode *p;int j=0;p=L;while(p!=NULL;j<i-1){p=p->next;j++;}if(p==NULL){return false;}if(p->next==NULL){return false;}LNode *q=p->next;x=q->data;p->next=q->next;free(q);
}
1.3.4.2. 不带头结点

与不带头结点的插入类似,这里不再赘述。

1.3.5. 指定元素的删除操作

删除操作和带头结点的的相似,指定元素和指定元素的插入相似,这里不再赘述!

http://www.lryc.cn/news/178158.html

相关文章:

  • DEM格式转换:转换NSDTF-DEM国标数据格式为通用格式,使用ArcGIS工具转换NSDTF-DEM国标.dem文件为通用.tif格式。
  • 施耐德电气:勾勒未来工业愿景,赋能中国市场
  • 安防监控产品经营商城小程序的作用是什么
  • php中判断指定字符串是否包含指定字符的封装函数
  • GICI-LIB源码阅读(三)因子图优化模型
  • 5、Docker安装mysql主从复制与redis集群
  • 【AI视野·今日NLP 自然语言处理论文速览 第四十三期】Thu, 28 Sep 2023
  • Unity 制作登录功能01-创建登录的UI并获取输入内容
  • 什么是用户画像?
  • DevExpress WinForms图表组件 - 直观的数据信息呈现方式!(二)
  • 基于AIOps实现智慧园区极简IT运维
  • chatgpt 只会死记硬背吗
  • 03-Zookeeper客户端使用
  • 自然语言处理(NLP)学习之与HanLP的初相识
  • JDBC【DBUtils】
  • 大数据Doris(一):Doris概述篇
  • vue 基于vue-seamless-scroll无缝滚动的用法和遇到的问题解决
  • SmartX 边缘计算解决方案:简单稳定,支持各类应用负载
  • FPGA 多路视频处理:图像缩放+视频拼接显示,HDMI采集,提供2套工程源码和技术支持
  • 【数据结构】抽象数据类型
  • Android 查看路由表
  • vulnhub靶机-DC系列-DC-3
  • 【CTFHUB】SSRF原理之简单运用(一)
  • wepack打包生产环境使用http-proxy-middleware做api代理转发的方法
  • 一百八十六、大数据离线数仓完整流程——步骤五、在Hive的DWS层建动态分区表并动态加载数据
  • Idea引入thymeleaf失败解决方法
  • Dev C++安装与运行
  • Docker下如何构建包含延迟插件的RabbitMQ镜像
  • Vue3理解(6)
  • react+IntersectionObserver实现页面丝滑帧动画