C语言线性链表
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Note:只要不特殊说明,用的就是带头结点的链表。 Note:只要不特殊说明,用的就是带头结点的链表。
13
课后作业
对照不带头结点和带头结点两种单链表 的插入操作, 的插入操作,自行分析两种单链表对于 删除操作的不同。(书面作业 操作的不同。(书面作业) 删除操作的不同。(书面作业) 说明: 说明: 必须要做! 必须要做! 虽然不讲,但是是考试内容! 虽然不讲,但是是考试内容!
方法2:尾插法建立单链表 方法 :尾插法建立单链表
int CreatListR(LinkList &H ) { int element; LinkList L; LNode *s, *last; //s指向新结点,last指向链表的最后结点 指向新结点, 指向新结点 指向链表的最后结点 L=(LinkList)malloc(sizeof(LNode)); L->next=NULL; //建立头结点 建立头结点 last=L; cin>>element; while (element !=0) { s =(LNode *)malloc(sizeof(LNode)); //申请新结点 申请新结点 s ->data=element; s->next=NULL; last->next= s; //新结点链入链表 新结点链入链表 last=s; //last指向新的最后结点 指向新的最后结点 cin>>element; } H=L; return 0; ; }// CreatListR 18
s->next=p->next; >next=pp->next=s ; s->next
^
(2)空表插入: head 空表插入: 空表插入 p s
欧耶! 欧耶! 太给力了!!! 太给力了
X
11
^
单链表插入操作的算法描述
status ListInsert_L( LinkList &L, int i, ElemType e ) { 在带头结点的链表中的第 个结点前插入元素e // 在带头结点的链表中的第i个结点前插入元素 个结点前插入元素 p=L; j=0; while (p && j<i-1) { p=p->next; ++j; } //查找第 个结点 查找第i-1个结点 查找第 if (!p || j>i-1) return -1; //i值不合法 值不合法 s = (LNode*) malloc( sizeof(LNode) ); //申请新结点的空间 申请新结点的空间 s->data=e; s->next = p->next; p->next=s; //插入操作 插入操作 return OK; } // ListInsert_L P29 算法 算法2.9
尾插法
16
尾插法建立单链表算法
方法1: 方法 :调用基本算法 建立链表; 建立链表; 思想: 思想: 1.初始化链表 初始化链表; 1.初始化链表; 2.将结点逐个插入表尾 2.将结点逐个插入表尾
使用基本算法: 使用基本算法 void InitList(&L); ; void ListInsert(&L, i, e)
数据和数据间的关系分别存储
1
链表分类
按照链式存储的原则, 按照链式存储的原则,可以有多种形式的链表
线性链表(单链表) 线性链表(单链表) 循环链表 双向链表
rear
头结点 a1 an
H a1 a2 a3 an ^
单链表的定义
typedef int ElemType; typedef struct LNode{ ElemType data; //结点的数据域 结点的数据域 struct LNode *next; //结点的指针域 结点的指针域 }LNode, *LinkList;
小结: 小结:带表头结点的单链表
表头结点位于表的最前端,本身不带数据, 表头结点位于表的最前端,本身不带数据,仅 做标志。有时可用来存储附加信息。 做标志。有时可用来存储附加信息。 设置表头结点的好处 以空间赢得时间 好处: 设置表头结点的好处: 统一了链表第一位置和其他位置的操作; 统一了链表第一位置和其他位置的操作; 统一了空表和非空表的操作; 统一了空表和非空表的操作; 使得各种链表(单向链表、双向链表、 使得各种链表(单向链表、双向链表、单向循 环链表和双向循环链表)的空链表状态得到区 环链表和双向循环链表) 亦表明各种空链表结构是不同的。 分;亦表明各种空链表结构是不同的。
线性表的链式存储结构
每个元素由结点( 构成; 每个元素由结点(Node)构成; 结点间的逻辑关系是线性的,即线性表; 逻辑关系是线性的 结点间的逻辑关系是线性的,即线性表; 结点在计算机中可以不连续存储 不连续存储; 结点在计算机中可以不连续存储; 链表可以扩充,只受存储介质大小的限制; 链表可以扩充,只受存储介质大小的限制; Node:
核心语句: 核心语句: s->next=NULL; p->next =s ;
8
原语句: 原语句: s->next=p->next; >next=pp->next=s ;
单链表插入操作的特殊情况( ) 单链表插入操作的特殊情况(3)
空表插入 head==NULL
s
核心语句: 核心语句: s->next=NULL; head =s ; 原语句: 原语句: s->next=p->next; >next=pp->next=s ;
链表基本算法实现(2)——建立单链表 建立单链表 链表基本算法实现
建立链表的过程是一个动态生成的过程: 建立链表的过程是一个动态生成的过程: 从空表状态,依次建立各元素结点, 从空表状态,依次建立各元素结点,并逐个插入
head ^
步骤: 步骤: (1)找到单链表的末尾; )找到单链表的末尾; (2)将新结点插入。 )将新结点插入。
23
小结: 小结:顺序表和链表的比较
1. 选用原则
长度已知,且变化不大,则选择顺序表; 长度已知,且变化不大,则选择顺序表; 长度不定,或变化大,则选用链表。 长度不定,或变化大,则选用链表。
1. 主要操作的特点
顺序表:插入、删除费时间移动数据, 顺序表:插入、删除费时间移动数据, 取数据快速; 取数据快速; 链表:插入、删除快速,取数据费时间。 链表:插入、删除快速,取数据费时间。
3
单链表的存储映像
P
head
4
单链表的基本操作 单链表的基本操作
初始化: 初始化:InitList(&L) 销毁: 销毁:DestroyList(&L) 清空: 清空:ClearList(&L) 判表空: 判表空:ListEmpty(L) 求表长: 求表长:ListLength(L) 取元素值: 取元素值:GetElem(L,i,&e) 查找某元素: 查找某元素:LocateElem(L,e) 求前驱: 求前驱:PriorElem(L,cur_e,&pre_e) 求后继: 求后继:NextElem(L,cur_e,&next_e) 插入: 插入:ListInsert(&L,i,e) 删除: 删除:ListDelete(&L,i,&e) 遍历: 遍历:ListTraverse(L, Visit( ))
14
2.3.3 链表基本算法实现 链表基本算法实现(1)——初始化 初始化
生成一个带头结点的空链表 生成一个带头结点的空链表 头指针 head 表头结点
^
Status InitList_L(LinkList &L){ L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;//创建头结点 创建头结点 return OK; }//InitList_L;
X
∧
太麻烦了!!! 太麻烦了!!! 赶快想个办法吧! 赶快想个办法吧!
he ad
9
解决之道: 表头结点的单链表 解决之道:带表头结点的单链表
头指针 head 头指针 head 表头结点 表头结点
^
…
^
首结点:存储第一个数据元素
10
带表头节点单链表的插入操作
head p (1)表头插入: s 表头插入: 表头插入 X a b
45
36 ^
尾插法建立单链表性能分析
T(n)=O(n) 如果不设last指针,则T(n)=O(n2) 指针, 如果不设 指针 不省心,总要记住表尾。 不省心,总要记住表尾。 如何改进? 如何改进? 头插法
头插法建立单链表 算法2.11 2.11) 头插法建立单链表(P30 算法2.11)
void CreatList_L(LinkList &L, int n) { //逆位序输入 个元素的值,建立带头结点的单链表 逆位序输入n个元素的值 逆位序输入 个元素的值,建立带头结点的单链表L L=(LinkList) malloc (sizeof(LNode) ); L->next=NULL; //建立头结点 建立头结点 for (i=n; i>0; - -i) { p=(LinkList)malloc(sizeof(LNode)); cin>>p->data; p->next=L->next; 输入: , , , , 输入:36,45,10,23,67 L->next=p; } 67 23 10 45 36 ^ L } CreatList_L
方法2: 方法 :自编算法建立 思想: 思想: 1.初始化链表 初始化链表; 1.初始化链表; 2.申请一个结点 申请一个结点; 2.申请一个结点; 3.初始化它的值 初始化它的值; 3.初始化它的值; 4.结点链入表尾 结点链入表尾; 4.结点链入表尾; 5.结束否 结束否? 5.结束否? 6.Yes,结束创建操作; 6.Yes,结束创建操作; 7.No,重复步骤2 7.No,重复步骤2-6;
单链表的插入操作
Step 1:s->next=p->next; >next=pStep 2:p->next=s ;
当!当!当! 当 万无一失吗??? 万无一失吗 有没有问题呢? 有没有问题呢
6
单链表插入操作wenku.baidu.com特殊情况( ) 单链表插入操作的特殊情况(1)
在第一个结点前插入 p
head a b ……
方法1实现: 方法 实现:利用基本算法建立链表 实现
LinkList CallFunc_CreatLinkList( ) { LinkList L; int i=0; InitList(L); //初始化链表 InitList(L); //初始化链表 i=1; scanf(&x); while (x!=flag)//建立链表,flag结束标志 (x!=flag)//建立链表,flag结束标志 建立链表,flag { ListInsert(L, i, x);//结点插入链表末尾 x);//结点插入链表末尾 i++; 输入: , , , , 输入:67,23,10,45,36 scanf(&x); } 67 23 10 L return L; }
s
X
s->next 原语句: 原语句: s->next=p->next; >next=pp->next=s ;
7
核心语句: 核心语句: s->next=p;//head; head=s ;
单链表插入操作的特殊情况( ) 单链表插入操作的特殊情况(2)
在末尾插入
head a p b ∧
s
X ∧
s->next
总结: 总结:单链表的优缺点
优点
能有效利用存储空间; 能有效利用存储空间; 指针"指示数据元素之间的后继关系 用"指针 指示数据元素之间的后继关系,便于进 指针 指示数据元素之间的后继关系, 插入"、 删除 等操作; 删除"等操作 行"插入 、"删除 等操作; 插入
缺点: 缺点:
不能随机存取数据元素。 不能随机存取数据元素。 同时,还丢失了一些顺序表有的长处, 同时,还丢失了一些顺序表有的长处,如数据元 素在线性表中的“位序”,在的单链表中都“看 素在线性表中的“位序” 在的单链表中都“ 不见” 不见”了。 不便于在表尾插入元素, 不便于在表尾插入元素,需遍历整个表才能找到 表尾。 表尾。
22
其他类型的链表——双向链表 双向链表 其他类型的链表
H a1 a2 a3 an ^
空表: 空表:
H
^
^
typedef int ElemType ; typedef struct DuLNode { ElemType data ; struct DuLNode *prior ; struct DuLNode *next ; } DuLNode, *DuLinkList ;
13
课后作业
对照不带头结点和带头结点两种单链表 的插入操作, 的插入操作,自行分析两种单链表对于 删除操作的不同。(书面作业 操作的不同。(书面作业) 删除操作的不同。(书面作业) 说明: 说明: 必须要做! 必须要做! 虽然不讲,但是是考试内容! 虽然不讲,但是是考试内容!
方法2:尾插法建立单链表 方法 :尾插法建立单链表
int CreatListR(LinkList &H ) { int element; LinkList L; LNode *s, *last; //s指向新结点,last指向链表的最后结点 指向新结点, 指向新结点 指向链表的最后结点 L=(LinkList)malloc(sizeof(LNode)); L->next=NULL; //建立头结点 建立头结点 last=L; cin>>element; while (element !=0) { s =(LNode *)malloc(sizeof(LNode)); //申请新结点 申请新结点 s ->data=element; s->next=NULL; last->next= s; //新结点链入链表 新结点链入链表 last=s; //last指向新的最后结点 指向新的最后结点 cin>>element; } H=L; return 0; ; }// CreatListR 18
s->next=p->next; >next=pp->next=s ; s->next
^
(2)空表插入: head 空表插入: 空表插入 p s
欧耶! 欧耶! 太给力了!!! 太给力了
X
11
^
单链表插入操作的算法描述
status ListInsert_L( LinkList &L, int i, ElemType e ) { 在带头结点的链表中的第 个结点前插入元素e // 在带头结点的链表中的第i个结点前插入元素 个结点前插入元素 p=L; j=0; while (p && j<i-1) { p=p->next; ++j; } //查找第 个结点 查找第i-1个结点 查找第 if (!p || j>i-1) return -1; //i值不合法 值不合法 s = (LNode*) malloc( sizeof(LNode) ); //申请新结点的空间 申请新结点的空间 s->data=e; s->next = p->next; p->next=s; //插入操作 插入操作 return OK; } // ListInsert_L P29 算法 算法2.9
尾插法
16
尾插法建立单链表算法
方法1: 方法 :调用基本算法 建立链表; 建立链表; 思想: 思想: 1.初始化链表 初始化链表; 1.初始化链表; 2.将结点逐个插入表尾 2.将结点逐个插入表尾
使用基本算法: 使用基本算法 void InitList(&L); ; void ListInsert(&L, i, e)
数据和数据间的关系分别存储
1
链表分类
按照链式存储的原则, 按照链式存储的原则,可以有多种形式的链表
线性链表(单链表) 线性链表(单链表) 循环链表 双向链表
rear
头结点 a1 an
H a1 a2 a3 an ^
单链表的定义
typedef int ElemType; typedef struct LNode{ ElemType data; //结点的数据域 结点的数据域 struct LNode *next; //结点的指针域 结点的指针域 }LNode, *LinkList;
小结: 小结:带表头结点的单链表
表头结点位于表的最前端,本身不带数据, 表头结点位于表的最前端,本身不带数据,仅 做标志。有时可用来存储附加信息。 做标志。有时可用来存储附加信息。 设置表头结点的好处 以空间赢得时间 好处: 设置表头结点的好处: 统一了链表第一位置和其他位置的操作; 统一了链表第一位置和其他位置的操作; 统一了空表和非空表的操作; 统一了空表和非空表的操作; 使得各种链表(单向链表、双向链表、 使得各种链表(单向链表、双向链表、单向循 环链表和双向循环链表)的空链表状态得到区 环链表和双向循环链表) 亦表明各种空链表结构是不同的。 分;亦表明各种空链表结构是不同的。
线性表的链式存储结构
每个元素由结点( 构成; 每个元素由结点(Node)构成; 结点间的逻辑关系是线性的,即线性表; 逻辑关系是线性的 结点间的逻辑关系是线性的,即线性表; 结点在计算机中可以不连续存储 不连续存储; 结点在计算机中可以不连续存储; 链表可以扩充,只受存储介质大小的限制; 链表可以扩充,只受存储介质大小的限制; Node:
核心语句: 核心语句: s->next=NULL; p->next =s ;
8
原语句: 原语句: s->next=p->next; >next=pp->next=s ;
单链表插入操作的特殊情况( ) 单链表插入操作的特殊情况(3)
空表插入 head==NULL
s
核心语句: 核心语句: s->next=NULL; head =s ; 原语句: 原语句: s->next=p->next; >next=pp->next=s ;
链表基本算法实现(2)——建立单链表 建立单链表 链表基本算法实现
建立链表的过程是一个动态生成的过程: 建立链表的过程是一个动态生成的过程: 从空表状态,依次建立各元素结点, 从空表状态,依次建立各元素结点,并逐个插入
head ^
步骤: 步骤: (1)找到单链表的末尾; )找到单链表的末尾; (2)将新结点插入。 )将新结点插入。
23
小结: 小结:顺序表和链表的比较
1. 选用原则
长度已知,且变化不大,则选择顺序表; 长度已知,且变化不大,则选择顺序表; 长度不定,或变化大,则选用链表。 长度不定,或变化大,则选用链表。
1. 主要操作的特点
顺序表:插入、删除费时间移动数据, 顺序表:插入、删除费时间移动数据, 取数据快速; 取数据快速; 链表:插入、删除快速,取数据费时间。 链表:插入、删除快速,取数据费时间。
3
单链表的存储映像
P
head
4
单链表的基本操作 单链表的基本操作
初始化: 初始化:InitList(&L) 销毁: 销毁:DestroyList(&L) 清空: 清空:ClearList(&L) 判表空: 判表空:ListEmpty(L) 求表长: 求表长:ListLength(L) 取元素值: 取元素值:GetElem(L,i,&e) 查找某元素: 查找某元素:LocateElem(L,e) 求前驱: 求前驱:PriorElem(L,cur_e,&pre_e) 求后继: 求后继:NextElem(L,cur_e,&next_e) 插入: 插入:ListInsert(&L,i,e) 删除: 删除:ListDelete(&L,i,&e) 遍历: 遍历:ListTraverse(L, Visit( ))
14
2.3.3 链表基本算法实现 链表基本算法实现(1)——初始化 初始化
生成一个带头结点的空链表 生成一个带头结点的空链表 头指针 head 表头结点
^
Status InitList_L(LinkList &L){ L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;//创建头结点 创建头结点 return OK; }//InitList_L;
X
∧
太麻烦了!!! 太麻烦了!!! 赶快想个办法吧! 赶快想个办法吧!
he ad
9
解决之道: 表头结点的单链表 解决之道:带表头结点的单链表
头指针 head 头指针 head 表头结点 表头结点
^
…
^
首结点:存储第一个数据元素
10
带表头节点单链表的插入操作
head p (1)表头插入: s 表头插入: 表头插入 X a b
45
36 ^
尾插法建立单链表性能分析
T(n)=O(n) 如果不设last指针,则T(n)=O(n2) 指针, 如果不设 指针 不省心,总要记住表尾。 不省心,总要记住表尾。 如何改进? 如何改进? 头插法
头插法建立单链表 算法2.11 2.11) 头插法建立单链表(P30 算法2.11)
void CreatList_L(LinkList &L, int n) { //逆位序输入 个元素的值,建立带头结点的单链表 逆位序输入n个元素的值 逆位序输入 个元素的值,建立带头结点的单链表L L=(LinkList) malloc (sizeof(LNode) ); L->next=NULL; //建立头结点 建立头结点 for (i=n; i>0; - -i) { p=(LinkList)malloc(sizeof(LNode)); cin>>p->data; p->next=L->next; 输入: , , , , 输入:36,45,10,23,67 L->next=p; } 67 23 10 45 36 ^ L } CreatList_L
方法2: 方法 :自编算法建立 思想: 思想: 1.初始化链表 初始化链表; 1.初始化链表; 2.申请一个结点 申请一个结点; 2.申请一个结点; 3.初始化它的值 初始化它的值; 3.初始化它的值; 4.结点链入表尾 结点链入表尾; 4.结点链入表尾; 5.结束否 结束否? 5.结束否? 6.Yes,结束创建操作; 6.Yes,结束创建操作; 7.No,重复步骤2 7.No,重复步骤2-6;
单链表的插入操作
Step 1:s->next=p->next; >next=pStep 2:p->next=s ;
当!当!当! 当 万无一失吗??? 万无一失吗 有没有问题呢? 有没有问题呢
6
单链表插入操作wenku.baidu.com特殊情况( ) 单链表插入操作的特殊情况(1)
在第一个结点前插入 p
head a b ……
方法1实现: 方法 实现:利用基本算法建立链表 实现
LinkList CallFunc_CreatLinkList( ) { LinkList L; int i=0; InitList(L); //初始化链表 InitList(L); //初始化链表 i=1; scanf(&x); while (x!=flag)//建立链表,flag结束标志 (x!=flag)//建立链表,flag结束标志 建立链表,flag { ListInsert(L, i, x);//结点插入链表末尾 x);//结点插入链表末尾 i++; 输入: , , , , 输入:67,23,10,45,36 scanf(&x); } 67 23 10 L return L; }
s
X
s->next 原语句: 原语句: s->next=p->next; >next=pp->next=s ;
7
核心语句: 核心语句: s->next=p;//head; head=s ;
单链表插入操作的特殊情况( ) 单链表插入操作的特殊情况(2)
在末尾插入
head a p b ∧
s
X ∧
s->next
总结: 总结:单链表的优缺点
优点
能有效利用存储空间; 能有效利用存储空间; 指针"指示数据元素之间的后继关系 用"指针 指示数据元素之间的后继关系,便于进 指针 指示数据元素之间的后继关系, 插入"、 删除 等操作; 删除"等操作 行"插入 、"删除 等操作; 插入
缺点: 缺点:
不能随机存取数据元素。 不能随机存取数据元素。 同时,还丢失了一些顺序表有的长处, 同时,还丢失了一些顺序表有的长处,如数据元 素在线性表中的“位序”,在的单链表中都“看 素在线性表中的“位序” 在的单链表中都“ 不见” 不见”了。 不便于在表尾插入元素, 不便于在表尾插入元素,需遍历整个表才能找到 表尾。 表尾。
22
其他类型的链表——双向链表 双向链表 其他类型的链表
H a1 a2 a3 an ^
空表: 空表:
H
^
^
typedef int ElemType ; typedef struct DuLNode { ElemType data ; struct DuLNode *prior ; struct DuLNode *next ; } DuLNode, *DuLinkList ;