数据结构:线性表的链式表示

目录

基本组成

链表的类型

主要操作

初始化:

带头结点

不带头结点

插入操作

删除操作:

查找操作:

求表长:

建立单链表:

头插法:

尾插法:

双链表:

查找操作

插入操作:

删除操作:

详细解释(插入和删除):

插入操作的时间复杂度为O(1):

删除操作的时间复杂度为O(1):

注意事项:

优缺点


线性表的链式表示,又称为链式存储结构或链式映像,是一种常见且灵活的数据结构表示方式。它使用指针(或链)将一组数据元素按照其逻辑顺序连接起来,而不需要这些元素在物理位置上连续存储。这种表示方式特别适用于需要频繁进行插入和删除操作的场景。

基本组成

线性表的链式表示的基本单位是节点(Node),每个节点通常包含两部分信息:

  • 数据域:用于存放数据元素本身的信息。
  • 指针域:用于存放指向下一个节点的指针(或链),以表示数据元素之间的逻辑关系。

链表的起始节点称为头节点,尾节点的指针域为空(或指向一个特殊的结束标记,这取决于链表的具体实现方式)。

链表的类型

根据节点指针的指向和链表的结构,链表可以分为多种类型,其中最常见的是单链表循环链表

  • 单链表:每个节点只有一个指针域,指向下一个节点。单链表的最后一个节点的指针域为空。
  • 循环链表:在单链表的基础上,将最后一个节点的指针域指向头节点,形成一个闭环。循环链表可以是单向的,也可以是双向的(即每个节点有两个指针域,分别指向前一个和后一个节点)。
  1. 循环单链表:若设的是头指针,对在表尾插入元素需要O(n),若设的是尾指针r,r->next就是头指针,对在表头插入和表尾插入元素都只要O(1)。
  2. 循环双链表

主要操作

线性表的链式表示提供了多种操作,包括但不限于:

初始化:
带头结点

先创建一个头结点,让头指针指向头结点,头结点的next域初始化为null

//initialize
bool initList(LinkList &L){L=(LNode*)malloc(sizeof(LNode));//创建头结点,由系统生成一个LNode型的结点,并将该结点的起始位置赋给L(L就是头指针)L->next=NULL;//此时表为空 头结点的指针域为空return true;}
不带头结点

只需将头指针初始化为null

bool initList(LinkList &L){L=NULL;return true;
}
插入操作

在链表的任意位置插入一个新节点,而不需要移动其他节点,时间复杂度通常为O(1)(如果已知插入位置的前驱节点)。

//insert
bool insertList(LinkList &L,int i,ElemType e){LNode *p=L;int j=0;while(p->next!=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;
}
删除操作

从链表中删除一个节点,同样不需要移动其他节点,时间复杂度也为O(1)(如果已知要删除节点的位置或其前驱节点的位置)。

//delete
bool deleteList(LinkList &L,int i,ElemType &e){LNode *p=L;int j=0;while(p->next!=NULL&&j<i-1){p=p->next;j++;}if(p==NULL||p->next==NULL)return false;LNode *q=p->next;e=q->data;p->next=q->next;free(q);return true;}

时间复杂度:O(n) 

查找操作

通过遍历链表来查找指定元素

按序号:

//get
LNode *getelem(LinkList L,int i){
LNode *p=L;
int j=0;
while(p->next&&j<i){p=p->next;j++
}
return p;
}

按值:

//getbyvalue
LNode *getelem(LinkList L,Elemtype e){LNode *p=L;while(p->next){if(p->data==e)return p;elsep=p->next;}return p;
}

时间复杂度:都为O(n),其中n是链表中节点的数量。

求表长

从头节点开始,沿着指针逐个节点遍历,直到遍历完整个链表。

//length
int Length(LinkList L){int len=0;LNode *p=L;while(p->next!=NULL){p=p->next;len++;}return len;
}

时间复杂度:O(n)

建立单链表:
头插法:
//create
LinkList List_headInsert(LinkList &L){LNode *s;int x;L=(LNode*)malloc(sizeof(LNode));L->next=NULL;scanf("%d",&x);while(x!=9999){s=(LNode*)malloc(sizeof(LNode));s->data=x;s->next=L->next;L->next=s;scanf("%d",&x);}return L;
}
尾插法:
//create
LinkList List_tailInsert(LinkList &L){int x;l=(LNode*)malloc(sizeof(LNode));LNode *s,*r=L;scanf("%d",&x)while(x!=9999){s=(LNode*)malloc(sizeof(LNode));s->data=x;r->next=s;r=s;scanf("%d",&x);}r->next=NULL;return L;}

时间复杂度:O(n)

双链表:

查找操作

和单链表一样

插入操作:
//doubleline insert
s->next=p->next;
p->next->prior=s;
s->prior=p;
p->next=s;
删除操作:
//doubleline delete
p->next=q->next;
q->next->prior=p;
free(q);

时间复杂度:O(1) 因为可以很方便的查找到节点的前驱 

详细解释(插入和删除):
插入操作的时间复杂度为O(1):

在双链表中插入一个节点,如果已知插入位置的前驱节点或后继节点,则插入操作可以在常数时间内完成。具体步骤如下:

  1. 调整指针:首先,将新节点的prev指针指向插入位置的前驱节点,将新节点的next指针指向插入位置的后继节点。
  2. 更新前驱和后继节点的指针:然后,如果前驱节点存在,则更新其next指针指向新节点;如果后继节点存在,则更新其prev指针指向新节点。

由于这些操作仅涉及指针的重新赋值,不依赖于链表中元素的数量,因此时间复杂度为O(1)。

删除操作的时间复杂度为O(1):

同样地,在双链表中删除一个节点,如果已知待删除节点的前驱节点或后继节点,则删除操作也可以在常数时间内完成。具体步骤如下:

  1. 保存待删除节点的后继节点(如果需要):首先,如果需要访问被删除节点的数据,可以将其后继节点的数据(如果存在)保存在临时变量中。

  2. 调整指针:然后,将待删除节点的前驱节点的next指针指向待删除节点的后继节点,将待删除节点的后继节点的prev指针指向待删除节点的前驱节点(如果前驱和后继节点都存在的话)。

  3. 释放内存(在动态分配内存的情况下):最后,释放待删除节点所占用的内存空间。

这些操作同样只涉及指针的重新赋值和可能的内存释放,不依赖于链表中元素的数量,因此时间复杂度也为O(1)。

注意事项:

需要注意的是,上述O(1)的时间复杂度是基于已知插入或删除位置的前驱节点或后继节点的前提下的。如果只知道待插入或删除节点的值或序号,则需要先遍历链表找到该节点及其前驱节点或后继节点,此时时间复杂度将变为O(n),其中n是链表的长度。

综上所述,双链表插入和删除的时间复杂度为O(1),这主要得益于其双向链接的结构特性和操作方式。

综上所述,线性表的链式表示是一种灵活且高效的数据结构表示方式,特别适用于需要频繁进行插入和删除操作的场景。然而,在选择使用链表时,也需要根据具体的应用场景和需求来权衡其优缺点。

优缺点

优点

  • 插入和删除操作效率高,因为只需要修改指针,而不需要移动数据元素。
  • 不需要预先分配固定大小的存储空间,可以根据需要动态地申请和释放存储空间。

缺点

  • 访问链表中的元素需要从头节点开始遍历,因此随机访问的效率较低。
  • 每个节点都需要额外的指针域来存储指针信息,这会增加一定的存储开销。

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

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

相关文章

【自动驾驶】对2D框的四条边同时缩进

对【自动驾驶】随机缩进2D框的一条边-CSDN博客进行补充。 所以这里直接进入正题&#xff0c;怎么做才能对每条边进行缩进&#xff1f; 待补充。

QT学习笔记之绘图

或许有人会等你到天黑&#xff0c;但是你不该在天黑后再找他&#xff08;她&#xff09;。 1.绘图事件 在ui文件中添加一个按钮&#xff0c;同时在资源文件中添加一个名字为1.jpg的图片。 widget.cpp #include "widget.h" #include "ui_widget.h" #incl…

这条挣钱的路,离我好遥远啊

近日&#xff0c;笔者在发表的《乱篇弹&#xff08;54&#xff09;让子弹飞》一文中写道&#xff1a;“ 当然&#xff0c;笔者在《博客中国-狼头长啸的作家专栏》耕耘期间&#xff0c;也赚了一些用以补贴自己养老的‘ 散碎银两’。那么笔者是否可以依照知乎网的‘申请开通权限’…

支付宝远程收款跳转码接口api之工作证跳转收款码

1、在制作工作证跳转收款之前需要在支付宝上开通工作证 2、然后获取支付宝账户信息、收款码等信息 3、将所需信息填入如下代码之中 const axios require(axios); const authCode 从客户端接收到的授权码;axios({method: post,url: https://openapi.alipay.com/alipay.syst…

SpringCloud入门(八)Feign自定义配置

一、Feign自定义配置 Feign可以支持很多的自定义配置&#xff0c;如下表所示&#xff1a; - 类型&#xff1a; feign.Logger.Level 作用 &#xff1a;修改日志级别 说明 &#xff1a; 包含四种不同的级别&#xff1a;NONE、BASIC、HEADERS、FULL - 类型&a…

用通义灵码如何快速合理解决遗留代码问题?

本文首先介绍了遗留代码的概念&#xff0c;并对遗留代码进行了分类。针对不同类型的遗留代码&#xff0c;提供了相应的处理策略。此外&#xff0c;本文重点介绍了通义灵码在维护遗留代码过程中能提供哪些支持。 什么是遗留代码 与过时技术相关的代码&#xff1a; 与不再受支持的…

Python如何配置环境变量详解

一、概述 前提&#xff1a;已安装 Python&#xff0c;如下图&#xff1a; 1.1 检查是否已配置成功&#xff08;选&#xff09; 1 2 3 4 5 1. 打开运行窗口 (1) 快捷键 : Win r&#xff0c;并输入 cmd (2) 直接输入: Python 2. 若有下列提示&#xff0c;即为 安装成功…

星辰计划04-深入理解kafka的消息存储和索引设计

消息存储 提到存储不得不说消息的读写&#xff0c;那么kafka他是如何读写数据的呢&#xff1f; 读取消息 1.通过debug(如何debug) 我们可以得到下面的调用栈&#xff0c;最终通过FileRecords来读取保存的数据 写入消息 1.通过debug(如何debug) 我们可以得到下面的调用栈&am…

【HTTP 和 HTTPS详解】3

HTTP 状态代码 HTTP 状态代码是服务器发送给客户端的三位数字&#xff0c;用于指示客户端请求的结果。它们分为五类&#xff1a;信息性&#xff08;100-199&#xff09;、成功&#xff08;200-299&#xff09;、重定向&#xff08;300-399&#xff09;、客户端错误&#xff08…

怎么不用付费直接编辑pdf?5款pdf在线编辑器免费推荐给你!

在我们日常工作中&#xff0c;可能会经常需要直接编辑修改pdf内容&#xff0c;例如&#xff0c;在将文档发送给其它人之前&#xff0c;您可能需要进行一些修改&#xff1b;或者当扫描的文本出现错误时&#xff0c;您也需要进行修正。此时&#xff0c;如果有一款在线编辑器&…

【C++笔记】初始模版和STL简介

【C笔记】初始模版和STL简介 &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;C笔记 文章目录 【C笔记】初始模版和STL简介前言一.初始模版1.1泛型编程1.2函数模版1.3类模板 二.STL简介2.1什么是STL2.2STL的版本2.3STL的六大组件2.4STL的重要…

Vue项目之Element-UI(Breadcrumb)动态面包屑效果 el-breadcrumb

效果预览 需要导航的页面Vue.js 最笨的方法就是在每个需要面包屑的页面中固定写好 <template><div class="example-container"><el-breadcrumb separator="/"

Tableau数据可视化入门

目录 一、实验名称 二、实验目的 三、实验原理 四、实验环境 五、实验步骤 1、Tableau界面引导 2、数据来源 3、数据预处理操作 4、制作中国各个地区的利润图表 4.1条形图 4.2气泡图 5、制作填充地球图 一、实验名称&#xff1a; 实验一&#xff1a;Tableau数据可视…

vue使用indexedDB缓存教程

1.前端缓存几种方式: cookie、localStorage、sessionStorage、indexedDB&#xff0c;下面详细介绍indexedDB 2.完整代码 class DBManager {dbName: any null;version: any null;db: any null;/*** 初始化数据库名、版本* param dbName* param version*/constructor(dbName…

在C#中使用JSON

JSON简介 1. 什么是 JSON&#xff1f; JSON&#xff08;JavaScript Object Notation&#xff09;是一种轻量级的数据交换格式。它的语法基于 JavaScript 对象表示法&#xff0c;简单、易读&#xff0c;同时被许多编程语言支持。尽管它来源于 JavaScript&#xff0c;但它并不依…

RTE大会报名丨 重塑语音交互:音频技术和 Voice AI,RTE2024 技术专场第一弹!

Voice AI 实现 human-like 的最后一步是什么&#xff1f; AI 视频爆炸增长&#xff0c;新一代编解码技术将面临何种挑战&#xff1f; 当大模型进化到实时多模态&#xff0c;又将诞生什么样的新场景和玩法&#xff1f; 所有 AI Infra 都在探寻规格和性能的最佳平衡&#xff0…

美畅物联丨GB/T 28181系列之TCP/UDP被动模式和TCP主动模式

GB/T 28181《安全防范视频监控联网系统信息传输、交换、控制技术要求》作为我国安防领域的重要标准&#xff0c;为视频监控系统的建设提供了全面的技术指导和规范。该标准详细规定了视频监控系统的信息传输、交换和控制技术要求&#xff0c;在视频流传输方面&#xff0c;GB/T 2…

大厂面试真题:简单说下Redis的bigkey

什么是bigkey bigkey是指key对应的value所占的内存空间比较大&#xff0c;例如一个字符串类型的value可以最大存到512MB&#xff0c;一个列表类型的value最多可以存储23-1个元素。 如果按照数据结构来细分的话&#xff0c;一般分为字符串类型bigkey和非字符串类型bigkey。 字…

考研数据结构——C语言实现插入排序

插入排序是一种简单直观的比较排序算法&#xff0c;它的工作原理是通过构建有序序列&#xff0c;对于未排序数据&#xff0c;在已排序序列中从后向前扫描&#xff0c;找到相应位置并插入。插入排序在实现上&#xff0c;通常采用in-place&#xff08;原地排序&#xff09;&#…

ceph rgw 桶分片之reshard

Ceph RGW&#xff08;RADOS Gateway&#xff09;的 reshard 功能是用来动态调整对象存储的分片&#xff08;shard&#xff09;数量&#xff0c;从而优化性能和存储利用率。随着数据量的增加&#xff0c;初始的分片设置可能无法满足性能需求&#xff0c;因此 reshard 功能允许用…