中南大学数据结构实验报告.docx
《中南大学数据结构实验报告.docx》由会员分享,可在线阅读,更多相关《中南大学数据结构实验报告.docx(40页珍藏版)》请在冰豆网上搜索。
中南大学数据结构实验报告
[键入文档副标题]
[键入文档标题]
实验题目:
(1)单链表的实现
(2)栈和队列
(3)二叉树的遍历(4)查找与排序
学生姓名:
代巍
学生学号:
0909121615
指导老师:
余腊生
所在学院:
信息科学与工程学院
专业班级:
信息安全1201班
指导教师评定:
签名:
实验一单链表的实现
一、实验目的
了解线性表的逻辑结构和各种存储表示方法,以及定义在逻辑结构上的各种
基本运算及其在某种存储结构上如何实现这些基本运算。
在熟悉上述内容的基础上,能够针对具体应用问题的要求和性质,选择合适的存储结构设计出相应的有效算法,解决与线性表相关的实际问题
二、实验内容
用C/C++语言编写程序,完成以下功能:
(1)运行时输入数据,创建一个单链表
(2)可在单链表的任意位置插入新结点
(3)可删除单链表的任意一个结点
(4)在单链表中查找结点
(5)输出单链表
三、程序设计的基本思想,原理和算法描述:
(包括程序的结构,数据结构,输入/输出设计,符号名说明等)
用一组地址任意的存储单元存放线性表中的数据元素。
以元素(数据元素的映象) + 指针(指示后继元素存储位置) = 结点(表示数据元素 或 数据元素的映象)
以“结点的序列”表示线性表称作线性链表(单链表)
单链表是指数据接点是单向排列的。
一个单链表结点,其结构类型分为两部分:
(1)、数据域:
用来存储本身数据。
(2)、链域或称为指针域:
用来存储下一个结点地址或者说指向其直接后继的指针。
1、单链表的查找
对单链表进行查找的思路为:
对单链表的结点依次扫描,检测其数据域是否是我们所要查好的值,若是返回该结点的指针,否则返回NULL。
2、单链表的插入
因为在单链表的链域中包含了后继结点的存储地址,所以当我们实现的时候,只要知道该单链表的头指针,即可依次对每个结点的数据域进行检测。
假设在一个单链表中存在2个连续结点p、q(其中p为q的直接前驱),若我们需要在p、q之间插入一个新结点s,那么我们必须先为s分配空间并赋值,然后使p的链域存储s的地址,s的链域存储q的地址即可。
(p->link=s;s->link=q),这样就完成了插入操作。
3、单链表的删除
删除运算思想方法删除运算是将表的第i个结点删去。
具体步骤:
找到 i-1 的存储位置p令p-next指向 i 的直接后继结点释放结点 i 的空间,将其归还给"存储池"。
四、源程序及注释
#include
#include
#include
#include
#include
#defineElemTypeint
//链表类型
typedefstructLNode
{
ElemTypedata;
structLNode*next;
}LNode,*LinkList;
intEmptyList(LinkList&L)
{if(L->next==NULL){
return0;
}
else{return1;}
}
//手动建立一个带头结点的线性链表L
voidSCreateList_L(LinkList&L)
{LinkListl,p;
inti;
ElemTyped;
l=(LinkList)malloc(sizeof(LNode));
L=(LinkList)malloc(sizeof(LNode));//生成头结点
l=L;
L->next=NULL;
cout<<"请依次输入结点值,以0为结束:
"<for(i=1;i=1;){
cin>>d;
if(d!
=0)
{
p=(LinkList)malloc(sizeof(LNode));//生成新结点
p->data=d;
p->next=l->next;l->next=p;l=l->next;
}
elsebreak;
}
if(EmptyList(L))cout<<"生成链表成功!
!
";
elsecout<<"链表为空,未生成!
!
";
cin.get();
cin.get();
}//SCreate_L
//自动建立一个带头结点的线性链表L
voidZCreateList_L(LinkList&L,intn)
{LinkListl,p;
l=(LinkList)malloc(sizeof(LNode));
L=(LinkList)malloc(sizeof(LNode));//生成头结点
l=L;
L->next=NULL;
srand((unsigned)time(NULL));
for(inti=n;i>0;--i){
p=(LinkList)malloc(sizeof(LNode));//生成新结点
p->data=(rand()%100+1);
p->next=l->next;l->next=p;l=l->next;
}
cout<<"生成链表成功!
!
";
cin.get();
cin.get();
}//ZCreate_L
//建立一个带头结点的线性链表
LinkListCreateList_L()
{charc;
intn;
LinkListL;
cout<<"*********建立线性链表*********"<cout<<"1.手动建立"<cout<<"2.自动建立"<cout<<"******************************"<cin>>c;
if(c=='1'){SCreateList_L(L);}
elseif(c=='2'){cout<<"请输入链表结点的个数:
";cin>>n;ZCreateList_L(L,n);}
else{cout<<"输入错误,请重新输入:
"<returnL;
cin.get();
cin.get();
}
//计算线性链表L中结点的个数
intLengthList(LinkList&L)
{
LinkListp=L->next;
inti=0;
while(p)
{
++i;
p=p->next;
}
returni;
cin.get();
cin.get();
}//LengthList
//在线性链表L中第i个结点之前插入新的数据元素e
voidListInsert_L(LinkList&L)
{inti;ElemTypee;
cout<<"第i个结点之前插入新的结点,请输入i:
";
cin>>i;
while(i<=0||i>LengthList(L))
{
cout<<"位置错误,重新输入插入位置:
";
cin>>i;
}
LinkListp,s;
p=L;intj=0;
while(p&&jnext;++j;}
if(!
p||j>i-1){cout<<"输入错误!
!
";
cin.get();
cin.get();
}
else{
cout<<"新结点的数据为:
";
cin>>e;
s=(LinkList)malloc(sizeof(LNode));
s->data=e;s->next=p->next;
p->next=s;
cout<<"插入成功!
!
";
}
cin.get();
cin.get();
}//ListInsert_L
//删除线性链表L中的第i个结点
voidListDelete_L(LinkList&L)
{
inti;
ElemTypee;
cout<<"请输入要删除第i个结点的i值:
";
cin>>i;
while(i<=0||i>LengthList(L))
{
cout<<"位置错误,重新输入删除位置:
";
cin>>i;
}
LinkListp,q;
p=L;intj=0;
q=(LinkList)malloc(sizeof(LNode));
while(p->next&&jp=p->next;
++j;
}//寻找第i个结点
if(!
(p->next)||j>i-1){cout<<"删除位置不合理";
cin.get();
cin.get();
}
else{
q=p->next;
p->next=q->next;
e=q->data;
cout<<"删除成功!
!
"<"<free(q);//删除并释放结点
}
cin.get();
cin.get();
}//ListDelete_L
//输出线性链表L中的所有数据元素
voidPrintList(LinkList&L)
{
LinkListp=L->next;
cout<<"所有数据如下所示:
"<while(p)
{
cout<data<<"";
p=p->next;
}
cin.get();
cin.get();
}//PrintList
voidSearchList(LinkList&L)//查找某一结点,显示其位置
{
inti=0;
ElemTypen;
cout<<"请输入要找的数据:
";
cin>>n;
if(L==NULL){cout<<"链表为空!
!
";}
LinkListp=L->next;
while(p->data!
=n&&p->next!
=NULL){p=p->next;i=i+1;}
if(p->data==n){cout<<"找到了对应的结点,在链表的第"<
";}
elsecout<<"链表上找不到相应的的结点!
!
";
cin.get();
cin.get();
}
voidDestroyList(LinkList&L)//退出系统前,内部做结尾工作
{
while(L)
{
LinkListp;
p=L;
L=L->next;
free(p);
}
L=NULL;
cout<<"线性链表L已销毁!
!
"<}//DestroyList
intmenu_select()//选择函数
{
char*m[7]={"1.建立线性链表",
"2.某一结点前插入一个结点",
"3.删除一个结点",
"4.计算结点个数并输出",
"5.查找并显示某一结点位置",
"6.输出所有节点",
"0.退出系统"};
inti;
charc1;
do{
system("cls");/*清屏*/
cout<<"\n\n=========链表的基本操作=========\n\n";
for(i=0;i<7;i++)
cout<cout<<"\n==================================\n";
cout<<"请选择(1-6,0):
";
cin>>c1;
}while(c1<'0'||c1>'6');
return(c1-'0');
}
voidmain()
{
LinkListL=NULL;
for(;;)
{
switch(menu_select())
{
case1:
L=CreateList_L();
system("pause");
break;
case2:
if(L!
=NULL)ListInsert_L(L);
else{
cout<<"链表为空,请先建链表!
!
";
cin.get();
cin.get();
break;
}
system("pause");
break;
case3:
if(L!
=NULL)ListDelete_L(L);
else{
cout<<"链表为空,请先建链表!
!
";
cin.get();
cin.get();
break;
}
system("pause");
break;
case4:
if(L!
=NULL){inti=LengthList(L);cout<<"结点的个数为:
"<
cin.get();
cin.get();}
else{
cout<<"链表为空,请先建链表!
!
";
cin.get();
cin.get();
break;
}
system("pause");
break;
case5:
if(L!
=NULL)SearchList(L);
else{
cout<<"链表为空,请先建链表!
!
";
cin.get();
cin.get();
break;
}
system("pause");
break;
case6:
if(L!
=NULL)PrintList(L);
else{
cout<<"链表为空,请先建链表!
!
";
cin.get();
cin.get();
break;
}
system("pause");
break;
case0:
if(L!
=NULL)DestroyList(L);
exit(0);
}
}
}
五、实验结果
实验二栈和队列
一、实验目的
了解栈和队列的特性。
掌握栈的顺序表示和实现。
掌握栈的链式表示和实现。
掌握队列的顺序表示和实现。
掌握队列的链式表示和实现。
掌握栈和队列在实际问题中的应用。
二、实验内容
编写一个程序实现顺序栈的各种基本运算,并在此基础上设计一个主程序完成如下功能:
初始化顺序栈,插入元素,删除栈顶元素,取栈顶元素,遍历顺序栈,置空顺序栈。
三、程序设计的基本思想,原理和算法描述
栈的修改时按照先进后出的原则进行的,试验中用到构造空栈,及入栈出栈操作。
队列是一种先进先出的线性表,只允许在表的一端插入,而在另一端删除元素,试验中构造队并且入队出队。
立顺序栈SeqStack,存放测试数据;建立队列SeqQueue存放出栈数据;
建立InitStack、StackEmpty、StackFull、Pop、Push、GetTop函数用作顺序栈的基本操作;建立InitQueue、QEmpty、Qfull、InQueue、OutQueue、ReadFront函数用作队列的基本操作;
建立主函数依次按序对子函数进行操作:
InitStack初始化栈→Push压入数据→InitQueue初始化队列→Pop弹出数据→InQueue存入队列→OutQueue出队列→Push压入栈→Pop弹出数据→free清空栈与队列。
在数据的输入与数据的输出时提供必要的提示信息。
四、源程序及其注释
#include
#include"stack.h"
#include
#defineMAXSIZE100
//作用:
对栈进行初始化
//参数:
无
//返回值:
SeqStack
SeqStackSeqStackInit()
{
SeqStackS;
S.top=-1;
returnS;
}
//作用:
对栈进行判断是否为空
//参数:
传入要判断的栈
//返回值:
返回TRUE为空,返回FLASE为非空
intSeqStackEmpty(SeqStackS)
{
if(S.top<0)
{
returnTRUE;
}
else
{
returnFLASE;
}
}
//作用:
把S置为空栈
//参数:
传入要操作的栈
//返回值:
无
voidClearStack(SeqStack*S)
{
while(!
SeqStackEmpty(*S))
{
S->top--;
}
printf("\n清空!
\n");
}
//作用:
把元素x压入栈,使其成为新的栈顶元素
//参数:
传入栈和要输入的数字
//返回值:
无
voidSeqStackPush(SeqStack*S,DataTypex)
{
S->top++;//要求是先挖坑,再种萝卜
S->data[S->top]=x;
}
//作用:
出栈
//参数:
要从该栈出来
//返回值:
从栈中出来的数
DataTypeSeqStackPop(SeqStack*S)
{
DataTypetemp;
if(SeqStackEmpty(*S))
{
printf("sorry!
为空栈!
");
//exit
(1);
}
else
{
temp=S->data[S->top];//出栈是当前出栈,要求先挖萝卜再填坑
S->top--;
printf("\n%d\n",temp);
}
}
//作用:
取栈顶元素
//参数:
要操作的栈
//返回值:
从栈中出来的数
DataTypeSeqStackGetTop(SeqStackS)
{
DataTypetemp;
if(SeqStackEmpty(S))
{
printf("sorry!
为空栈!
");
//exit
(1);
}
else
{
temp=S.data[S.top];//出栈是当前出栈,要求先挖萝卜再填坑
printf("\n%d\n",temp);
}
}
//作用输出顺序栈中的元素
//参数:
要操作的栈
//返回值:
从栈中出来的数
voidSeqStackPrint(SeqStackS)
{
DataTypetemp;
SeqStackp;
p=S;
printf("输出栈中的所有元素:
");
while(!
SeqStackEmpty(p))
{
temp=p.data[p.top];//出栈是当前出栈,要求先挖萝卜再填坑
p.top--;
printf("\n%d\n",temp);//当这里位置数据类型怎么办
}
}
voidmain(void)
{
intnum;
intinput;
SeqStackp;
p=SeqStackInit();
//这里调用入栈函数,把10,20,30进栈
SeqStackPush(&p,10);
SeqStackPush(&p,20);
SeqStackPush(&p,30);
while
(1)
{
printf("\n\t实验二\n\n");
printf("\n1.入栈");
printf("\n2.栈顶元素弹出");
printf("\n3.取栈顶元素");
printf("\n4.输出顺序栈中的元素");
printf("\n5.清空栈\n");
printf("\t请输入要实现的功能\n");
scanf("%d",&num);
switch(num)
{
case1:
printf("\n请输入要入栈的数:
\t\t\n");
scanf("%d",&input);
SeqStackPush(&p,input);
break;
case2:
SeqStackPop(&p);
break;
case3:
SeqStackGetTop(p);
break;
case4:
SeqStackPrint(p);
break;
case5:
ClearStack(&p);
break;
}
}
}
五、实验结果
实验三二叉树的建立和遍历
一、实验目的
1、学会实现二叉树结点结构和对二叉树的基本操作。
2、掌握对二叉树每种操作的具体实现,学会利用递归方法编写对二叉树这种递归数据结构进行处理的算法。
二、实验内容
编写程序任意输入二叉树的结点个数和结点值,构造一棵二叉树,采用三种递归遍历算法(前序、中序、后序)对这棵二叉树进行遍历并计算出二叉树的高度。
三、程序设计的基本思想,原理和算法描述
1、数据结构的定义
二叉树是另一种树型结构,它的特点是每个结点至多只有两棵子树,并且二叉树有左右之分,其次序不能任意颠倒。
二叉树的存储结构分为顺序存储和链式存储结构,本次我们主要应用二叉树的二叉链表的方式存储方式,实验中首先必须对二叉树的数据结构进行定义,即定义一个二叉链表,其中其数据成员包括节点的数据、左子树的指针、右子树的指针。
2、二叉树的建立
在实验开始前我们要建立一个以先序形式的二叉树,先序的二叉树就是先访问根结点,然后访问左子树,最后访问右子树的遍历。
3、二叉树的遍历
二叉树的遍历分为先序、中序、后序,需先取遍历的节点的数据存入队列中,然后输出。
4、程序中要的函数的介绍
(1)二叉树的类型定义
(2)定义链式队列类型
(3)初始化链式队列的函数 (4)主函数
四、源程序及注释
#include
#include
typedefstructBiTNode
{chardata;
structBiTNode*lchild,*rchild;
}BiTNode,*BiTree;
voidCreatBiTree(BiTree&T)
{//前序法创建二叉树
charch;
if((ch=getchar())=='\n')
T=NULL;
else
{
T=(BiTNode*)malloc(sizeof(BiTNode));
if(!
T)
exit
(1);
T->data=ch;
CreatBiTree(T->lchild);
CreatBiTree(T->rchild);
}
}
voidPreTravel(BiTree&T)
{//前序遍历
if(T)
{
printf("%c",T->data);
PreTravel(T->lchild);
PreTravel(T->rchild);
}
}
voidMidTravel(BiTree&T)
{//中序遍历
if(T)
{
MidTravel(T->lchild);
printf("%c",T->data);
MidTravel(T->rchild);
}
}
voidPostTravel(BiTr