目录
- 分析顺序表和链表
- 实现单链表
- 打印链表
- 动态申请一个节点
- 尾插
- 头插
- 尾删
- 头删
- 查找值函数
- 单链表在pos位置之前插入x
- 单链表在pos位置之后插入x
- 删除pos位置
- 单链表删除pos位置之后的值
- 释放内存空间
分析顺序表和链表
如下图可以看出顺序表的优点
1.尾插尾删足够快
2.下标随机访问和修改方便
但是也能看出一些问题
1.由于顺序表是连续存放的,所以顺序表的头部和中部的插入删除的效率都不行(相比于链表)
2.空间不够,扩容会有一定的消耗
3.可能还存在空间浪费的问题
链表可以解决顺序表的这些问题。对于链表空间是一个一个分开存放的,链表的上一个元素只要保存要访问的下一个元素的地址即可。在申请内存时也不需要申请一整块内存空间,只需要在插入元素时申请所需要的内存大小即可。
下面我们来实现一个单链表。
实现单链表
打印链表
要打印出链表,首先定义一个结构体指针cur让这个结构体指针和phead指针同时指向第一个节点,创建完cur后,只需要判断该节点在while循环中指针不为空即可。不断把cur->nextD的值赋值给cur,然后打印cur节点,就完成了整个链表的遍历。
动态申请一个节点
动态申请一个节点最要注意的是需要申请的malloc的大小
尾插
尾插的常见错误分析:
1.tail通过while循环判断条件错误导致尾插失败
判断条件写成cur != NULL
正确结果是找到NULL的前一个节点,通过tail->next指向newnode,这样出了函数tail和newnode局部变量销毁也不会影响整个链表。
但是如果链表一开始是空的呢?
2.链表为空时,改变phead的值但是尾插失败
-----
-----
-----分析:----------
改变int要传int*,改变int*要传int**
得出结论:改变结构体要用结构体指针,改变结构体指针要用结构体指针的指针(二级指针)。
总结:当链表不为空时,只要改变tail->next,tail->next是结构体,所以只需要结构体的指针即可,链表为空时,我们要改变的是结构体指针plist,所以要用结构体指针的指针。
头插
头插不管链表为不为空都很明显需要用到二级指针。
尾删
尾删首先要考虑的问题是这个地方需不需要用到二级指针?对于数据结构的学习我们要考虑全面一些,如果尾删对于有多个节点的链表不需要用到二级指针,但是只有一个节点要怎么删除呢?答案还是要用到二级指针。尾删的时候链表为空还要尾删吗?所以这个地方还要考虑判断链表为不为空。
链表为空,我们只需要加一个断言即可。
链表只有一个节点
—
链表有多个节点
尾删首先要找尾,这里有一个常见错误
为了避免这种问题,有两种写法
1.定义一个tailprev找tail之前的位置,把tail指向的空间free,把tailprev的next置空。
2.在判断循环条件部分判断tail->next->next是否为空,释放tail->next,
把tail->next的值置空。
头删
头删只有两种情况,一种是空链表,一种是非空链表
查找值函数
这里可以传一级指针也可以传二级指针,因为我们不需要修改值。
利用find函数我们找到了节点的地址就可以修改当前节点的值。
单链表在pos位置之前插入x
在pos 位置之前插入,先要判断pos的位置,如果pos在头结点位置,就是头插我们可以复用头插的函数。这里pos在尾结点不用单独判断。