收藏 分享(赏)

C++第六章结构和链表.ppt

上传人:hyngb9260 文档编号:8386565 上传时间:2019-06-23 格式:PPT 页数:39 大小:198KB
下载 相关 举报
C++第六章结构和链表.ppt_第1页
第1页 / 共39页
C++第六章结构和链表.ppt_第2页
第2页 / 共39页
C++第六章结构和链表.ppt_第3页
第3页 / 共39页
C++第六章结构和链表.ppt_第4页
第4页 / 共39页
C++第六章结构和链表.ppt_第5页
第5页 / 共39页
点击查看更多>>
资源描述

1、1,第六章 结构和链表,6.1 结构类型 6.2 结构的应用-链表 6.3 应用举例,2,6.1 结构类型,6.1.1 结构类型说明,C语言提供了这样一种数据结构:它将不同类型的数据组合成一个有机的整体结构体。,3,struct date int month;int day;int year; ;,struct man char name15;char sex;int age;date birthday; ;,如,说明一个结构类型date,含三个整型数据成员,在此基础上,又可说明另一个结构类型man,birthday,Name,sex,age,month,day,year,struct man

2、,结构类型,4,6.1.2 结构变量定义及初始化,先说明结构类型再定义结构变量 在说明结构数据类型的同时定义结构变量 省略结构标识符直接定义结构类型变量,struct man man1, man2;,struct man char name15; char sex; int age;struct date birthday; man1, man2;,struct char name15; char sex; int age;struct date birthday; man1, man2;,无类型名变量,5,struct goods /定义一个商品结构类型 char bh6; /商品编号cha

3、r mc20; /商品名称float dj; /商品单价int sl; /商品数量char jhrq8; /进货日期 g1=“10012“, “shoes“, 124,100, “080912“;,结构变量也允许在定义的同时给出初值,即初始化。如:,struct person char name15;char sex;int age;s10 =“Fang Min“,F,24, “Fang Hua“,M,35;,定义一个结构数组并对其部分元素初始化。,6,6.1.3 结构变量的访问,访问形式:,结构变量名.成员名 (*指向结构的指针).成员名指向结构的指针-成员名,或,或,通过指向结构的指针引用

4、结构变量成员,成员访问运算符 优先级最高的 四个运算符之一,括号不能少,如,假设有定义man m,*p=,strcpy (m.name, “Fang Min“); p-birthday.month = 8;,则可如下引用结构成员,7,【例6.1】某商场周年店庆期间对其会员进行积分换购活动,活动内容为允许每天前五名光临的会员用其积分换购相应的商品,假设每100个积分可以换购5元的商品,编程序求该商场店庆期间每天换购出去的商品金额以及会员换购后的剩余积分值。假设会员将全部可能积分全部进行换购。 分析:可以将会员卡号和积分组合在一起定义一个结构类型,用结构数组来描述若干会员的信息。如,struct

5、card char num10;int score;c10;,8,#include “iostream.h“ #define N 5 void main( ) struct card char num10;int score;cN;int i,s=0;for(i=0;ici.numci.score;s=s+5*(ci.score/100); /每100分换购5元商品ci.score=ci.score-100*(ci.score/100); /该会员的剩余积分cout“扣除积分后:n“;for(i=0;iN;i+)coutci.numtci.scoreendl;cout“积分换购金额=“send

6、l; ,9,链表是一种线性表。一个线性表是n(n0)个数据元素的有限序列。在计算机中,线性表可以选择连续存储和链接存储。连续存储把数据元素一个接一个地放在一组连续的存储单元之中,也就是把线性表中的数据元素存放在一片连续的存储域。连续存储的线性表称为数组。因为数组的长度是固定的,而线性表的元素个数通常是不确定的,所以通常将数组定义成充分大,但这样会造成存储空间的浪费。用数组存储线性表的另一个缺点是在进行插入和删除操作时需要移动数据。,6.2 结构的应用链表,10,链接存储链接存储的线性表称为链表。元素之间靠指针链接。,特点每个元素(结点node)由数据域data和指针域next构成,其中指针域指

7、向下一个元素的首地址,最后一个元素的指针为NULL。结点之间可以连续,可以不连续存储; 结点的逻辑顺序与物理顺序可以不一致; 表可根据需要动态扩充。,11,下图是一个具有5个数据元素(称为结点)的线性链表(单向链表)。每一个线性链表都有一个表头指针(head),如果链表是非空链表,则存放第一个结点的起始地址,否则head=NULL。,2238 46 58 94,存储地址 数据域 指针域,38,head,12,链表中的每一个结点都是结构类型的变量,应包含两个部分:数据域和指针域(即下一个结点的地址)。前面图中的结点和表头指针的类型可以这样说明:struct node int data;struc

8、t node *next;struct node *head;,/指向它所属的结构类型,13,链表的常见操作有: 1. 建立链表; 2. 输出链表; 3. 确定链表的长度,即统计链表中结点的个数; 4. 查找链表中的某个结点; 5. 在链表中插入一个新的结点; 6. 删除链表中的某个结点。,14,6.2.1 链表的基本操作方法,1生成结点变量当向链表中加入新数据时,需要生成一个新结点以存放要加入的新数据。为此,首先要为新结点申请存放空间,有两种常用方法:使用malloc函数分配空间 假设有定义: struct node int data;struct node *next; *p; /此时p尚

9、没明确的指向单元则使用如下语句可使p指向一个node类型的结点:p=(struct node *)malloc(sizeof(node);,15,关于函数malloc的说明: 功能是分配一个类型为node的结点变量的空间,并返回其首地址。 对该函数的原型说明包含在头文件stdlib.h中。 sizeof是一个求字节数的运算,malloc函数的参数中要给出申请空间的大小。使用new运算符分配空间 p=new node; 该方法使用起来更加简单,但C语言中不支持此方法。为方便起见,本书中的程序多采用后一种方式来为新结点申请存放空间。,16,2释放结点变量空间当删除链表中的结点时,也应该及时地将其占

10、用的存储空间返还给内存。假设下图中p所指向的结点是要删除的结点,则相对应用malloc函数分配的空间,可以用如下语句释放。free(p); 其中free是个函数,其原型说明也包含在头文件“stdlib.h”中。相对应用new运算符申请的空间,则用如下语句释放。delete p;,17,3结点分量的访问 由于在链表中各个结点之间的联系是靠指针域来实现的,所以对结点各成员的访问也是利用指向结点的指针变量来进行的。对p所指向的结点的数据域的访问:(*p).data 或 p-data /多以后一种方式为常见对p所指向的结点的指针域的访问:(*p).next 或 p-next /多以后一种方式为常见,1

11、8,【例6.2】假设node是前面已经定义过的结构类型,又有定义node *p, *q,则建立一个如下图所示的包含两个结点的链表。,建立第一个结点需要两步操作。首先为其申请存放空间,然后为其数据域赋值 建立第二个结点。除了和建立第一个结点相同的两步操作外,因为它是链表中的最后一个结点,因此还要将其指针域置为空。 将第二个结点连接到第一个结点之后,即让第一个结点的指针域指向第二个结点。,19,/或p=(struct node *)malloc(sizeof(struct node); /为第二个结点的指针域赋值,10,20,p=new node;,p-data=10;,q=new node;,q

12、-data=20;,NULL,q-next=NULL,p-next=q;,20,6.2.2 链表的建立,【例6.3】创建一个含有n个结点的、包含一个数据域,且其类型为整型的单链表。链表的建立过程如下: 首先设置head为NULL,即建立一个空的链表。 申请一个新结点存储区域,让newnode指向该结点,然后向其数据域输入数据。 把newnode所指向的结点插入到链表中。 如果当前链表是空表,newnode所指向的结点应该成为该链表中唯一的一个结点,故head和tail都应该指向该结点。,21,如果当前链表非空,则newnode所指向的结点应该做为链表中的最后一个结点加入到链表中,故应该将其插在

13、tail指向的结点后面。 重复执行第2、3步共n次。 将最后一个结点的next域置空(NULL)。,22,#include “iostream.h“ struct node int data; struct node *next; ; struct node *create(int n ) struct node *head = NULL;struct node *tail,*newnode;int x;for (int i=0; ix;newnode= ; /为newnode申请存放空间newnode-data=x;,new node,也可用如下语句 newnode=( struct nod

14、e *)malloc(sizeof( struct node);,23,if(head=NULL); /newnode成为空表的第一个结点else;/将newnode连接到原来的表尾; / newnode成为新的表尾tail-next=NULL;return(head); void main( ) struct node *head;int n;coutn;head = create(n); ,head=newnode,tail-next=newnode,tail = newnode,24,6.2.3 单链表的基本操作,1、链表的遍历,由于链表的指针域中包含了后继结点的存储地址,所以只要知道该

15、链表的头指针,即可依次对每个结点进行访问。 【例6.4】输出上例中建立的单链表的各结点的值。假设定义p是指向链表中结点的工作指针,该指针从表头head开始逐一指向后续的各个结点,每指向一个结点,便通过该指针访问结点的数据域,直到p的值为NULL。,25,遍历的函数实现如下: void print(struct node *head) struct node *p=head;while(p!=NULL)coutdatat; /注意不能通过p+实现 指针后移 ,p = p-next,26,2、 统计结点个数,【例6.5】统计例6.3中创建的链表中结点的个数。设置一个工作指针从表头结点开始,每经过一

16、个结点,计数器的值增加1。实现统计的函数形式如下: int count(struct node *head) struct node *p = head;int n = 0;while (p != NULL)n+;p = p-next;return(n); ,27,3、查找结点,【例6.6】在链表中按序号查找第i个结点。设置一个序号计数器j和一个工作指针p,从表头结点开始,顺着链表的链进行查找。仅当j=i并且p!= NULL时查找成功,否则查找不成功。,28,void search(struct node *head, int i) int j=1;struct node *p=head;if

17、(idata;else cout“illegal index n“; ,p=p-next,j=i&p!=NULL,29,4、在链表中插入结点,假定有一个指针behind 指向链表中的某个结点,newnode指向待插入结点。,newnode,12,10 15 19,behind,front,如果有一个指针front指向behind的前驱,则仅需编写下面的两个语句,即可实现插入。 ; ;如果没有behind指针,插入操作仍然可以完成。newnode-next=front-next;front-next=newnode; 思考题:上述两个语句的次序能否交换?为什么?,newnode-next=beh

18、ind,front-next=newnode,30,两种特殊情况: 1. 在表头结点之前插入:;2. 在尾结点之后插入:;,newnode,head,behind,6,7,newnode,8,【例6.7】编写函数,实现在头结点为head的链表中插入值为x的结点。,newnode-next=behind,head=newnode,behind-next=newnode,NULL,newnode-next=NULL,31,struct node * insert(node *head,int x) struct node *behind,*front,*newnode;newnode=new no

19、de;newnode-data=x; behind=head;if(head=NULL) /空表 head=newnode; newnode-next=NULL; else /非空表 while(behind!=NULL ,32,5、删除链表中的某个结点,删除链表中的某个结点,是把被删除结点的后继结点的地址,赋给其前趋结点的指针域或表头指针head,无后继结点时,则赋NULL。,假定p为指向要删除结点的指针,q为指向删除结点前趋的指针。如果p=head,则删除的是第一个结点,则应修改表头指针head,使其指向第二个结点,并释放第一个结点占据的存储空间。,head=p-next; delete

20、p;,33,如果删除的是链表的中间结点,则应把被删除结点p的后继结点的地址,赋给其前趋结点q的指针域。如果没有后继结点时,则赋空指针NULL。,q-next=p-next ;delete p;,34,【例6.8】编写函数实现在头结点为head的链表中删除值为x的结点。 struct node *delnode(node *head,int x) struct node *p,*q; /p为工作指针,q为p的前驱p = head;if(head=NULL) /空表coutdata!= x) / 找删除的结点 q=p; p = p-next; if(p=head) /删除第一个结点 head=p-

21、next; delete p; else if(p!=NULL) /删除非表头结点 q-next=p-next ; delete p; else /未找到要删除的元素coutx“dose not exist in the list!n“;return head;,35,6.2.4带表头结点的单链表,表头结点(又称伪结点)位于表的最前端,本身不带数据,仅标志表头。 设置表头结点的目的是统一空表与非空表、表头和表中位置的操作形式,简化链表操作的实现。,非空表 空表,36,在带表头结点的单链表最前端插入新结点,newnode-next = p-link; p-next = newnode;,非空表,

22、空表,可见,空表和非空表的操作是一致的,无需再分别讨论,简化了操作。,37,q = p-next; p-next = q-next; delete q;,从带表头结点的单链表中删除最前端的结点,可见,即使删除后为空表,也无需修改head,与非空表操作一致,38,6.3 应用举例,【例6.9】建立一个带表头结点的单链表,要求每次都将最后加入的结点加到最前面,结点中的数据均是不为0的整数(要求输入0时建立过程结束),然后统计结点个数并输出结点中的所有数据。分析 根据题意,建立该链表的过程是不断向表头插入新结点的过程。考虑到题目要求建立的是一个含表头结点的单链表,因此新结点应加入到伪结点的后面,成为

23、第一个有效结点。,39,#include “iostream.h“ struct node int data;struct node *next; ; void main() struct node *head,*newnode,*p;int x,count=0;head=new node ;head-next=NULL;while(1) cinx;if(x=0) break;newnode=new node;newnode-data=x;newnode-next=NULL;newnode-next=head-next; /让新结点指向第一个有效结点head-next=newnode; /让新结点成为第一个有效结点 ,接while语句后p=head-next; while(p!=NULL)count+;coutdatanext;cout“count=“countendl; ,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报