链表的基本操作
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
q
x
D3
D2
D1
D0 ^
head 表头节点 数据节点 数据节点 数据节点 数据节点
p
链表基础
例:在链表的第i个节点的后面插入新节点p(程序)
insert_node ( NODE * head , NODE * p , int i )
{ NODE * q;
int n=0;
for ( q = head; n<i && q->link!=NULL; ++n )
/* head指向表头节点 p */
P指向最后 一个结点
p
head
NULL
表头指针
表头节点
(不含数据节点的空链表)
链表基础
加入第一个数据结点 NODE * p; p = ( NODE * ) malloc ( sizeof (NODE) ) ; /* 申请新数据结点 */ gets(p->name );gets(p->address);gets(p->phone ); /* 用访问结构的方法将数据读入p所指向的结点成员 */ p->link = NULL; /*将NULL存入p的link中 */ head->link = p; /* 将数据结点 p 插在表头结点之后 */
x
-1
head 表头
for ( i=30; i>0; i-- )
{ p = (struct node *)malloc(sizeof(struct node));
p->no = i;
p->next = head->next;
head->next = p;
}
p
30 p
-1 head 表头
1
2
...
数据结点 数据结点
原型:void * malloc(int size) 功能:动态分配长度为size个字节的存储区。 返回值:分配成功,返回所分配区域的首地址。
分配失败,返回 0 。 注意:一般系统返回指向void型数据的指针,而应用时需要指向
结构类型的指针,所以要用强制类型转换。
例如: struct student * ps; ps=(struct student *)malloc(sizeof(struct student));
链表基础
3、访问链表中全部数据节点
wk.baidu.com
output ( NODE * head ) { NODE * p; p = head->link;
while ( p!=NULL )
/* p 指向第一个数据节点 */
{
puts ( p->name ) ;
p = p->link ;
}
}
需要分析两种情况:
/* 输出 p 所指向节点的数据 */ /* p 指向下一个数据节点 */
链表基础
申请存储空间建立表头节点 NODE * p;
将malloc的返回值强 制转换为NODE型
p = ( NODE * ) malloc ( sizeof (NODE) ) ;
/* 开辟新存储区,申请表头节点 */
p->link = NULL; /* 将表头节点的link置为NULL*/
head = p;
p head
表头指针
NULL
表头节点
name NULL
数据节点
链表基础
从表头开始将数据节点插入链表中(插下一个数据节点) p = ( NODE * ) malloc ( sizeof (NODE) ) ; /* 申请数据节点 */
gets(p->name); gets(p->address);gets(p->phone );
int no; struct node * next; };
head
表头
1
2
...
数据结点 数据结点
29
30
数据结点 数据结点
链表基础
main( ) { int i, k; struct node *head, *p, *q;
head = (struct node *)malloc(sizeof(struct node)); head->no = -1; head->next = head;
链表基础
释放内存函数 原型:void free(void *p)
头文件:stdlib.h 功能:释放p所指向的内存空间 返回值:无 例如: free(ps); ps是最近一次调用 malloc函数时返回的值
链表基础
(3) 创建链表的过程
定义结点的结构,说明表头指针
例如:定义描述学生(姓名/住址/电话)的结点
head
NULL
head
表头指针
表头节点
表头指针
表头节点
name1 NULL 数据节点
链表基础
4、在链表中插入新节点(基本原理) 定位—— 指针 q 指向第 i 个节点,指针 p 指向需要插入 的节点 ◆ 链接后面指针—— p->link = q->link ;
◆ 链接前面指针—— q->link = p ;
...
29
30
数据结点 数据结点
/* p 指向 30 */
p
-1 head 表头
1
2
...
数据结点 数据结点
29
30
数据结点 数据结点
链表基础
p
-1
1
2
...
29
30
head 表头 数据结点 数据结点
数据结点 数据结点
for ( i=0; i<15; i++ )
{ for ( k=1 ; k<9 ; k++ )
/* 按照访问结构的方法,将数据存入p所指向的节点 */
p->link = head->link;
/* 将表头节点的link存入 p 的link中 */
head->link = p;
/* 将数据结点 p 插在表头结点之后 */
head
表头指针
p
表头节点
name2
数据节点
x name1 NULL
数据节点
q = q->link; p->link = q->link; q->link = p;
/* ① 定位 */ /* ② 链接后面指针 */ /* ③ 链接前面指针 */
}
特殊情况:
在空表中(0的后面)插入新节点
q
^
p
^
head 表头节点
链表基础
5、在链表中删除第 i 个节点(基本原理) 定位—— 指针 q 指向第 i-1 个节点,指针 p 指向被删 除的节点 ◆ 摘链—— q->link = p->link ;
29
30
数据结点 数据结点
链表基础
p
-1
1
2
...
29
30
head 表头 数据结点 数据结点
数据结点 数据结点
while ( p->next != head ) /* 循环链跳过表头结点 */
p = p->next;
p
-1
1
2
head 表头 数据结点 数据结点
p->next = head->next;
1 创建单向链表
链表基础
创建步骤: 定义结点的结构类型,说明表头指针 按照结构的大小分配一块内存区域 将该区域的首地址赋给一个头指针 继续分配一块内存区域 将该区域的首地址分配给前一个结点的指针变量 继续上述过程,直到链表的尾。
链表基础
(2) 两个重要的库函数 动态存储分配函数 (头文件:stdlib.h)
◆ 释放 p节点—— free ( p );
x
D3
D2
D1
D0 ^
head 表头节点 数据节点 数据节点 数据节点 数据节点
q
p
常见形式
head
D3
D2
表头节点 数据节点 数据节点
有表头节点的单向链表
D1
D0 ^
数据节点 数据节点
head
D4
D3
D2
数据节点 数据节点 数据节点
无表头节点的单向链表
D1
D0 ^
数据节点 数据节点
head
D3
D2
表头节点 数据节点 数据节点
有表头节点的单向环表
D1
D0
数据节点 数据节点
head
D4
D3
D2
数据节点 数据节点 数据节点
无表头节点的单向环表
D1
D0
数据节点 数据节点
链表基础
约瑟夫问题 这是十七世纪的法国数学家加斯帕在《数目的游戏问题》
中讲的一个故事: 15个基督教徒和15个异教徒在海上遇险,必须将一半的人
struct node
{ char name[20],address[20],phone[15];
struct node * link;
/*定义node型结构指针 */
};
/* 定义结构 */
typedef struct node NODE
/* 定义结点类型 */
NODE * head ;
/* 说明头指针head */
p = p->next;
q = p->next;
/* p 的下一个结点是要出列的结点 */
p->next = q->next; /* 循环链表跳过要出列的结点 */
printf(“%3d”, q->no); /* 输出 q 结点的编号 */
free(q);
/* 释放 q 结点 */
}
-1 head 表头
投入海中,其余的人才能幸免于难,于是想了一个办法:30 个人围成一个圆圈,从第一个人开始依次报数,每数到第 9 个人就将他扔入大海,如此循环进行直到仅余 15 人为止。
问怎样排法,才能使每次投入大海的都是异教徒。
链表基础
约瑟夫(Josephus)问题 n个人围成一个圆圈,从第s个
人开始报数,数到第m的人出 列,然后从出列的下一个人重新开始报数,数到第m的人又出 列,如此反复直到所有的人全部出列为止。Josephus问题是: 对于任意给定的n,s和m,求出按出列次序得到的n个人员的序 列。
(d) n4 n8 n5 n2
链表基础
(e) n4 n8 n5 n2 n1
(f) n4 n8 n5 n2 n1 n3
(g) n4 n8 n5 n2 n1 n3 n7 (h) n4 n8 n5 n2 n1 n3 n7 n6
链表基础
用链表的方法对约瑟夫问题进行编程 算法分析与设计
用链表解决约瑟夫问题,首先定义链表数据结构 struct node {
以n=8,s=1,m=4为例,问题的求解过程如下列图所示。图 中s1指向开始报数位置,带圆圈的是本次应出列人员。若初 始顺序为n1,n2,n3,n4,n5,n6,n7,n8,则问题的解为 n4,n8,n5,n2,n1,n3,n7,n6。
链表基础
(a) n4
(b) n4 n8
(c) n4 n8 n5
x
D3
D2
D1
D0 ^
head 表头节点 数据节点 数据节点 数据节点 数据节点
p
链表基础
例:在链表的第i个节点的后面插入新节点p(程序)
insert_node ( NODE * head , NODE * p , int i )
{ NODE * q;
int n=0;
for ( q = head; n<i && q->link!=NULL; ++n )
/* head指向表头节点 p */
P指向最后 一个结点
p
head
NULL
表头指针
表头节点
(不含数据节点的空链表)
链表基础
加入第一个数据结点 NODE * p; p = ( NODE * ) malloc ( sizeof (NODE) ) ; /* 申请新数据结点 */ gets(p->name );gets(p->address);gets(p->phone ); /* 用访问结构的方法将数据读入p所指向的结点成员 */ p->link = NULL; /*将NULL存入p的link中 */ head->link = p; /* 将数据结点 p 插在表头结点之后 */
x
-1
head 表头
for ( i=30; i>0; i-- )
{ p = (struct node *)malloc(sizeof(struct node));
p->no = i;
p->next = head->next;
head->next = p;
}
p
30 p
-1 head 表头
1
2
...
数据结点 数据结点
原型:void * malloc(int size) 功能:动态分配长度为size个字节的存储区。 返回值:分配成功,返回所分配区域的首地址。
分配失败,返回 0 。 注意:一般系统返回指向void型数据的指针,而应用时需要指向
结构类型的指针,所以要用强制类型转换。
例如: struct student * ps; ps=(struct student *)malloc(sizeof(struct student));
链表基础
3、访问链表中全部数据节点
wk.baidu.com
output ( NODE * head ) { NODE * p; p = head->link;
while ( p!=NULL )
/* p 指向第一个数据节点 */
{
puts ( p->name ) ;
p = p->link ;
}
}
需要分析两种情况:
/* 输出 p 所指向节点的数据 */ /* p 指向下一个数据节点 */
链表基础
申请存储空间建立表头节点 NODE * p;
将malloc的返回值强 制转换为NODE型
p = ( NODE * ) malloc ( sizeof (NODE) ) ;
/* 开辟新存储区,申请表头节点 */
p->link = NULL; /* 将表头节点的link置为NULL*/
head = p;
p head
表头指针
NULL
表头节点
name NULL
数据节点
链表基础
从表头开始将数据节点插入链表中(插下一个数据节点) p = ( NODE * ) malloc ( sizeof (NODE) ) ; /* 申请数据节点 */
gets(p->name); gets(p->address);gets(p->phone );
int no; struct node * next; };
head
表头
1
2
...
数据结点 数据结点
29
30
数据结点 数据结点
链表基础
main( ) { int i, k; struct node *head, *p, *q;
head = (struct node *)malloc(sizeof(struct node)); head->no = -1; head->next = head;
链表基础
释放内存函数 原型:void free(void *p)
头文件:stdlib.h 功能:释放p所指向的内存空间 返回值:无 例如: free(ps); ps是最近一次调用 malloc函数时返回的值
链表基础
(3) 创建链表的过程
定义结点的结构,说明表头指针
例如:定义描述学生(姓名/住址/电话)的结点
head
NULL
head
表头指针
表头节点
表头指针
表头节点
name1 NULL 数据节点
链表基础
4、在链表中插入新节点(基本原理) 定位—— 指针 q 指向第 i 个节点,指针 p 指向需要插入 的节点 ◆ 链接后面指针—— p->link = q->link ;
◆ 链接前面指针—— q->link = p ;
...
29
30
数据结点 数据结点
/* p 指向 30 */
p
-1 head 表头
1
2
...
数据结点 数据结点
29
30
数据结点 数据结点
链表基础
p
-1
1
2
...
29
30
head 表头 数据结点 数据结点
数据结点 数据结点
for ( i=0; i<15; i++ )
{ for ( k=1 ; k<9 ; k++ )
/* 按照访问结构的方法,将数据存入p所指向的节点 */
p->link = head->link;
/* 将表头节点的link存入 p 的link中 */
head->link = p;
/* 将数据结点 p 插在表头结点之后 */
head
表头指针
p
表头节点
name2
数据节点
x name1 NULL
数据节点
q = q->link; p->link = q->link; q->link = p;
/* ① 定位 */ /* ② 链接后面指针 */ /* ③ 链接前面指针 */
}
特殊情况:
在空表中(0的后面)插入新节点
q
^
p
^
head 表头节点
链表基础
5、在链表中删除第 i 个节点(基本原理) 定位—— 指针 q 指向第 i-1 个节点,指针 p 指向被删 除的节点 ◆ 摘链—— q->link = p->link ;
29
30
数据结点 数据结点
链表基础
p
-1
1
2
...
29
30
head 表头 数据结点 数据结点
数据结点 数据结点
while ( p->next != head ) /* 循环链跳过表头结点 */
p = p->next;
p
-1
1
2
head 表头 数据结点 数据结点
p->next = head->next;
1 创建单向链表
链表基础
创建步骤: 定义结点的结构类型,说明表头指针 按照结构的大小分配一块内存区域 将该区域的首地址赋给一个头指针 继续分配一块内存区域 将该区域的首地址分配给前一个结点的指针变量 继续上述过程,直到链表的尾。
链表基础
(2) 两个重要的库函数 动态存储分配函数 (头文件:stdlib.h)
◆ 释放 p节点—— free ( p );
x
D3
D2
D1
D0 ^
head 表头节点 数据节点 数据节点 数据节点 数据节点
q
p
常见形式
head
D3
D2
表头节点 数据节点 数据节点
有表头节点的单向链表
D1
D0 ^
数据节点 数据节点
head
D4
D3
D2
数据节点 数据节点 数据节点
无表头节点的单向链表
D1
D0 ^
数据节点 数据节点
head
D3
D2
表头节点 数据节点 数据节点
有表头节点的单向环表
D1
D0
数据节点 数据节点
head
D4
D3
D2
数据节点 数据节点 数据节点
无表头节点的单向环表
D1
D0
数据节点 数据节点
链表基础
约瑟夫问题 这是十七世纪的法国数学家加斯帕在《数目的游戏问题》
中讲的一个故事: 15个基督教徒和15个异教徒在海上遇险,必须将一半的人
struct node
{ char name[20],address[20],phone[15];
struct node * link;
/*定义node型结构指针 */
};
/* 定义结构 */
typedef struct node NODE
/* 定义结点类型 */
NODE * head ;
/* 说明头指针head */
p = p->next;
q = p->next;
/* p 的下一个结点是要出列的结点 */
p->next = q->next; /* 循环链表跳过要出列的结点 */
printf(“%3d”, q->no); /* 输出 q 结点的编号 */
free(q);
/* 释放 q 结点 */
}
-1 head 表头
投入海中,其余的人才能幸免于难,于是想了一个办法:30 个人围成一个圆圈,从第一个人开始依次报数,每数到第 9 个人就将他扔入大海,如此循环进行直到仅余 15 人为止。
问怎样排法,才能使每次投入大海的都是异教徒。
链表基础
约瑟夫(Josephus)问题 n个人围成一个圆圈,从第s个
人开始报数,数到第m的人出 列,然后从出列的下一个人重新开始报数,数到第m的人又出 列,如此反复直到所有的人全部出列为止。Josephus问题是: 对于任意给定的n,s和m,求出按出列次序得到的n个人员的序 列。
(d) n4 n8 n5 n2
链表基础
(e) n4 n8 n5 n2 n1
(f) n4 n8 n5 n2 n1 n3
(g) n4 n8 n5 n2 n1 n3 n7 (h) n4 n8 n5 n2 n1 n3 n7 n6
链表基础
用链表的方法对约瑟夫问题进行编程 算法分析与设计
用链表解决约瑟夫问题,首先定义链表数据结构 struct node {
以n=8,s=1,m=4为例,问题的求解过程如下列图所示。图 中s1指向开始报数位置,带圆圈的是本次应出列人员。若初 始顺序为n1,n2,n3,n4,n5,n6,n7,n8,则问题的解为 n4,n8,n5,n2,n1,n3,n7,n6。
链表基础
(a) n4
(b) n4 n8
(c) n4 n8 n5