《数据结构(刘大有)》学习(2)

系列文章目录

一、绪论

二、线性表


文章目录


线性表的定义和基本操作

        一个线性表是由0个或多个具有相同类型的结点组成的有序集合

        用[a_1,a_2,a_3,...,a_n]表示线性表,n=0时,线性表为空表;n≥1时,a_1称为表头a_n表尾。n≥2时,a_ia_{i+1}前驱结点a_{i+1}a_i后继结点。表头无前驱结点,表尾无后继结点。若线性表中的结点是按值(或按关键字值)由小到大(或者由大到小)排列的,则称线性表是有序

  • 线性表可以是单值的:人工智能学院某学科某学年期末考试成绩,按照学号的顺序成绩依次是: 85, 87, 89, 90, 85, ……, 87, 94, 88
  • 线性表也可以是记录型的:某校2020级同学的基本情况:{(‘2020414101’,‘张里户’,‘男’,06/24/2003), (‘2020414102’,‘张化司’,‘男’,08/12/2004) …, (‘2020414102’,‘李利辣’,‘女’,08/12/2003) }

       线性表的基本操作:

  •  创建一个线性表
  • 确定线性表的长度
  • 判断线性表是否为空
  • 在线性表中第k个结点后插入一个新结点(增)
  • 删除线性表中第k个结点(删)
  • 存取线性表中第k个结点的字段值(改)
  • 查找指定字段值在线性表中的位置(查)
  • 归并、分拆、复制、排序…...

线性表的存储结构

线性表的顺序存储结构

顺序存储:按逻辑顺序将线性表的结点依次存放在一组地址连续的字节中

顺序存储的线性表也被称为顺序表,若其中元素有序,则称其为有序顺序表

顺序表特点:逻辑顺序和物理顺序相同

对于顺序结构,结点的物理地址可以由数学公式算出

b是表头地址,c为存储结点所需字节数

顺序表的插入操作

插入数据的基本操作

  1. 判断插入数据是否合法
  2. 将顺序表L中的第k个至第n个结点后移一个位置
  3. 将结点item插入到结点a_{k-1}
  4. 顺序表长度加1

时间复杂度

  • 插入操作的基本运算是元素移动
  • 长度为n的线性表有n+1中插入可能
  • 设插入合法且插入各位置的概率相同:1/(n+1)

则时间复杂度期望为:

顺序表的删除操作

删除数据的基本操作

  1. 判断删除结点是否合法
  2. 将顺序表L中的第k+1个至第n个结点向前移动一个位置
  3. 顺序表长度减一

时间复杂度

  • 删除操作的基本运算是元素移动
  • 长度为n的线性表有n中删除可能
  • 设删除合法且插入各位置的概率相同:1/(n+1)

则时间复杂度期望为:

顺序表优缺点

优点

  • 空间利用率高
  • 简单、易于实现
  • 存取速度快

缺点:

  • 插入和删除结点时间复杂度高

线性表的数目可以改变,定义数组时需定义足够大的静态数组(可能空间利用率低)或者使用动态数组


线性表的链接存储结构

链式存储:用一组任意的存储单元存储线性表中的数据元素。用这种方法存储的线性表称为线性链表

链表中结点的逻辑顺序和物理顺序不一定相同。存储链表中结点的一组任意的存储单元可以是连续的,也可以是不连续的,甚至是零散分布在内存中的任意位置上的。

分类

  • 单链表
  • 循环链表
  • 双链表

单链表

一个单链表结点由以下两个域构成:

  • 链表的第一个结点被称为头节点表头),指向头节点的指针被称为头指针head
  • 链表的最后一个结点被称为尾结点表尾),指向尾结点的指针(如果有)被称为尾指针(tail),验证一个结点是否为尾结点,只需考察该结点的next域是否为NULL
n个元素组成的线性链表
  • 逻辑顺序与物理顺序可以相同也可不同,即逻辑上相邻的结点与物理上不必相邻

单链表插入结点

  • 在单链表中,插入一个结点,只需改变一个或两个相关结点的指针域,不对其它结点产生影响
  • 插入操作:在结点 p 之后插入结点 s,next(s) ← next(p)   next(p) ← s

单链表删除结点

  • 在单链表中,删除一个结点,只需改变一个或两个相关结点的指针域,不对其它结点产生影响
  • 删除操作:在结点 p 之后删除结点 q,q ← next (p).  next (p) ← next (q) .  

哨兵结点

在插入和删除结点时,若我们的操作对象是表头,则需要修改头指针,令其指向新结顶,此时我们可以引入哨兵结点

哨兵结点与其他结点相同,也是由数据域和指针域构成,但数据域没有被赋值指针域存储指向第一个真正结点的指针,即头节点

哨兵结点不被看作表中实际结点

单链表查找结点

  • 在单链表中,在单链表中,查找一个结点,只能头结点开始比对,找到才返回

时间复杂度(增删查)

  • 最好情况下时间复杂度为O(1)
  • 最坏情况下时间复杂性度为O(n)
  • 平均情况下是O(n)

\frac{0+1+...+n+n+1}{n+2}=\frac{1}{n+2}\frac{(n+1)(n+2)}{2}=\frac{n+1}{2}=O(n)

单链表综述

单链表的特性:

  • 利用链接域实现线性表元素的逻辑关系
  • 单链表有头结点、尾结点、头指针

单链表的优点:

  • 插入、删除方便
  • 共享空间好,结点可以不连续存储,易于扩充

单链表的不足:

  • 单链表虽然克服了顺序存储的缺点,但却不能进行随机访问
  • 对单链表来说,只有从头结点开始才能扫描链表中的全部结点
  • 从一个结点出发,只能访问到链接在它后面的结点,而无法访问位于它前面的结点


循环链表

  • 把链表结构“循环化”,即让表尾结点的next域存放指向哨位结点的指针,而不是存放空指针NULL,这样的链表称为循环链表
  • 循环链表的指针域接成一个环
  • 循环链表使我们可以从链表任何位置开始,访问链表中的任一结点

  • 判断空表的条件:next(head) = head
  • 判断表尾的条件:next (p) = head
  •  在循环链表中访问某结点p的前驱结点,需遍历整个链表,其时间复杂性为O(n).

循环链表本质就是将单链表进行改造,因此其增删查的操作与单链表相同


双向链表

所谓双向链表(Double-Linked List),指链表中任一结点P都是由data域、左指针域left和右指针域right构成的,左指针域和右指针域分别存放P的左右两边相邻结点的地址信息,链表中表头结点的left指针和表尾结点的right指针均为NULL. 指针head和tail分别指向双向链表的头结点和尾结点,双向链表也被称为双重链表

双向链表特点

  • 每个结点有两个指针域left和right
  • 左指针指向其前驱结点,右指针指向其后继结点
  • 头结点和尾结点的指针域特殊

优点:

  • 方便查找某个结点的前驱结点

双向链表插入结点

在s之后插入结点p

  • left(right(s)) ← p
  • right(p) ← right(s)
  • left(p) ← s
  • right(s) ← p

双向链表删除结点

删除s结点

  • right(left(s)) ← right(s)
  • left(right(s)) ← left(s) 


各链表使用场景

  • 链表的头结点和尾结点使用频繁:带尾指针的循环链表
  • 经常查找结点的前驱和后继的场合:双向链表
  • 结合循环链表和双向链表的特点,构造双向循环链表

ps:删除链表结点时,记得释放删除结点的存储空间,python等语言会自动释放,但C和C++不会

  • 18
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值