文章目录
- 第二章 线性表
- 2.1线性表的定义和基本操作
- 1.线性表
- 2.线性表的基本操作
- 2.2线性表的顺序表示
- 1.顺序表的定义
- 2)顺序表的实现——静态分配
- 3)顺序表的实现——动态分配(时间开销大)
- 2.顺序表的插入删除
- 1)顺序表的插入
- 2)顺序表的删除
- 3.顺序表的查找
- 1)按位查找
- 按位查找的时间复杂度
- 2)按值查找
- 按值查找的时间复杂度
- 2.单链表的插入删除
- 1)按位序插入(带头结点)
- 2)按位序插入(不带头指针)
- 3)指定结点的后插操作
- 4)指定结点的前插操作
- 5)按位序删除(带头结点)
- 6)指定结点的删除
第二章 线性表
2.1线性表的定义和基本操作
1.线性表
线性表是具有相同(每个元素所占空间一样大)数据类型的n(n>=0)个数据元素的有限序列(有次序),其中n为表长,当n=0时线性表是一个空表。若用L命名线性表,则其一般表示为
几个概念:
2.线性表的基本操作
理解:什么时候要传入参数的引用“&”——对参数 的修改结果需要“带回来”。(类似于C语言中传入参数的地址,在函数内对参数修改)
2.2线性表的顺序表示
1.顺序表的定义
1)顺序表——用顺序存储的方式实现线性表顺序存储。
顺序存储。把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的领接关系来体现。
如何知道一个数据元素的大小?
c语言中
sizeof(ElemType);EleemType就是你顺序表中存放的数据元素类型
eg:
typedef struct{
int num;
int people;
}Customer;
sizeof(int) = 4B
sizeof(Customer) = 8B
2)顺序表的实现——静态分配
代码理解
更好的做法是使用基本操作来访问各个数据元素
静态分配的缺点:顺序表的长度一旦确定无法更改(存储空间是静态的)
3)顺序表的实现——动态分配(时间开销大)
代码理解
当执行free( p )时*p所指空间被释放
顺序表的特点:
- 随机访问,即可以在O(1)时间找到第i个元素。(代码实现:data[i-1]静态分配、动态分配都一样)
- 存储密度高,每个节点只存储数据元素
- 扩展容量不方便,(即便采用动态分配 的方式实现,拓展长度的时间复杂度也比较高)
- 插入、删除操作不方便,需要移动大量元素
2.顺序表的插入删除
1)顺序表的插入
代码理解
阅读代码可以发现:代码不具备健壮性,添加下面代码
插入操作的时间复杂度
- 平均复杂度为O(n)
- 最坏时间复杂度也是O(n)
- 最好时间复杂度是O(1)
2)顺序表的删除
代码理解
删除操作的时间复杂度
- 平均复杂度为O(n)
- 最坏时间复杂度也是O(n)
- 最好时间复杂度是O(1)
总结:插入和删除的时间复杂度最好、平均复杂度均为O(n)。
3.顺序表的查找
1)按位查找
静态分配
动态分配
再次理解
按位查找的时间复杂度
2)按值查找
代码理解
结构类型的比较
不能用“ == ”
手写代码中也许可以用
按值查找的时间复杂度
2.单链表的插入删除
1)按位序插入(带头结点)
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。(找到第i-1个结点,将新节点插入其后)。
代码实现
- 最坏时间复杂度:O(n)
- 平均时间复杂度:O(n)
2)按位序插入(不带头指针)
ListInsert(&L,i,e):插入操作。在表L中的第i个位置上插入指定元素e。(找到第i-1个结点,将新节点插入其后)。
- 对第一个结点的操作需要一段代码来处理
3)指定结点的后插操作
这段时间复杂度为:O(1)
4)指定结点的前插操作
第一种方法:传入头指针
第二种方法:将p中元素复制到s中;p中元素覆盖为e
第三种方法:使用交换思想
5)按位序删除(带头结点)
ListDelete(&L,i,&e):删除操作。删除表L中第i个位置的元素,并用e返回删除元素的值。(找到第i-1个结点,将其指针指向第i-1个结点,并释放第i个结点)
代码实现
6)指定结点的删除
- 如果p是最后一个结点,上述代码就会有bug,p->next->data的值就是一个null,所有是一个bug。
- 这时只能从表头开始一次寻找p的前驱,时间复杂度O(n)