数据结构实验指导书实验3
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三栈操作
一、实验目的
1.熟悉栈的的顺序存储结构和链式存储结构定义;
2.掌握栈的基本操作,如:压栈、弹栈、判栈空、判栈满等运算。
3.掌握栈的特点(先进后出FILO),并能在实际问题背景下灵活应用。
二、实验内容
示例程序1:圆括号匹配的检验(LinkStack.h+LS_ParenMatch.cpp)本示例程序在头文件LinkStack.h中定义了栈的链式存储结构,并实现了链栈的基本操作(判栈空、构造、压栈、弹栈、销毁栈等)。
在文件LS_ParenMatch.cpp 中实现了栈基本操作的一个实际应用:圆括号()匹配的检验。
要求学生利用头文件LinkStack.h中已经定义的栈的基本操作实现栈的其他应用,或在头文件中添加其他关于栈的基本操作。
1.LinkStack.h中代码如下:
//链栈基本操作的实现
#include <stdio.h>
#include <stdlib.h>
#define NULL 0
//定义栈中元素的类型,可根据实际数据类型进行定义
//typedef char StackElementType;//栈中元素的类型
//#define PF "%c" //元素输出格式
//定义栈的链式存储结构
typedef struct node
{
StackElementType data;
struct node *next;
}LinkStack;
//链栈基本操作的说明
int IsEmpty(LinkStack *top);//判栈空
LinkStack *Push(LinkStack *top,StackElementType x);// 压栈
LinkStack *Pop(LinkStack *top,StackElementType &elem);//弹栈StackElementType GetTop(LinkStack *top);//取栈顶元素
void ShowStack(LinkStack *top);//输出栈中数据(顶-->底)void DestroyStack(LinkStack *top);//销毁栈
//链栈基本操作的实现
int IsEmpty(LinkStack *top)
{//判栈空
return top? 0:1;
}
LinkStack *Push(LinkStack *top,StackElementType x)
{// 压栈
LinkStack *p;
p=(LinkStack *)malloc(sizeof(LinkStack));
if(p)
{
p->data=x;
p->next=top;
top=p;
}
else
{
printf("内存空间不足,程序运行终止!\n");
exit(0);
}
return top;
}
LinkStack *Pop(LinkStack *top,StackElementType &elem)
{//弹栈
LinkStack *temp;
if(IsEmpty(top))
{
printf("空栈,出栈操作失败!\n");
return NULL;
}
else
{
temp=top;
elem=top->data;
top=top->next;
free(temp);
return top;
}
}
StackElementType GetTop(LinkStack *top)
{//取栈顶元素
if(IsEmpty(top))
{
printf("空栈,取栈顶元素失败!\n");
return 0;
}
else
return top->data;
}
void ShowStack(LinkStack *top)
{//输出栈中数据(顶-->底)
LinkStack *p;
p=top;
printf(" Stack:");
while(p)
{
printf(PF,p->data);
p=p->next;
}
printf("\n");
}
void DestroyStack(LinkStack *top)
{//销毁栈
LinkStack *p;
if(top)
{
p=top;
top=top->next;
free(p);
}
printf("栈已经销毁!\n");
}
2.LS_ParenMatch.cpp中代码如下:
//栈的一个应用实例:圆括号()匹配的检验
//假设表达式中充许括号嵌套,
//则检验括号是否匹配的方法可用“期待的急迫程度”这个概念来描述。
//例:(()()(()))
//先出现的左括号后匹配,后出现的左括号先匹配。
//符合栈的操作特性:先进后出(后进先出)。
//故可通过栈的基本操作实现括号是否匹配的检验。
//链栈基本操作的实现
//定义栈中元素的类型,可根据实际数据类型进行定义typedef char StackElementType;//元素类型
#define PF "%c" //元素输出格式
#include "linkstack.h"
//链栈头文件,实现了链栈的基本操作
//(判栈空、构造、压栈、弹栈、销毁栈、输出栈数据)
bool PMatch()
{//检查表达式中圆括号()配对是否正确
LinkStack *s=NULL;
char c,e;
printf("请输入表达式(以';'结束):\n");
c=getchar();
while(c!=';')
{
printf("读入字符为:%c",c);
ShowStack(s);
if(c=='(')
s=Push(s,c);
if(c==')')
{
if(s) s=Pop(s,e);
else {
printf("missing '('\n");
return false;
}
}
c=getchar();
}
if(!IsEmpty(s))
{
printf("missing ')'\n");
return false;
}
else { printf("Match Success!\n");
return true;
}
}
void main()
{
PMatch();//调用括号匹配检查函数
getchar();
}
示例程序2:数制转换(SqStack.h+SS_Conver.cpp)
本示例程序在头文件SqStack.h中定义了栈的顺序存储结构,并实现了顺序栈的基本操作(构造、压栈、弹栈、清空栈、销毁栈、输出栈中数据等)。
在文件SS_Conver.cpp中实现了栈基本操作的一个实际应用:数制转换(将任意十进制数转换为二、八、十六进制数)。
要求学生利用头文件SqStack.h中已经定义的栈的基本操作实现栈的其他应用,或在头文件中添加其他关于栈的基本操作。
1.SqStack.h中代码如下:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//定义栈中元素的类型,可根据实际数据类型进行定义
//typedef int ElemType;//栈中元素的类型
//#define PF "%d" //元素输出格式
//定义栈的顺序存储结构
#define StackInitSize 100 //存储空间初始分配量
typedef struct {
ElemType data[StackInitSize]; /*栈存储空间用一个预设的长度的一维数组来实现 */ int top; // 栈顶指针
}SeqStack;
//顺序栈基本操作的说明
SeqStack *InitStack();//构造空栈
void Push(SeqStack *s,ElemType x);//压栈
ElemType Pop(SeqStack *s);//弹栈
void ClearStack(SeqStack *s);//清空栈
void DestroyStack(SeqStack *s);//销毁栈
void ShowStack(SeqStack *s,int mark);//输出栈中数据
//顺序栈基本操作的实现
SeqStack *InitStack()
{//构造空栈
SeqStack *s;
s=(SeqStack *)malloc(sizeof(SeqStack)); if(s)
{
s->top=-1;
return s;
}
else
{
printf("内存不够!程序结束!");
exit(0);
}
}
void Push(SeqStack *s,ElemType x)
{//压栈
if(s->top==StackInitSize-1)
{
printf("栈满!上溢!无法进栈!\n");
exit(0);
}
else
{
s->top++;
s->data[s->top]=x;
}
return;
}
ElemType Pop(SeqStack *s)
{//弹栈
ElemType temp;
if(s->top==-1)
{
printf("栈空!下溢!程序结束!\n");
exit(0);
}
else
{
temp=s->data[s->top];
s->top--;
return temp;
}
}
void ClearStack(SeqStack *s)
{//清空栈
s->top=-1;
}
void DestroyStack(SeqStack *s)
{//销毁栈
free(s);
printf("栈已销毁!\n");
}
void ShowStack(SeqStack *s,int mark)
{//输出栈中数据
if(mark==0)//(底->顶)
{
for(int i=0;i<=s->top;i++)
printf(PF,s->data[i]);
printf("\n");
}
else//(顶->底)
{
for(int i=s->top;i>=0;i--)
printf(PF,s->data[i]);
printf("\n");
}
}
2.SS_Conver.cpp中代码如下:
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
//定义栈中元素的类型,可根据实际数据类型进行定义
typedef int ElemType;//栈中元素的类型
#define PF "%d " //元素输出格式
#include "sqstack.h"
//顺序栈头文件,实现了顺序栈的基本操作
//(构造、压栈、弹栈、清空栈、销毁栈、输出栈中数据)
void conversion( )
{//对于输入的任意一个非负的十进制整数,
//打印输出与其等值的r进制数
SeqStack *s;
int n,r;
s=InitStack();
printf("请输入一个非负十进制数n:");
scanf("%d",&n);
L1:
printf("\n请输入需转换的进位计数制r(2,8,16):");
scanf("%d",&r);
if(r==2||r==8||r==16)
{
while(n)
{
Push(s,n%r);
n=n/r;
}
}
else goto L1;
printf("栈中数据(底->顶):");
ShowStack(s,0);//栈中数据(底->顶)
printf("栈中数据(顶->底):");
ShowStack(s,1);//栈中数据(顶->底)
printf("转换得到的%d进制数为:",r);
while(s->top!=-1)
{
int e=Pop(s);
if(e>=10&&e<=15)//十六进制10..15对应字符A..F printf("%c", 65+e-10);
else printf("%d",e);
}
}
void main()
{
L2:
conversion( );//调用数制转换函数
printf("\n重复一次(y|n)?");
getchar();//读入换行符
if(getchar()=='y') goto L2;
}
三、实验要求
1.认真阅读和掌握本实验所有示例程序。
2.上机运行示例程序,打印出程序的运行结果,并作必要的说明。
3.对示例程序,在程序中至少添加2个关于栈的应用的函数,并重新改写主程序(要求必需调用自己添加的函数),打印出文件清单(自己添加的函数及修改后的主函数)和运行结果。
关于栈的应用可考虑如下问题:
(1)利用栈基本操作判断给定字符串是否为回文。
(2)判断表达式中圆括号和方括号是否正确配对。
(3)利用栈基本操作实现行编辑程序。
一个简单的行编辑程序的功能是:接受用户从键盘输入的程序或
数据,并存入一个文本文件。
由于用户在输入时,不能保证不出
差错,故可设立一个输入缓冲区(栈),用于接受用户输入的一
行字符,然后逐行存入文本文件。
允许用户输入时有差错,并能
及时更正。
输入‘#’表示前一个字符无效;输入‘@’表示当
前行’@’之前的字符无效。
如,从终端输入如下两行字符:
fi##if(x>y1#)
ptirnff@printf(“max=%f#d\n”,x);
则,实际应存入文本文件的是下列两行:
if(x>y)
printf(“max=%d\n”,x);
(4)利用栈基本操作迷宫求解。
给定用二维数组表示的迷宫,求从任意指定的入口到任意指定出口的路径(可以用特殊符号在二维数
组中标出找到的路径,如’*”)。
如下即为一个迷宫:
‘#’表示无通路(障碍)。
空格表示通路(无障碍)。
(5)其他可以用栈求解的问题。
4.分析示例程序中每一个算法(函数)的时间复杂度。
根据上述要求撰写实验报告,并简要给出算法设计小结和心得。