单链表操作验证 验证型.docx
《单链表操作验证 验证型.docx》由会员分享,可在线阅读,更多相关《单链表操作验证 验证型.docx(15页珍藏版)》请在冰豆网上搜索。
单链表操作验证验证型
实验报告
课程名称数据结构
实验名称单链表实验验证
实验类型验证型
实验地点计405机房实验日期2017.4.28
指导教师魏海平
专业软件工程
班级软件1601
学号1611030102
姓名寇春雷
辽宁石油化工大学计算机与通信工程学院
数据结构实验报告评分表
项目
要求
分数
有无项目(√)
得分
预习报告
(30分)
实验目的明确
5
实验内容理解透彻
5
实验方案设计完整合理
程序总体框架设计完整
10
完成相关辅助代码
5
测试方案合理
5
实验过程
(30分)
发现问题
5
问题的分析
15
问题的解决方法
10
实验报告
(20分)
内容翔实无缺漏
5
如实记录实验过程
10
撰写规整
5
实验总结
(10分)
实验结果的分析
5
按照结果对原实验方案的改进意见
5
实验体会
(10分)
实验的收获
5
实验内容的发散考虑
5
总分
一.问题描述:
1.实验题目
单链表操作验证。
2.实验目的
(1)掌握线性表的链接存储结构。
(2)验证单链表及其基本操作的实现。
(3)进一步掌握数据结构及算法的程序实现的基本方法。
3.实验内容的理解
(1)用头插法(或尾插法)建立带头结点的单链表。
(2)对已建立的单链表实现按给定值和按序号对单链表进行插人、删除、查找和置逆等基本操作。
(3)对单链表进行初始化,建立带头节点的单链表,将单链表按其值非递归排序等操作。
4.实验要求
(1)采用标准C语言实现。
(2)对单链表操作前和操作后都要输出链表的内容。
(3)对要进行的操作有必要的提示信息。
(4)对实现的功能采用菜单的形式进行展示和选择。
二.设计
1.数据结构设计和核心算法设计描述。
2.主控及功能模块层次结构。
3.主要功能模块。
(1)主程序模块:
void main(){
初始化;
正序、逆序输出链表;
合并链表;
}
(2)集合单元模块——实现集合的抽象数据类型;
(3)单链表单元模块——实现单链表的抽象数据类型;
(4)结点结构单元模块——定义链表的结点结构;
4.功能模块之间的调用与被调用关系:
主程序模块
集合单元模块
单链表单元模块
结点结构单元模块
三.测试
(1)程序运行截图
(2)程序源码
#include"stdafx.h"
/*第一部包括必要的头函数并定义状态值*/
#include
#include
#include/*malloc()等*/
#include/*INT_MAX等*/
#include/*EOF(=^Z或F6),NULL*/NULLscanf();printf();
#include
#include/*eof()*/
#include
#include/*exit()*/
/*函数结果状态代码*/
#defineTRUE1
#defineFALSE0
#defineOK1
#defineERROR0
#defineINFEASIBLE-1
/*#defineOVERFLOW-2因为在math.h中已定义OVERFLOW的值为3,故去掉此行*/
typedefintStatus;/*Status是函数的类型,其值是函数结果状态代码,如OK等*/
typedefintBoolean;/*Boolean是布尔类型,其值是TRUE或FALSE*/
typedefintElemType;
/*第二部定义线性表的单链表存储结构*/
typedefstructLNode
{
ElemTypedata;
structLNode*next;
}LNode;
typedefstructLNode*LinkList;/*另一种定义LinkList的方法*/
/*第三部带有头结点的单链表(存储结构如上定义)的基本操作(12个)*/
voidInitList(LinkListL)
{/*操作结果:
构造一个空的线性表L*/
L=(LinkList)malloc(sizeof(LNode));/*产生头结点,并使L指向此头结点*/
if(!
L)/*存储分配失败*/
exit(OVERFLOW);
L->next=NULL;/*指针域为空*/
}
voidDestroyList(LinkListL)
{/*初始条件:
线性表L已存在。
操作结果:
销毁线性表L*/
LinkListq;
while(L)
{
q=L->next;
free(L);
L=q;
}
}
voidClearList(LinkListL)/*不改变L*/
{/*初始条件:
线性表L已存在。
操作结果:
将L重置为空表*/
LinkListp,q;
p=L->next;/*p指向第一个结点*/
while(p)/*没到表尾*/
{
q=p->next;
free(p);
p=q;
}
L->next=NULL;/*头结点指针域为空*/
}
StatusListEmpty(LinkListL)
{/*初始条件:
线性表L已存在。
操作结果:
若L为空表,则返回TRUE,否则返回FALSE*/
if(L->next)/*非空*/
returnFALSE;
else
returnTRUE;
}
intListLength(LinkListL)
{/*初始条件:
线性表L已存在。
操作结果:
返回L中数据元素个数*/
inti=0;
LinkListp=L->next;/*p指向第一个结点*/
while(p)/*没到表尾*/
{
i++;
p=p->next;
}
returni;
}
StatusGetElem(LinkListL,inti,ElemType*e)/*算法2.8*/
{/*L为带头结点的单链表的头指针。
当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR*/
intj=1;/*j为计数器*/
LinkListp=L->next;/*p指向第一个结点*/
while(p&&j
{
p=p->next;
j++;
}
if(!
p||j>i)/*第i个元素不存在*/
returnERROR;
*e=p->data;/*取第i个元素*/
returnOK;
}
intLocateElem(LinkListL,ElemTypee,Status(*compare)(ElemType,ElemType)){/*初始条件:
线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0)*/
/*操作结果:
返回L中第1个与e满足关系compare()的数据元素的位序*/
/*若这样的数据元素不存在,则返回值为0*/
inti=1;
LinkListp=L->next;
while(p)
{
i++;
if(compare(p->data,e))/*找到这样的数据元素*/
returni;
p=p->next;
}
return0;
}
StatusPriorElem(LinkListL,ElemTypecur_e,ElemType*pre_e)
{/*初始条件:
线性表L已存在*/
/*操作结果:
若cur_e是L的数据元素,且不是第一个,则用pre_e返回它的前驱,*/
/*返回OK;否则操作失败,pre_e无定义,返回INFEASIBLE*/
LinkListq,p=L->next;/*p指向第一个结点*/
while(p->next)/*p所指结点有后继*/
{
q=p->next;/*q为p的后继*/
if(q->data==cur_e){
*pre_e=p->data;
returnOK;
}
p=q;/*p向后移*/
}
returnINFEASIBLE;
}
StatusNextElem(LinkListL,ElemTypecur_e,ElemType*next_e)
{/*初始条件:
线性表L已存在*/
/*操作结果:
若cur_e是L的数据元素,且不是最后一个,则用next_e返回它的后*/
/*返回OK;否则操作失败,next_e无定义,返回INFEASIBLE*/
LinkListp=L->next;/*p指向第一个结点*/
while(p->next)/*p所指结点有后继*/
{
if(p->data==cur_e){
*next_e=p->next->data;
returnOK;
}
p=p->next;
}
returnINFEASIBLE;
}
StatusListInsert(LinkListL,inti,ElemTypee)/*算法2.9。
不改变L*/
{/*在带头结点的单链线性表L中第i个位置之前插入元素e*/
intj=0;
LinkListp=L,s;
while(p&&j{
p=p->next;
j++;
}
if(!
p||j>i-1)/*i小于1或者大于表长*/
returnERROR;
s=(LinkList)malloc(sizeof(structLNode));/*生成新结点*/
s->data=e;/*插入L中*/
s->next=p->next;
p->next=s;
returnOK;
}
StatusListDelete(LinkListL,inti,ElemType*e)/*算法2.10。
不改变L*/
{/*在带头结点的单链线性表L中,删除第i个元素,并由e返回其值*/
intj=0;
LinkListp=L,q;
while(p->next&&j{
p=p->next;
j++;
}
if(!
p->next||j>i-1)/*删除位置不合理*/
returnERROR;
q=p->next;/*删除并释放结点*/
p->next=q->next;
*e=q->data;
free(q);
returnOK;
}
voidListTraverse(LinkListL,void(*vi)(ElemType))
/*vi的形参类型为ElemType*/
{/*初始条件:
线性表L已存在。
操作结果:
依次对L的每个数据元素调用函数vi()*/
LinkListp=L->next;
while(p){
vi(p->data);
p=p->next;
}
printf("\n");
}
/*第四部定义了几个常用函数equal()、comp()、print()、print2()和print1()函数*/
Statusequal(ElemTypec1,ElemTypec2){/*判断是否相等的函数*/
if(c1==c2)returnTRUE;
elsereturnFALSE;
}
intcomp(ElemTypea,ElemTypeb){/*根据a<、=或>b,分别返回-1、0或1*/
if(a==b)return0;
elsereturn(a-b)/abs(a-b);
}
voidprint(ElemTypec){
printf("%d",c);
}
voidprint2(ElemTypec){
printf("%c",c);
}
voidprint1(ElemType*c){
printf("%d",*c);
}
voidCreateList(LinkList*L,intn)/*算法2.11*/
{/*逆位序(插在表头)输入n个元素的值,建立带表头结构的单链线性表L*/
inti;
LinkListp;
*L=(LinkList)malloc(sizeof(structLNode));
(*L)->next=NULL;/*先建立一个带头结点的单链表*/
printf("请输入%d个数据\n",n);
for(i=n;i>0;--i){
p=(LinkList)malloc(sizeof(structLNode));/*生成新结点*/
Scanf_s("%d",&p->data);/*输入元素值*/
p->next=(*L)->next;/*插入到表头*/
(*L)->next=p;
}
}
voidCreateList2(LinkList*L,intn)
{/*正位序(插在表尾)输入n个元素的值,建立带表头结构的单链线性表L*/
inti;
LinkListp,q;
*L=(LinkList)malloc(sizeof(structLNode));/*生成头结点*/
(*L)->next=NULL;
q=*L;
printf("请输入%d个数据\n",n);
for(i=1;i<=n;i++){
p=(LinkList)malloc(sizeof(structLNode));
Scanf_s("%d",&p->data);
q->next=p;
q=q->next;
}
p->next=NULL;
}
voidMergeList(LinkListLa,LinkList*Lb,LinkList*Lc)/*算法2.12*/
{/*已知单链线性表La和Lb的元素按值非递减排列。
*/
/*归并La和Lb得到新的单链线性表Lc,Lc的元素也按值非递减排列*/
LinkListpa=La->next,pb=(*Lb)->next,pc;
*Lc=pc=La;/*用La的头结点作为Lc的头结点*/
while(pa&&pb)
if(pa->data<=pb->data){
pc->next=pa;
pc=pa;
pa=pa->next;
}
else{
pc->next=pb;
pc=pb;
pb=pb->next;
}
pc->next=pa?
pa:
pb;/*插入剩余段*/
free(*Lb);/*释放Lb的头结点*/
Lb=NULL;
}
voidmain()
{
intn=5;
LinkListLa,Lb,Lc;
printf("按非递减顺序(正位序建立单链表括");
CreateList2(&La,n);/*正位序输入n个元素的值*/
printf("La=");/*输出链表的内容*/
ListTraverse(La,print);
printf("按非递增顺序(逆位序建立单链表");
CreateList(&Lb,n);/*逆位序输入n个元素的值*/
printf("Lb=");/*输出链表的内容*/
ListTraverse(Lb,print);
MergeList(La,&Lb,&Lc);/*按非递减顺序归并La和Lb,得到新表Lc*/
printf("Lc=");/*输出链表括Lc的容*/
printf("La和Lb非递减顺序为Lc:
\n");
ListTraverse(Lc,print);
printf("Lc单链表的长度为:
");
printf("%d\n",ListLength(Lc));
printf("在Lc单链表的第i个位置前插入元素e:
\n请输入元素e=");
inte;
scanf("%d",&e);
printf("请输入位置i=");
inti;
scanf("%d",&i);
ListInsert(Lc,i,e);
printf("Lc=");
ListTraverse(Lc,print);
printf("将Lc置为空表\n");
ClearList(Lc);
printf("Lc=");
ListTraverse(Lc,print);
}
(3)实验过程发现的问题
①.在voidCreateList2(LinkList*L,intn)函数中Scanf("%d",&p->data);输入方式不安全
②.在voidCreateList(LinkList*L,intn)函数中Scanf_s("%d",&p->data);输入方式不安全
③.在intLocateElem(LinkListL,ElemTypee,Status(*compare)(ElemType,ElemType))函数中
i=0;LinkListp=L->next;逻辑错误
(4)问题分析及解决方案
①.在voidCreateList2(LinkList*L,intn)函数中改为
Scanf_s("%d",&p->data);
②.在voidCreateList(LinkList*L,intn)函数中改为
Scanf_s("%d",&p->data);
③.在intLocateElem(LinkListL,ElemTypee,Status(*compare)(ElemType,ElemType))函数中
将i=0;改为i=1;或将LinkListp=L->next;改为LinkListp=L->next->next;
p指向第一节点。
四.实验结果分析
除了scanf();函数出错外,intLocateElem(LinkListL,ElemTypee,Status(*compare)(ElemType,ElemType))函数中有逻辑错误,其他函数测试正常。
五.作业小结
(1)StatusListInsert(LinkListL,inti,ElemTypee)中
①.插入新数据只该元素的地址
②.转移原指针
③.拼接新指针
(2)在StatusGetElem(LinkListL,inti,Elemtype*e)中
P=L->next;j=1;while();查找元素时,如果第i个元素不存在,则返回ERROR
(3)在voidCreateList(LinkList*L,intn)中
P->next=L->next;L->next=p;
①转移指针。
②连接指针。
(4)在MergeList(LinkListLa,LinkList*Lb,LinkList*Lc)中
La,Lb为非空表时,pa和pb分别指向表中的第一个结点。
第一个循环条件是Pa,pb都不为空。
六.对原方案的改进意见
intLocateElem(LinkListL,ElemTypee,Status(*compare)(ElemType,ElemType)){若这样的数据元素不存在,则返回值为0*/
inti=1;
LinkListp=L->next;
while(p)
{
i++;
if(compare(p->data,e))/*找到这样的数据元素*/
returni;
p=p->next;
}
return0;
}
或者i=0;LinkListp=L->next->next;
七.实验收获
(1)通过此实验我对单链表进行初始化,建立带头节点的单链表,将单链表按其值非递归排序等操作有了进一步的了解。
(2)再进行插入,删除等操作时,单链表由于顺序表。
(3)对验证实验有了进一步的了解。