C++线性表、单链表

文章介绍了线性表、顺序表和链表的基本概念,强调了它们之间的关系和区别。顺序表是逻辑和物理地址均连续的存储方式,如数组;链表则仅要求逻辑连续,物理地址可以不连续。单链表解决了数组大小固定和插入删除复杂的问题,通过指针链接数据节点,支持动态扩展。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概述

在先说链表前,我们先来理清几个概念。

什么是线性表、顺序表和链表?三者有什么关系?

线性表:元素线性排列,在逻辑上具有次序的存储结构。

顺序表:线性表的顺序存储称为线性表。它是用一组地址连续(逻辑上连续、物理上也连续)的存储单元依次存储线性表中的数据元素。比如,数组。

链表:线性表的链式存储称为线性表。由一任意的存储单元来存储线性表中的数据元素。存储单元只是在逻辑上连续,在物理地址上可以不连续。

三者关系:顺序表和链表都是线性表,顺序表和链表的存储结构不同。

在这里插入图片描述

什么是逻辑上连续?什么又是物理上连续?

我们都知道,程序使用的数据都存放在一块存储空间中。为了便于在存储空间中查找我们存储的数据,我们会给这段存储空间进行地址编号,类似家庭住址。

物理上连续:存储地址编号相邻。这样地址不同地址,就能顺序访问所有元素。

逻辑上连续:不要求存储地址编号相邻,但要求根据前一个数据地址,能找到下一个逻辑连续的数据地址。

举个例子:

现在我们要存储A,B,C,D 。要求,依次访问A,B,C,D。

在这里插入图片描述

对于顺序存储,我们将A存放在地址为100的位置,那么B,C,D的地址就确定下来了,依次是101,102,103。这样依次访问A,B, C, D就是从编号为100的位置依次取出四个数据。

对于链式存储,我们也把A存放在地址为100的位置,由于A,B,C,D只要求逻辑上连续,不要求物理地址连续。所以我们并不能由A的地址,推出B,C,D的地址。但我们会将A,B,C,D链接起来,这样也可以实现访问A后依次访问B,C,D。

顺序表

数组是一种常用的顺序表。

你还我们当初为什么会引出数组吗?数组的提出是为了解决什么问题》

简单的说,数组可以存储大量的、相同数据类型的数组。比如,我需要记录一个10个整数的值,我们就可以创建一个大小为10的整型数组 a [ 10 ] a[10] a[10], 这个十个整型依次就是 a [ 0 ] , a [ 1 ] , a [ 2 ] . . . , a [ 9 ] a[0],a[1],a[2]...,a[9] a[0],a[1],a[2]...,a[9]

数组支持随机访问,给出元素的下标i,直接通过a[i]就可访问元素,无需从第一个元素依次遍历,直至第 i 个元素。

单链表

介绍一个我们最场使用的链表,就是单链表。

什么是单链表?单链表被提出是为了解决什么问题的?它有什么特点?

首先,我们先来看看顺序表有什么不足吧?

(1)数组大小固定。创建数组的时候,创建数组时必须给出数组的大小。

  • 现在有这么个需求,让你从读入用户输入的数字,用户输入的数字的个数在 1 − 1000 1-1000 11000 之间。为了使数组够用,我们得就会这样创建数组int a[1000]; 但你发现,大多数用户,只输了10多个数字,只有个别用户会输入1000个数字,很多时候数组都设置大了,导致有很多设置的空间都没用上,浪费了空间。如何解决?

(2)插入、删除数据复杂。每次在数组中插入或者删除数据,都要不停的移动数据,来移出或填补空位,太浪费时间了,如何解决?

你可能已经猜到了,单链表能很好得解决上面的问题。接下来,然我们来见识见识它。

什么是单链表?

还是那个问题,读入用户的输入的数字,用户输入数字的个数在1-1000之间。

我们可以这样读,每次读入一个整数,用int 型的数据变量存储。但这样就有大量的变量,如何保证这些变量的次序关系呢?

能不能用一个链条把这些变量链接起来呢,串成一个表。每次有新的输入,我们就设置个变量读入,然后加入这个表中。

在这里插入图片描述

如何将这些数据链接起来呢?想一想哪个让我们很费解的,大名鼎鼎的“指针”,它就可以。

指针,存放数据地址的一种数据。可看成,指向了数据。

在这里插入图片描述

如果想到这,那说明你已经懂了单链表70%的内容了。

单链表,就是由一个个链表结点链接而成的数据结构。

结点由两部分组成,存放数据的数据域,和用来链接表的指针域

在这里插入图片描述

结点类型的描述如下:

// 链表结点
struct LNode{
    DataType data;		// 存放数据
    struct LNode *next;	// 指向下一个链表结点
};

对于任意一个非空结点node,我们知道它存放的数据为node.data或node->data ,它的下一个结点为nextnode = node.next或nextnode = node->next

对于ABCD存放结构图如下:

在这里插入图片描述

查找C,得先依次访问A、B

单链表的特点

每个结点只能访问到它的下一个结点,所以结点只能一个接一个依次访问,不支持随机访问,单链表的查找速度变慢了。

每次插入数据,只需创建一个新结点,然后调节结点的next指针,就实现了插入。

比如,在BC间插入个E。

在这里插入图片描述

特殊的,对于链表的尾结点(最后一个结点),指针的指向?

链表尾结点的next指针指向空(NULL)

这样,当遍历到的结点的next指针为空时,我们就知道此时已经遍历到链表的尾结点了,即链表已经遍历完了。

上面我们提到了尾结点,你可能会提出那有没有首结点呢?

有,我们一般称为头结点

上面的A结点是不是就是头结点呢?

一般,我们认为头结点是不存放数据,所以A我们不认为是头结点。那头结点有什么用?

可以存放链表的长度,即链表的结点个数。当然,也可以什么元素都不存。但头结点,一定有个指针指向链表中第一个存放数据的结点。

添加头结点后的链表。

在这里插入图片描述

对于一个链表,头结点为head。如果head->next == NULL 说明链表为空链表。因为该链表没有存放数据的结点。

其实,头结点还有很多好处,他会让很多的操作统一,减小很多特殊判断。不展开说了。如果你发现链表操作需要很多特判,想想是否可以加一个头结点。

顺序表和链表的比较

在这里插入图片描述

总结

这里具体的单链表的插入、删除、查找操作都没讲。其实,如果能理解单链表这个结构,对于这些基本操作还是很简单的。

单链表是一种常用的一种基本数据结构,重点就是理清楚结点指针

双链表、循环链表和循环双链表这里没提,其实先搞懂单链表,之后的其他特殊链表都很好理解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值