第11章C语言程序设计链表PPT课件
合集下载
C语言链表课件

return counter;
}//Count_LinkList
Void ChangeLinkList(LinkList &L) { LinkList p, q, s, r, t; q=null; r=L; t=null; //r指示原表的表尾,q是临时表 的表头指针,t指示临时表的表尾,p指示当前正在处理的结点 p=L→next; while(p) { if(p→data %2 == 1) { // p结点是奇数结点 s = p; r→next = p→next; //从原表中删除奇 数结点 s→data = s→data + 1; s→next = null; if(!q) { q = s; t = s ; } //在临时表中插入第一 个结点 else { t→next = s; t = s; } }//if else r = r→next; p = p→next; //处理下一个结点 }//while r→next=q; //将临时表链接到原表之后 }//ChangeLinkList
链表
结点(数据元素) = 元素(数据元素的映象) + 指针(指示后继元素存储位置) 结点 元素(data) 指针(next)
用一组地址任意的存储单元存放线性表中的数据元素。
链表:以“结点的序列”表示线性表
使用内存分配函数,动态申请和释放堆中的存储空间。
P124
struct node{//定义节点类型 int data; node * next; };
void main( ) { node * h; h=CreList( ); PrintList(h); }
node *CreList()
{node A_node; node *head; //首地址 node* s; //当前结点 head = NULL; printf("\n Please input the number ( 0 the end):\t"); scanf("%d",&A_node.data);
C语言-链表(课堂PPT)

内存释放函数原形:void free(void *p); 功能:释放p所指向的内存块。
包含文件:malloc.h、stdlib.h中均有其原型声明。
C 程序设计
第十一章 结构体与共用体 NWPU—CC—ZhangYanChun
5
5) 采用链表的意义
与定长数据结构数组相比,链表能更好地利用 内存,按需分配和释放存储空间。
head
1048 p1 2101
1370 p1 2304
1012
2918
89.5
90
85
操作:
1370
1012
NULL
pp22
p2
p1=(struct student *)malloc(len); scanf("%ld,%f", &p1->num, &p1->score);
p2->next=p1; p2=p1; p2->next=NULL;
/*使p2也指向新节点*/ /*末尾节点next赋值0*/
C 程序设计
第十一章 结构体与共用体 NWPU—CC—ZhangYanChun
11
【例】建立并输出有3名学生数据的单链表。
#include <stdio.h> #include <math.h> #define N 3 struct student { long num;
int i, len; sqrt(5.5);
float score; struct student *next; }; void main( ) {┇ }
/*包含NULL的定义*/ /*结构体类型定义*/ /*自引用结构体指针*/
C 程序设计
《C语言链表》课件

了解如何删除链表中的指定节点
详细描述
删除链表中的节点需要找到要删除的节点,修改其前一个节点的指针,使其指向要删除节点的下一个 节点,然后将要删除节点的指针置为NULL。如果要删除的是头节点或尾节点,还需要对头指针或尾 指针进行相应的修改。
遍历链表
总结词
了解如何遍历链表中的所有节点
VS
详细描述
遍历链表需要从头节点开始,依次访问每 个节点,直到达到链表的尾部。在遍历过 程中,可以使用一个指针变量来指向当前 节点,每次循环将指针向后移动一个节点 ,即修改指针的next指针。
链表和循环链表的主要区别在于它们的最后一个节点指向的方向。在链表中,最后一个节点指向NULL; 而在循环链表中,最后一个节点指向第一个节点。循环链表具有更好的性能,但实现起来相对复杂一些 。
05
总结与展望
总结链表的重要性和应用场景
总结1
链表作为C语言中一种基本的数据结构,在计算机科学中 有着广泛的应用。通过学习链表,可以更好地理解数据 结构的基本概念,提高编程能力和解决实际问题的能力 。
详细描述
合并两个有序链表可以通过比较两个链表的 节点值来实现。从头节点开始比较,将较小 的节点添加到结果链表中,并将指针向后移 动。重复此过程直到其中一个链表为空。如 果还有剩余的节点,将其添加到结果链表的 末尾。这种方法的时间复杂度为O(n),其中
n为两个链表中节点的总数。
04
常见错误与注意事项
内存泄漏问题
内存泄漏定义
在C语言中,内存泄漏是指在使用动 态内存分配函数(如malloc、calloc 、realloc等)分配内存后,未能正确 释放这些内存,导致程序运行过程中 不断占用越来越多的内存,最终可能 导致程序崩溃或性能下降。
详细描述
删除链表中的节点需要找到要删除的节点,修改其前一个节点的指针,使其指向要删除节点的下一个 节点,然后将要删除节点的指针置为NULL。如果要删除的是头节点或尾节点,还需要对头指针或尾 指针进行相应的修改。
遍历链表
总结词
了解如何遍历链表中的所有节点
VS
详细描述
遍历链表需要从头节点开始,依次访问每 个节点,直到达到链表的尾部。在遍历过 程中,可以使用一个指针变量来指向当前 节点,每次循环将指针向后移动一个节点 ,即修改指针的next指针。
链表和循环链表的主要区别在于它们的最后一个节点指向的方向。在链表中,最后一个节点指向NULL; 而在循环链表中,最后一个节点指向第一个节点。循环链表具有更好的性能,但实现起来相对复杂一些 。
05
总结与展望
总结链表的重要性和应用场景
总结1
链表作为C语言中一种基本的数据结构,在计算机科学中 有着广泛的应用。通过学习链表,可以更好地理解数据 结构的基本概念,提高编程能力和解决实际问题的能力 。
详细描述
合并两个有序链表可以通过比较两个链表的 节点值来实现。从头节点开始比较,将较小 的节点添加到结果链表中,并将指针向后移 动。重复此过程直到其中一个链表为空。如 果还有剩余的节点,将其添加到结果链表的 末尾。这种方法的时间复杂度为O(n),其中
n为两个链表中节点的总数。
04
常见错误与注意事项
内存泄漏问题
内存泄漏定义
在C语言中,内存泄漏是指在使用动 态内存分配函数(如malloc、calloc 、realloc等)分配内存后,未能正确 释放这些内存,导致程序运行过程中 不断占用越来越多的内存,最终可能 导致程序崩溃或性能下降。
C语言课件 链表

3.处理动态链表所需的函数
上例是比较简单的,所有结点都是在程序中定义 的,不是临时开辟的,也不能用完后释放,这种链表 称为“静态链表”。 前面讲过,链表结构是动态生地分配存储的,即 在需要时才开辟一个结点的存储单元 以便插入或追 加节点,删除节点后需要释放节点占用的内存单元。 C 语言提供了相应的函数。
⑴ void *malloc(unsigned int size) :在内存的动态存储区中分 配一个长度为size的连续空间。成功,则返回一个void型的空指针, 否则,返回NULL. 分配内存的字节数。
使用方法: ptr=malloc(size);
返回空类型的指针。 成功:返回内存的地址。 失败:返回NULL。 ⑵void free(ptr) 作用: 释放ptr指向的内存空间。 (3)void *calloc(unsigned n,unsigned size) 在内存的动态区 存储中分配n个长度为size的连续空间。函数返回分配域的起始 地址;如果分配不成功,返回0。
删除结点的函数: struct student *del (struct student *head,int num) {struct student *p1,*p2; if (head==NULL) {printf ("\nlist is null\n");} p1=head; while (p1->num!=num && p1->next!=NULL) {p2=p1;p1=p1->next;} if (p1->num==num) {if (p1==head) head=p1->next; else p2->next=p1->next; printf ("delete:%d\n",num); } else printf ("%ld not been found!",num); return(head); }
C语言_链表ppt课件

} 许多问题中,有时候为了操作方便,需要在第一个节点之前增加一个
特殊的节点,称为头节点,它的data字段不含信息或根据问题的需要 存放特殊信息。
2、链表的遍历(显示链表)
一个非递归算法
以下函数disp()用于显示头节点为*h的链表的所有节点 数据域。
void disp(struct Node *h) { struct Node *p=h; printf("输出链表:"); if(p==NULL) printf("空表\n"); else { while (p->next!=NULL) { printf("%4d",p->data); p=p->next; } printf("%4d\n",p->data); }
在链表结尾出插入一个元素
p
data
首先要用一个循环语句找到q
q
q=h;
h
...
NULL
while(q->next!=NULL)
q=q->next;
p
然后执行插入语句:
data
p->next=NULL;
q
q->next=p;
h
...
NULL
p
data
q
h
...
NULL
在链表中间插入一个元素
p
data
}
单链表的插入
.
3、链表的插入(头指针的情况下)
对于插入有以下几种情况 在一个空链表上插入一个元素。 (即要插入位置前方和后方均无元素) 从链表表头处插入一个元素 (即要插入的位置前方无元素,后方有元素) 从链表结尾处处插入一个元素 (即要插入的位置后方五元素,前方有元素) 从链表的中间插入 (即要插入的位置前方和后方均有元素) 其中第三种情况可以按照第四种情况处理,但有一定特殊性所以将 其分开 注意:产生新的节点必须用malloc或者calloc开辟空间
特殊的节点,称为头节点,它的data字段不含信息或根据问题的需要 存放特殊信息。
2、链表的遍历(显示链表)
一个非递归算法
以下函数disp()用于显示头节点为*h的链表的所有节点 数据域。
void disp(struct Node *h) { struct Node *p=h; printf("输出链表:"); if(p==NULL) printf("空表\n"); else { while (p->next!=NULL) { printf("%4d",p->data); p=p->next; } printf("%4d\n",p->data); }
在链表结尾出插入一个元素
p
data
首先要用一个循环语句找到q
q
q=h;
h
...
NULL
while(q->next!=NULL)
q=q->next;
p
然后执行插入语句:
data
p->next=NULL;
q
q->next=p;
h
...
NULL
p
data
q
h
...
NULL
在链表中间插入一个元素
p
data
}
单链表的插入
.
3、链表的插入(头指针的情况下)
对于插入有以下几种情况 在一个空链表上插入一个元素。 (即要插入位置前方和后方均无元素) 从链表表头处插入一个元素 (即要插入的位置前方无元素,后方有元素) 从链表结尾处处插入一个元素 (即要插入的位置后方五元素,前方有元素) 从链表的中间插入 (即要插入的位置前方和后方均有元素) 其中第三种情况可以按照第四种情况处理,但有一定特殊性所以将 其分开 注意:产生新的节点必须用malloc或者calloc开辟空间
C语言_链表

24
§11.5 链表的删除操作
p
Head
101 Zhang 90
103 Wang 80
101 Zhao 70
105 N U Li L 60 L
(a) head指示已有链表
q Head p
101 Zhang 90
103 Wang 80
101 Zhao 70
105 N U Li L 60 L
(b) 删除第3个结点
图11-2 删除第n个结点
25
(8) 返回链表头head。
20
§11.4 链表的插入操作
p Head
101 Zhang 90
103 Wang 80
105 Li 70
NU L
q
L
104 Zhao 70
r Head 101 Zhang 90 103 Wang 80 q
p 105 Li 70
NU
L
L
104 Zhao 60
图11-1 将指针q所指结点插入第2个结点之后
17
§11.4 链表入操作
在第n个结点之后插入一个新结点 ,插入操作步骤:
(1) q指针指向新结点,i为已访问过的结点数;
(2) p=head,r指向p结点的前一个结点;
(3) i++,r=p,p=p->next,p结点往前移动一个结点;
(4) 若i<n且p!=NULL,则重复(3);
3
§11.1 链表的概念
某3位同学的物理成绩分别为96,89,93。分别 用数组和链表存储这些数据的示意图如下:
a
3个元素的数组: float a[3]; 3个节点的链表:
613 93
609 89
C语言链表详解PPT课件
撤消原来的链接关系。 两种情况: 1、要删的结点是头指针所指的结点则直接操作; 2、不是头结点,要依次往下找。 另外要考虑:空表和找不到要删除的结点
26
链表中结点删除
需要由两个临时指针: P1: 判断指向的结点是不是要删除的结点 (用于寻找); P2: 始终指向P1的前面一个结点;
27
图 11.19
4
结点里的指针是存放下一个结点的地址
Head
1249
1249
A 1356
1356
B 1475
1475
C 1021
1021
D Null
1、链表中的元素称为“结点”,每个结点包括两 个域:数据域和指针域;
2、单向链表通常由一个头指针(head),用于指 向链表头;
3、单向链表有一个尾结点,该结点的指针部分指
7
(4)删除操作是指,删除结点ki,使线性表的长度 减1,且ki-1、ki和ki+1之间的逻辑关系发生如下变 化:
删除前,ki是ki+1的前驱、ki-1的后继;删除后,ki-1 成为ki+1的前驱,ki+1成为ki-1的后继.
(5)打印输出
8
一个指针类型的成员既可指向其它类型的结构体数 据,也可以指向自己所在的结构体类型的数据
(x7,y7)
为了表示这种既有数据又有指针的情况, 引入结构这种数据类型。
3
11.7 用指针处理链表
链表是程序设计中一种重要的动态数据结构, 它是动态地进行存储分配的一种结构。
动态性体现为: 链表中的元素个数可以根据需要增加和减少,不 像数组,在声明之后就固定不变;
元素的位置可以变化,即可以从某个位置删除, 然后再插入到一个新的地方;
26
链表中结点删除
需要由两个临时指针: P1: 判断指向的结点是不是要删除的结点 (用于寻找); P2: 始终指向P1的前面一个结点;
27
图 11.19
4
结点里的指针是存放下一个结点的地址
Head
1249
1249
A 1356
1356
B 1475
1475
C 1021
1021
D Null
1、链表中的元素称为“结点”,每个结点包括两 个域:数据域和指针域;
2、单向链表通常由一个头指针(head),用于指 向链表头;
3、单向链表有一个尾结点,该结点的指针部分指
7
(4)删除操作是指,删除结点ki,使线性表的长度 减1,且ki-1、ki和ki+1之间的逻辑关系发生如下变 化:
删除前,ki是ki+1的前驱、ki-1的后继;删除后,ki-1 成为ki+1的前驱,ki+1成为ki-1的后继.
(5)打印输出
8
一个指针类型的成员既可指向其它类型的结构体数 据,也可以指向自己所在的结构体类型的数据
(x7,y7)
为了表示这种既有数据又有指针的情况, 引入结构这种数据类型。
3
11.7 用指针处理链表
链表是程序设计中一种重要的动态数据结构, 它是动态地进行存储分配的一种结构。
动态性体现为: 链表中的元素个数可以根据需要增加和减少,不 像数组,在声明之后就固定不变;
元素的位置可以变化,即可以从某个位置删除, 然后再插入到一个新的地方;
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
printf("%ld %5.1f\n", p->num, p->score); p = p->next; }while(p != NULL); }
19
四、删除一个结点 删除一个结点的算法:
20
应考虑以下情况: 1、找到需要删除的结点,用p1指向它。 并用p2指向p1的前一个结点。 2、要删除的结点是头结点。
指向空 */ p1 = (struct student *)malloc(LEN); /* 创
建一个新结点p1 */ p2 = p1; /* 表尾p2也指向p1 */ scanf("%ld,%f", &p1->num, &p1->score);
/* 读入第一个结点的学生数据 */
17
while(p1->num != 0) /* 假设num=0表示输入结束 */
6
7
8
9
10
11
12
13
通过以上分析,可以得到创建链表的算 法,其中,n=1表示创建的是第一个结点。
14
15
程序:
#include "stdio.h" #include "alloc.h" #include "stdlib.h"
struct student {
long num; float score; struct student *next; };
21
22
3、要删除的结点不是头结点
23
根据以上情况分析,得到删除一个结点 的算法:
24
程序:
在链表head中删除学号为num的结点。以表头 指针head和需要删除的结点的num(学号)为 参数,返回删除操作后的链表表头。
struct student * del(struct student *head, long num) {
组中插入、删除数据项时,需要移动其它数据项)
。
链表有单向链表、双向链表、环形链表等形式。以
单向链表为例、
1
整体 概述
一 请在这里输入您的主要叙述内容
二
请在这里输入您的主要 叙述内容
三 请在这里输入您的主要叙述内容
2
3
链表有一个“头指针”head,它指向链表的第一 个元素。
链表的一个元素称为一个“结点”(node)。 结点中包含两部分内容,第一部分是结点数据 本身,如图中的A、B、C、D所示。结点的 第二部分是一个指针,它指向下一个结点。
18
二、输出链表 只要已知表头结点,通过p->next可以找到下一 个结点,从而可以输出链表的全部结点数据。 void print(struct student *head) {
struct student *p; printf("\nNow, These %d records are:\n", n); p = head; if (p == NULL) return; do {
25
while(num != p1->num && p1->next != NULL) /* 查找要删除的结 点 */
{
p2 = p1;
p1 = p1->next;
} if (num == p1->num) /* 找到了 */
{ if (p1 == head) /* 要删除的是头结点 */
struct student *p1; /* 指向要删除的结点 */ struct student *p2; /* 指向p1的前一个结点 */
if (head == NULL) /* 空表 */ {
printf("\n List is NULL\n"); return (hea(struct student)
/* 注意,"#define NULL 0"不需要,因为, NULL已在stdio.h中定义 */
int n;
struct student * creat() /* 创建链表,并返回 16
{ struct student *head; /* 表头 */ struct student *p1; /* 新建结点 */ struct student *p2; /* 表尾结点 */ n = 0; /* 结点数为0 */ head = NULL; /* 还没有任何结点,表头为
{
n = n + 1; if (n == 1) head = p1;
/* 第一个新建结点是表头
*/ else
是新建结点 */
p2->next = p1; /* 原表尾的下一个结点
p2 = p1; /* 新建结点成为表尾 */
p1 = (struct student *)malloc(LEN); /* 新建一个结 点 */
§11.7 用结构体指针处理链表
一、链表概述
链表是一种最常见的数据结构,它动态地进行存储
分配。
数组:必须事先定义固定的长度(元素个数),不
能适应数据动态地增减的情况。当数据增加时,可
能超出原先定义的元素个数;当数据减少时,造成
内存浪费。
链表动态地进行存储分配,可以适应数据动态地增
减的情况,且可以方便地插入、删除数据项。(数
scanf("%ld,%f", &p1->num, &p1->score); /* 读入 新建结点的学生数据 */
}
free(p1); /* 对于num=0的结点,未加入链表,应删 除其空间 */
p2->next = NULL; /* 输入结束,表尾结点的下一个结 点为空 */
return (head); /* 返回表头指针 */ }
并返回指向该空间起始地址的指针。若分配失 败(系统不能提供所需内存),则返回NULL。
2、void * calloc(size_t n, size_t size) 在动态存储区分配n个长度为size的连续
空间,并返回指向该空间起始地址的指针。若 分配失败(系统不能提供所需内存),则返回
NULL。
3、void free(void * ptr)
最后一个结点称为“表尾”,表尾结点的指针为 空(NULL)。
在链表中插入一个结点,比如,在结点A后插入 结点P,只需使P指向B,使A指向P。
在链表中删除一个结点,比如删除结点C,只需 4
5
链表需要动态地进行存储分配,在C语言中, 使用以下函数进行动态存储分配和释放。
1、void * malloc(size_t size) 在动态存储区分配长度为size的连续空间,
19
四、删除一个结点 删除一个结点的算法:
20
应考虑以下情况: 1、找到需要删除的结点,用p1指向它。 并用p2指向p1的前一个结点。 2、要删除的结点是头结点。
指向空 */ p1 = (struct student *)malloc(LEN); /* 创
建一个新结点p1 */ p2 = p1; /* 表尾p2也指向p1 */ scanf("%ld,%f", &p1->num, &p1->score);
/* 读入第一个结点的学生数据 */
17
while(p1->num != 0) /* 假设num=0表示输入结束 */
6
7
8
9
10
11
12
13
通过以上分析,可以得到创建链表的算 法,其中,n=1表示创建的是第一个结点。
14
15
程序:
#include "stdio.h" #include "alloc.h" #include "stdlib.h"
struct student {
long num; float score; struct student *next; };
21
22
3、要删除的结点不是头结点
23
根据以上情况分析,得到删除一个结点 的算法:
24
程序:
在链表head中删除学号为num的结点。以表头 指针head和需要删除的结点的num(学号)为 参数,返回删除操作后的链表表头。
struct student * del(struct student *head, long num) {
组中插入、删除数据项时,需要移动其它数据项)
。
链表有单向链表、双向链表、环形链表等形式。以
单向链表为例、
1
整体 概述
一 请在这里输入您的主要叙述内容
二
请在这里输入您的主要 叙述内容
三 请在这里输入您的主要叙述内容
2
3
链表有一个“头指针”head,它指向链表的第一 个元素。
链表的一个元素称为一个“结点”(node)。 结点中包含两部分内容,第一部分是结点数据 本身,如图中的A、B、C、D所示。结点的 第二部分是一个指针,它指向下一个结点。
18
二、输出链表 只要已知表头结点,通过p->next可以找到下一 个结点,从而可以输出链表的全部结点数据。 void print(struct student *head) {
struct student *p; printf("\nNow, These %d records are:\n", n); p = head; if (p == NULL) return; do {
25
while(num != p1->num && p1->next != NULL) /* 查找要删除的结 点 */
{
p2 = p1;
p1 = p1->next;
} if (num == p1->num) /* 找到了 */
{ if (p1 == head) /* 要删除的是头结点 */
struct student *p1; /* 指向要删除的结点 */ struct student *p2; /* 指向p1的前一个结点 */
if (head == NULL) /* 空表 */ {
printf("\n List is NULL\n"); return (hea(struct student)
/* 注意,"#define NULL 0"不需要,因为, NULL已在stdio.h中定义 */
int n;
struct student * creat() /* 创建链表,并返回 16
{ struct student *head; /* 表头 */ struct student *p1; /* 新建结点 */ struct student *p2; /* 表尾结点 */ n = 0; /* 结点数为0 */ head = NULL; /* 还没有任何结点,表头为
{
n = n + 1; if (n == 1) head = p1;
/* 第一个新建结点是表头
*/ else
是新建结点 */
p2->next = p1; /* 原表尾的下一个结点
p2 = p1; /* 新建结点成为表尾 */
p1 = (struct student *)malloc(LEN); /* 新建一个结 点 */
§11.7 用结构体指针处理链表
一、链表概述
链表是一种最常见的数据结构,它动态地进行存储
分配。
数组:必须事先定义固定的长度(元素个数),不
能适应数据动态地增减的情况。当数据增加时,可
能超出原先定义的元素个数;当数据减少时,造成
内存浪费。
链表动态地进行存储分配,可以适应数据动态地增
减的情况,且可以方便地插入、删除数据项。(数
scanf("%ld,%f", &p1->num, &p1->score); /* 读入 新建结点的学生数据 */
}
free(p1); /* 对于num=0的结点,未加入链表,应删 除其空间 */
p2->next = NULL; /* 输入结束,表尾结点的下一个结 点为空 */
return (head); /* 返回表头指针 */ }
并返回指向该空间起始地址的指针。若分配失 败(系统不能提供所需内存),则返回NULL。
2、void * calloc(size_t n, size_t size) 在动态存储区分配n个长度为size的连续
空间,并返回指向该空间起始地址的指针。若 分配失败(系统不能提供所需内存),则返回
NULL。
3、void free(void * ptr)
最后一个结点称为“表尾”,表尾结点的指针为 空(NULL)。
在链表中插入一个结点,比如,在结点A后插入 结点P,只需使P指向B,使A指向P。
在链表中删除一个结点,比如删除结点C,只需 4
5
链表需要动态地进行存储分配,在C语言中, 使用以下函数进行动态存储分配和释放。
1、void * malloc(size_t size) 在动态存储区分配长度为size的连续空间,