第7关:编写程序输入n个整数链式存放并输出最大值
- 任务要求
- 参考答案
- 评论3
任务描述
本关任务:编写程序,输入n
个整数链式存放并输出最大值。
相关知识
在计算机中,除了用一组地址连续的存储单元存放数据,还可以用一组地址不连续的存储单元存储数据,这种存放数据的结构,称作链式存储结构。 链式存储结构是一种动态地进行存储分配的数据结构,优点是不需要事先确定最大长度,在插入或者删除元素时,也不会引起数据的大量移动;缺点是只能顺序访问链表中的元素,不能随机存取数据。
设有4
个相同类型的数据A
、B
、C
、D
,这4
个数据类型可以是数值型、字符串型或自定义的结构体类型,它们的顺序存储结构和链式存储结构的示意图如图 1 所示。
设计一个单链表的结点结构如下:
链式存储结构中,每个元素称为一个结点,每个结点都可存储在内存中不同的位置,为了表示每个元素与后继元素之间的逻辑关系,以便构成一个结点链着一个结点的链式存储结构,每个结点都包含两个部分:第 1 部分是数据域,用来存储元素本身的数据信息,这里用data
表示;第 2 部分是指针域,用来存储下一个结点的地址,这里用next
表示。如此串连下去直到最后一个结点,最后一个结点称为“表尾”,该结点的指针域值为 0,指向内存中编号为零的地址(常用符号常量 NULL 表示,称为空地址),表尾不再有后继结点。
举例说明,输入3
个整数,链式存放,定义链表的结点类型如下:
struct Node
{
int data;
struct Node *next;
} ;
typedef struct Node LNode;
typedef struct Node * LinkList;
data
成员用于存放输入的整数,next
成员用于存放下一个结点的地址。
如果结点的类型定义采用如下方法,系统编译能不能通过?
struct Node
{
int data;
struct Node next;
};
系统编译不能通过,结构体声明时不能包含本结构体类型成员,这是因为本结构体类型尚未定义结束,它所占用的内存单元的字节数尚未确定,因此系统无法为这样的结构体成员分配内存。结构体声明时,可以包含本结构体类型的指针成员。 因为指针其实就是地址,与它所指的基类型无关, 只与机器有关。 如果你的机器是16
位寻址的,那指针就是16
位的,2
个字节;如果是32
位寻址的,指针也是32
位的,4
个字节;如果寻址是64
位的,指针也是64
位,8
个字节。
/**********创建3个结点存放3个整数 **********/
/**********创建3个结点存放3个整数 **********/
LNode * p1, * p2, * p3;
p1=( LNode *)malloc(sizeof(LNode)); //申请动态内存
if(p1==NULL) //对动态内存分配是否成功进行检测
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d",&p1->data); //将输入的整数存放在结点的data域
/**********申请动态内存的同时并且检测**********/
if ( ( p2 = (LNode *)malloc(sizeof(LNode) ) ) == NULL )
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d",&p2->data); //将输入的整数存放在结点的data域
if( (p3 = (LNode t *)malloc(sizeof(LNode)) ) == NULL)
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d", &p3->data ); //将输入的整数存放在结点的data域
/**********将3个结点连接起来 **********/
p1->next = p2; //将p2链接在p1后
p2->next = p3; //将p3链接在p2后
p3->next = NULL; // p3后没有结点
结点链接后通过p1
,能找到p2
,通过p2
,能找到p3
。p2
,p3
的值不重要了,重要的是p1
的值不能丢。改进上述操作,用循环语句来完成建立链表:
/**********循环建立3个结点的链表**********/
LNode * p1, * p2, *head;
if ( ( p1 = (LNode *)malloc(sizeof(LNode) ) ) == NULL ) //创建第1个结点
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d",&p1->data);
head = p1;
for(i=1;i<3;i++) //循环创建其余结点
{
if ( ( p2 = (LNode *)malloc(sizeof(LNode) ) ) == NULL )
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d",&p2->data);
p1->next = p2;
p1 = p2;
}
p2->next=NULL; //将链表最后一个结点指针域置为空值
}
如果希望将第1
个结点的创建也在循环语句里进行,可以在第1
个结点之前附设一个头结点,单链表有带头结点和不带头结点之分:
在链表的开始结点之前附加一个结点,并称它为头结点,头结点的数据成员不用来存放数据,那么会带来以下两个优点:
- 由于存放第一个数据元素结点的位置被存放在头结点的指针域中,所以在链表的第一个位置上的操作就和在表的其它位置上的操作一致,无需进行特殊处理;
- 无论链表是否为空,其头指针是指向头结点的非空指针,空表中头结点的指针域为空,因此空表和非空表的处理也就统一了。
LNode * p1, * p2, *head;
if ( ( head = (LNode *)malloc(sizeof(LNode) ) ) == NULL ) //创建头结点
{
printf("不能成功分配存储空间。\n");
exit(1);
}
p1 = head;
for(i=0; i<3; i++) //循环创建其余结点
{
if ( ( p2 = (LNode *)malloc(sizeof(LNode) ) ) == NULL )
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d",&p2->data);
p1->next = p2;
p1 = p2; //p1始终指向链表最后一个结点
}
p2->next=NULL; //将链表最后一个结点指针域置为空值
}
上述创建单链表的方法称为尾插法,将建立单链表的操作模块化,定义创建带头结点的单链表的函数:
void CreateTailList(LinkList L, int n)
{
LNode *p,* tail;
int i,x;
tail = L; //设置尾指针,方便插入
for(i=0; i<n; i++) //循环创建其余结点
{
if ( ( p = (LNode *)malloc(sizeof(LNode) ) ) == NULL )
{
printf("不能成功分配存储空间。\n");
exit(1);
}
scanf("%d",&p->data);
tail ->next = p;
tail = p; //p1始终指向链表最后一个结点
}
p->next=NULL; //将链表最后一个结点指针域置为空值
}
请模仿单链表的创建函数定义,输出单链表的函数及销毁带头结点的单链表的函数。
编程要求
根据提示,在右侧编辑器 Begin-End 区间补充代码,完成子函数的自定义,实现输入n
个整数链式存放并输出最大值。
测试说明
平台会对你编写的代码进行测试。
测试输入: 4
64
25
17
83
输入说明: 第一个数字为整数个数; 第一个数字后面的数字为整数的具体值。
预期输出: max=83
开始你的任务吧,祝你成功!
#include<stdio.h>
#include<stdlib.h>
struct Node//定义链表的结点类型
{
int data;
struct Node *next;
} ;
typedef struct Node LNode;
typedef struct Node * LinkList;
void CreateTailList (LinkList L,int n);
void OutputList(LinkList L); //输出带头结点的单链表
void DestroyList(LinkList L); //销毁带头结点的单链表
int MaxList(LinkList L); //求带头结点的单链表最大值
int main()
{
LinkList head; //定义一个LinkList 型的变量head
int n;
if( ( head = (LNode *) malloc( sizeof(LNode) ) ) == NULL)
{
printf("申请空间失败!");
exit(0);
}
head ->next=NULL; //在函数体外创建单链表的头结点head
scanf("%d",&n);
CreateTailList ( head,n); //用尾插法输入数据创建单链表
//OutputList(head); //输出以head为头的链表各结点的值
printf("max=%d\n", MaxList(head) );
DestroyList (head); //销毁以head为头的链表各结点
}
/********** 定义CreateTailList()函数 **********/
/********** Begin **********/
void CreateTailList( LinkList L,int n)
{
LNode *p,*tail;
int i,x;
tail=L;
for(i=0;i<n;i++)
{
p=(LNode*)malloc(sizeof(LNode));
scanf("%d",&p->data);
tail->next=p;
tail=p;
}
p->next=NULL;
}
/********** End **********/
/**********定义DestroyList()函数**********/
void DestroyList (LinkList head)
{
/********* Begin **********/
free(head);
/********** End **********/
}
/**********定义MaxList ()函数**********/
int MaxList(LinkList L)
{
/********** Begin **********/
int max=0;
LNode *p;
p=L->next;
while(L)
{
L=L->next;
if(max<p->data)
max=p->data;
p=L;
}
return max;
/********** End **********/
}