一.链表的基本概念 线性表的链式存储-链表 头指针->头结点->首元结点
1.单链表、双链表、循环链表
(1)单链表:结点只有一个指针域的链表
(2)双链表:结点有两个指针域的链表
(3)循环链表:首尾相接的链表
2.结点由两个域组成:
数据域:存储数据
指针域:存储直接后继结点的地址
3.头指针是指向链表第一个结点的指针
头结点是存放链表相关信息,不计入表长;数据域内只放空表标志和表长等信息
首元结点是链表中存储第一个数据元素a1的结点
4.如何判断链表为空?
答:(1)无头结点,若头指针为空则链表为空 (2)有头结点,若头结点的指针域为空则链表为空
5.结点在存储器上是如何存储的?
答:结点在存储器上的位置是任意的,即逻辑上相邻的数据元素物理上不一定相邻
6.链表的优点和缺点
优点:(1)数据元素的个数可以自由扩充 (2)插入和删除等操作不必移动数据,只需要修改指针
缺点:(1)存储密度小 (2)存取的效率不高,必须采取顺序存取,即存取元素时,只能按链表的顺序,顺藤摸瓜
二.单链表的定义
sturct Lnode:自定义的一种类型,该类型存在两个成员
sturct Lnode *next:是指针,该指针的类型是"sturct Lnode","sturct Lnode"中包括两个如上图类型的成员(嵌套的定义)。*next指向的变量仍然是有data和*next的两个成员的类型,这种类型就是"struct node"
(1)定义链表一般用:Linklist L;(2)定义结点一般用:Lnode *p;
例如:存储学生学号,姓名,成绩的单链表结点类型定义如下:
为了统一链表的操作,通常定义为:
三.单链表的基本操作
方式2比较常用!!!
1.单链表的初始化(创建空的单链表)
【算法思路】
(1)生成新结点作为头结点,head指向头结点
(2)将头结点的指针域置空
2.尾插法创建链表
【算法思路】
(1)创建新结点(申请内存)
(2)寻找尾结点
(3)插入尾结点
3.判断链表是否为空
空表:链表中无元素,称为空链表(头指针和头结点仍然在)
【算法思路】判断头结点指针域是否为空
4.销毁单链表
链表的销毁:链表销毁后不存在
【算法思路】从头指针开始,依次释放所有结点
5.清空链表
链表仍存在,但链表中无元素,成为空链表(头指针和头结点仍然在)
【算法思路】依次释放所有结点,并将头结点指针域设置为空
6.打印链表,并返回链表长度
printf函数打印的数据类型以实际数据为准("%d" 或 "%c"等)
7.单链表的按值查找(查)
【算法步骤】
1.从第一个结点起,依次和e相比较。
2.如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址;
3.如果查遍整个链表都没有找到其值和e相等的元素,则返回NULL。
根据数据的不同,"char e"可以替换成"int e"等
第一种:返回地址
第二种:返回序号
8.单链表的按位置查找(查)
9.单链表的插入结点(增)
【算法步骤】
1、首先找到ai-1的存储位置p。
2、生成一个数据域为e的新结点s。
3、插入新结点:
- 新结点的指针域指向结点ai
- 结点ai-1的指针域指向新结点
10.单链表的删除结点(删)
【算法步骤】
1、首先找到ai-1的存储位置p,保存要删除的ai的值
2、令p -> next 指向ai+1
第一种:按位置删除结点
第二种:按值删除结点
11.单链表的修改结点(改)
(1)手动
(2)非手动
主函数: