《考研408数据结构》第二章《线性表(顺序表、链表)》复习笔记
前提提要:
因为数据结构我个人大一学过,而且我也一直认为是408里最简单的,所以我一直拖到很晚才开,视频也没看,直接加速用【思维导图】+【例题】极限回顾复习,因此我也默认大部分人都是很早就学完了数据结构,所以该数据结构系列笔记只适用于非初学者的框架回顾复习,不再解释简单知识点概念。
;
【另外】
这里需要强调一下,顺序表将是数据结构代码大题的重点!!!
而且难度比较大,频率比较高,往深了考的
那么会在文章最结尾会写一部分代码
那链表这块,貌似近几年考得较少,而且不会问复杂度太高的题,所以掌握基本的创建、初始化、头插尾插、双指针......这些基础的代码就行,都是套路,理解概念之后就可以直接背诵了
一、线性表基本概念
1、知识点
图片请点击放大查看,或保存在自己电脑用PPT打开看
;
基本线性表专业术语解释:
;
;
额外知识点
- 1、那几个基本操作根本就不用背,首先你是考研的如果这几个单词翻译不出来就废了,其次我们可以根据括号后面的参数来猜出这个操作
- 比如:GetElem(L, i),它是获取元素,传参传了L这个表、索引下标i,说明要在L表里根据下标i找到这个位置的元素的值
- 2、有的参数是【&】这样的,这是C++语言,我本人没学过C++所以了解一下,这其实就等于该函数有return返回值!!!
- 在C++里你可以写一个void无返回值类函数,但是当你用了&之后,这个参数在函数里最后的结果值,仍会被带回调用这个函数的 “父函数位置” ,不知道各位能否理解
2、例题
二、线性表之【顺序表】
1、概念知识点
图片请点击放大查看,或保存在自己电脑用PPT打开看
【静态分配】
- 就是数组长度固定了
【动态分配】
- 就是利用指针动态让数组长度可变,原理是每次都开辟更大的空间,把原数组复制到新的大空间里
然后最后把顺序表的优点缺点记一下:
就是把它当成数组,数组的特点就是【查找快(改值也快)】、【增、删慢】,我也懒得解释了,我觉得大学写过代码的自己应该有这个感悟
2、基本操作知识点
(1)【增删】
- 增删的最好情况都是在数组最尾加一个、减一个,那么只用执行一次,O(1)
- 增删最坏情况就是在数组头加一个、减一个,就是O(n)
- 那么【增】是整个数组所有元素[0~n-1]位全都要移动(向后or向前)一位,那么要执行n次,也就是O(n)
- 那么【减】是数组[1~n-1]位全都要移动(向后or向前)一位,那么要执行n-1次,也是O(n)
- 平均情况,你也甭算了,你就记着跟最坏情况差不多,最后都是O(n)就完事了
- 你要非要算,那【增】就是因为 [插入到第一位i=1 ~ 插到最后一位i=n+1] 的概率一样,那就是p=1/n+1,那在推算一下插入到每一位要循环几次*p,就是平均概率,最后还是O(n)
- 你要非要算,那【减】就是因为 [删第一位i=1 ~ 删最后一位i=n] 的概率一样,那就是p=1/n,那在推算一下插入到每一位要循环几次*p,就是平均概率,最后还是O(n)
(2)【查】
静态查找就不说了,是个人都会
动态查找用的是指针,所以简单看一下
【按位查找】
- 其实就是根据【指针:所指的第i个数据块的起始位置】+【这个类型数据块的大小】返回这【第i个数据的值】
- (图中为什么写[i-1]?是因为它默认我们比如像查找第5个元素,就是按照人类思维的1、2、3、4、5数数,而在计算机数组里对应的是0、1、2、3、4,他个死人也不解释一下)
【按值查找】
- 懒得解释了,看看图理解一下好了,找到就返回这个元素的位置i就行了
- (图中为什么写[i+1]?依旧是因为它默认我们按照人类思维的1、2、3、4、5数数,而在计算机数组里对应的是0、1、2、3、4,计算机找到第4个元素要转成人类思维告诉我们是第5个)
- 另外C语言里【结构体】不可以直接==来对比,我相信各位都会没必要解释,java也是一样不能用==来对比【对象】,要比较的应该是里面的具体值才对
- 但是考408伪代码可以写==,因为伪代码不在乎语法错误
【时间复杂度】跟【增】【删】都是一样的
另外我想强调一个概念区分:
- 【插入、增加】和【存】的区别
- 【插入、增加】特指给定位置i,其他元素值不变的情况下新添入一个元素,但整体序列长度增加
- 【存】是直接将数据覆盖到位置i里,改变了原本位置i的元素值,但是整体序列长度不变
- 【删除】和【取】的区别
- 【删除】就是给定位置i,指定删掉这个位置的元素
- 【取】强调访问,读取出第i位置的元素值,但不影响它原本在存储单元的变化
- 【存取】本质意义是“访问”,仅此而已
(3)例题
三、线性表之【链表】
这一块我只稍微解释一下双链表,因为主包大一只写过单链表,双链表我也不是很会,我一直痛恨链表来着......
1、单链表
(1)基本概念
- 1、C语言【起别名】
- 大家都会没必要解释,不过很多人可能忘了语法怎么写,这里回顾一下
- 2、定义单链表时的【结构体指针】的两种表示语法
- 不回忆的话我还真忘了
- 3、单链表有两种写法【带头结点】和【不带头结点】
- 【不带头结点】
- 创建的链表的“领头羊”是一个【结构体类指针】
- 【结构体类指针】初始为空NULL
- 【带头结点】
- 创建的链表的“领头羊”是【结构体类指针】+【头节点】
- 【结构体类指针】不为NULL,它指向【头节点】
- 【头节点的数据部分】不存数据,因为这个节点只是一个“领头羊”,而不是实际一个元素的空间
- 【头节点的指针部分】初始为空NULL
- 再次总结
(2)例题
(3)基本操作
【插入】
- 【带头节点的按位插入】
- 【不带头结点的按位插入】
- 关于【前插】、【后插】
- 上面代码里,从【while循环遍历】后到结尾的【插入操作】,其实还可以分成【前插】、【后插】
- 【前插】就是在指定插在【i-1 的位置】、【后插】是指定插在【i 的位置】
- 所以看的出【后插】跟前面的操作不变
- 【时间复杂度】:【O(1)】
- 【前插】则有一点不一样,而且还分两种方式:
- 【设置前指针pre,遍历到p指针】
- 【时间复杂度】:【O(N)】
- 【插入和后插一样,但是移动数据】
- 【时间复杂度】:【O(1)】
- 【时间复杂度】这块
【查找】
没什么好说的,【按位查找】和【按值查找】都是顺序遍历,都是O(N)
【删除】
;
;
- 【时间复杂度】这块
(4)单链表的建立
前面我们学的是【如何根据指定位置 i 插入、删除...】
现在我们要想怎么【给一个链表增长(任意位置插入)】
【头插法】
注意,一个顺序数用【头插法】建立链表的话,就会成为一个逆序数!!!
因为【每下一位数构建的节点】都是插入到【头节点后第一位】
【尾插法】
【对比】
(5)例题
2、双链表
单链表只能一个节点带一个指针,一直指向后一节点,当循环遍历指针P增删查改时,都只能往后遍历,不能往前遍历
双链表就是为了能解决往前遍历,让每个节点既包含了头指针、又包含尾指针
【初始化】
跟单链表唯一的区别就是多了个【前指针:L—>prior】
要把【L—>prior】和【L—>next】都置为NULL空
【插入】
【后插法】
其实这逻辑看不明白的话就自己画一下代码流程
另外,换个思维考虑:
- 我们把一个节点当成需要4根电线连接
- 节点前面有一根指向前驱节点、一根前驱节点指向自己的2根电线
- 节点后面有一根指向后继节点、一根后继节点指向自己的2根电线
- 那么插入一个新节点,也是需要按顺序接入4根电线
- 但是如果是在最后一个节点后面插入,就只用三根线
- 所以回到代码就是
【头插发】
- 而前插法原理无需多说,因为引入双指针后,可以很方便的用前指针找到【头节点】,只需要在【头节点】进行【后插法】即是【头插法】了
【删除】
按我刚刚那个逻辑,删除也很好理解
- 中间删就【p->next跨过q接上q->next】然后【q->next->prior也跨过q接上p】
- 结尾删就只用【p->next跨过q接上q->next】,因为NULL没有prior
【查找】
和单链表一样,没得【随机存取】,只能顺序遍历,没了
3、循环链表
【思维导图】
;
【循环单链表】
知识点就看这些就够了
;
【循环双链表】
4、静态链表
留意一下静态链表的结构体,是一个【结构体数组】
然后【指针域】也不再是【指针】,而是【int类型的 “游标”】
5、【顺序表】和【链表】的对比
背熟!考试选择题考一万遍,来回鞭尸反复考
6、【这一章整体思维导图】
;
;
整个方便打印的图片
四、手写代码大题!!!!!!
【顺序表代码重点】
1、定义顺序表结构体
首先,虽然大家很爱用【int数组】,但是顺序表408要求就是写成【结构体】,然后在【结构体里面】设置一个【数组】,那没招了,背这个套路就完事了呗
【定义一个结构体】
【初始化值】
一般情况我们更喜欢用typedef把麻烦的【struct 结构体类型名】换成简单的【结构体类型名】,那就如下:
这样换完,我们以后初始化创建变量时也可以简写了
小练一题
2、顺序表插入一个数
这里有一个区别,写习惯C语言的各位可能不习惯在顺序表插入函数里写bool类型,自己写代码都觉得插入不需要返回,写个void就够
不行,考试套路就这样,就是得返回bool,插入成功返回true、插入失败返回false
忘了说,那个Insert_L是函数自定义名,你爱写啥写啥,尽量单词让人看得懂你要干嘛
还有