实验二 栈与队列的储存与操作
说明:由于本次实验分数据结构(栈与队列)的基本操作、附加实验:基字符串模式匹配算法的病毒感染检测问题,同时栈的储存与操作又分为顺序栈和链栈两个部分,故该实验报告分为了:顺序栈的储存与操作、链栈的储存与操作、队列的储存与操作、附加实验等四个部分。
一、顺序栈的储存与操作
(一)实验目的
1.理解栈是限定只能在栈顶进行操作的线性表;
2.理解栈的存储结构特点,掌握栈的存储分配要点;
3.掌握栈的基本操作及实现,深刻领会栈操作的后进先出特征,并能正确分析其时间复杂度,知道栈性能优于普通线性表及栈的常用情况。
(二)实验内容
实验具体内容:
1. 定义顺序栈的存储结构:(私有)数据封装(一维)数组(存储数据元素,位置/下标表示数据元素之间的逻辑关系,不占用存储空间)和栈顶指针(整型变量,存储栈顶下标),栈底默认为数组的某一端,不占用存储空间;
2. 顺序栈的基本操作
(1)初始化顺序栈;
(2)数据元素入栈;
(3)数据元素出栈;
(4)读栈顶元素;
(5)判定栈空/满操作;
(6)销毁顺序栈。
实验需求分析:
在理解顺序栈逻辑结构及储存特点的基础上,设计、编写一段完整代码,该代码能够详细定义顺序栈的储存结构,同时完成实验具体内容中所要求的顺序栈的基本操作。在此基础上,从算法思想及时间、空间复杂度的角度对代码进行优化,并获得关于“顺序栈的储存与操作”的最优化代码。
预期结果:
完成实验指导书中所要求的具体实验内容,并对其进行优化。
(三)算法思想与时间复杂度
顺序栈在应用中涉及生长方向和栈顶是否存储有效值共有4种情况,常见台式机的系统栈是向下生长、栈顶存储有效值。本次实验实现向上生长、栈顶存储有效值的顺序栈。
1. 初始化顺序栈:栈底端的边界外,栈底为低端0,栈顶即为-1;
2. 数据元素入栈:栈不满,先增加栈顶,再存储数据元素,时间复杂度为O(1);
3. 数据元素出栈:栈不空,先读数据元素,再减栈顶指针,时间复杂度为O(1);
4. 读栈顶元素:栈不空,读数据元素,不动栈顶指针,时间复杂度为O(1);
5. 判定栈空/满操作:栈顶为-1/数组长度减1。
(四)实验方法
1. 栈的存储结构和操作接口
//SeqStack.h
#ifndef SEQSTACK_H
#define SEQSTACK_H
const int StackSize=10; //10只是示例性的数据,可以根据实际问题具体定义
template <class T> //定义模板类SeqStack
class SeqStack
{
public:
SeqStack( ) ; //构造函数,栈的初始化
~SeqStack( ); //析构函数
void Push(T x); //将元素x入栈
T Pop( ); //将栈顶元素弹出
T GetTop( ); //取栈顶元素(并不删除)
bool Empty( ); //判断栈是否为空
private:
T data[StackSize]; //存放栈元素的数组
int top; //栈顶指针,指示栈顶元素在数组中的下标
};
#endif
2. 栈操作的实现
//SeqStack.cpp
#include "SeqStack.h"
/*
* 前置条件:栈不存在
* 输 入:无
* 功 能:栈的初始化
* 输 出:无
* 后置条件:构造一个空栈
*/
template <class T>
SeqStack<T>::SeqStack( )
{
top= -1;
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:销毁栈
* 输 出:无
* 后置条件:释放栈所占用的存储空间
*/
template <class T>
SeqStack<T>::~SeqStack( )
{
}
/*
* 前置条件:栈已存在
* 输 入:元素值x
* 功 能:在栈顶插入一个元素x
* 输 出:如果插入不成功,抛出异常
* 后置条件:如果插入成功,栈顶增加了一个元素
*/
template <class T>
void SeqStack<T>::Push(T x)
{
if (top== StackSize-1) throw "上溢";
top++;
data[top]=x;
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:删除栈顶元素
* 输 出:如果删除成功,返回被删元素值,否则,抛出异常
* 后置条件:如果删除成功,栈顶减少了一个元素
*/
template <class T>
T SeqStack<T>::Pop( )
{
T x;
if (top==-1) throw "下溢";
x=data[top--];
return x;
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:读取当前的栈顶元素
* 输 出:若栈不空,返回当前的栈顶元素值
* 后置条件:栈不变
*/
template <class T>
T SeqStack<T>::GetTop( )
{
if (top==-1) throw "下溢";
else return data[top];
}
/*
* 前置条件:栈已存在
* 输 入:无
* 功 能:判断栈是否为空
* 输 出:如果栈为空,返回1,否则,返回0
* 后置条件:栈不变
*/
template <class T>
bool SeqStack<T>::Empty( )
{
if(top==-1) return 1;
else return 0;
}
3. 调试运行
//SeqStackMain.cpp
#include <iostream> //引用输入输出流
using namespace std;
#include "SeqStack.cpp" //引入成员函数文件
void main()
{
SeqStack<int> a; //创建模板类的实例
if (a.Empty( )){
cout<<"栈空,执行入栈操作:"<<endl;
cout<<"对15和10执行入栈操作:"<<endl;
try
{
a.Push(15);
a.Push(10);
}
catch(char* wrong)
{
cout<< wrong;
}
cout<<"栈顶元素为:"<<endl; //取栈顶元素
cout<<a.GetTop( )<<endl;
cout<<"执行出栈操作:"<<endl;
cout<<a.Pop( )<<endl; //执行出栈操作
cout<<"栈顶元素为:"<<endl;
cout<<a.GetTop( )<<endl;
}
else{
cout<<"栈不空"<<endl;
}
}
(五)实验体会与收获
通过这次实验,我掌握了顺序栈的储存与操作,巩固了C++相关的程序设计方法与技术,并且意识到熟练掌握课本知识是实验的基础,不把课本上的相关知识学深学透,实验便无从着手,另外在做实验的过程锻炼思考问题并动手解决的能力很重要。
(六)附:程序源代码
#include<iostream>
#include<stdlib.h>
#define STACK_INIT_SIZE 100//存储空间初始分配量。
#define STACKINCREMENT 10//存储空间分配增量。
using namespace std;
typedef int elemtype;
typedef struct {
elemtype* base;//在栈构造之前和销毁之后,base的值为NULL。
elemtype* top;//栈顶指针。
int stacksize;//当前已分配的存储空间,以元素为单位。
}Stack;
void Initstack(Stack& s);//1.初始化栈
void Destroystack(Stack& s);//2.销毁栈
void Clearstack(Stack& s);//3.清空栈
int StackEmpty(Stack s);//4.栈判空
int Stacklength(Stack s);//5.求栈长度
elemtype GetTop(Stack s);//6.获取栈顶元素
void Push(Stack& s, elemtype e);//7.插入一个元素
elemtype Pop(Stack& s);//8.删除一个元素
elemtype Stackvisit(Stack& s, int i);//9.输出所有元素
void conversion(Stack& jinzhi, int choose, int num);//10.进制转换
int main()
{
Stack zhan;
zhan.base = NULL;
zhan.top = NULL;
elemtype yuansu;
int in = 1;
cout << endl;
while (in == 1)
{
cout << "1.初始化栈" << endl;
cout << "2.销毁栈" << endl;
cout << "3.清空栈" << endl;
cout << "4.栈判空" << endl;
cout << "5.求栈长度" << endl;
cout << "6.获取栈顶元素" << endl;
cout << "7.插入一个元素" << endl;
cout << "8.删除一个元素" << endl;
cout << "9.输出所有元素" << endl;
cout << "10.进制转换" << endl;
cout << "☆☆☆退出,输入一个负数!☆☆☆" << endl;
int select;
cout << "请输入您的选择:";
cin >> select;
switch (select)
{
case 1://1.初始化栈.
system("cls");
Initstack(zhan);
if (!zhan.base)
{
cout << "存储空间分配失败,请重新操作!" << endl;
}
else
{
cout << "您已经成功初始化一个栈!" << endl;
}
cout << endl;
break;
case 2://2.销毁栈
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
Destroystack(zhan);
cout << "您已成功销毁栈!" << endl;
}
cout << endl;
break;
case 3://3.清空栈
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
if (zhan.base == zhan.top)
{
cout << "栈为空,不用清空!" << endl;
}
else
{
Clearstack(zhan);
cout << "已经成功清空栈!" << endl;
}
}
cout << endl;
break;
case 4://4.栈判空
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
if (StackEmpty(zhan) == 0)
{
cout << "栈为空!" << endl;
}
else
{
cout << "栈不为空!" << endl;
}
}
cout << endl;
break;
case 5://5.求栈长度
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
cout << "栈的长度为:" << Stacklength(zhan) << endl;
}
cout << endl;
break;
case 6://6.获取栈顶元素
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
if (zhan.base == zhan.top)
{
cout << "这是一个空栈,不存在元素!" << endl;
}
else
{
cout << "栈顶元素为:" << GetTop(zhan) << endl;
}
}
cout << endl;
break;
case 7://7.插入一个元素
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
cout << "请输入您要插入的元素:";
cin >> yuansu;
if (zhan.top - zhan.base >= zhan.stacksize)//栈满,追加存储空间。
{
zhan.base = (elemtype*)realloc(zhan.base, (zhan.stacksize + STACKINCREMENT) * sizeof(elemtype));
if (!zhan.base) {
cout << "存储空间分配失败!请重新操作。" << endl;
}
else
{
zhan.top = zhan.base + zhan.stacksize;
zhan.stacksize += STACKINCREMENT;
cout << "内存空间分配成功!" << endl;
}
}
Push(zhan, yuansu);
cout << "入栈成功!" << endl;
}
cout << endl;
break;
case 8://8.删除一个元素
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
if (zhan.base == zhan.top)
{
cout << "栈为空,没有元素可以出栈!" << endl;
}
else
{
cout << "元素" << Pop(zhan) << "出栈成功!" << endl;
}
}
cout << endl;
break;
case 9://9.输出所有元素
system("cls");
if (zhan.base == NULL)
{
cout << "还未初始化栈,请您先初始化!" << endl;
}
else
{
if (zhan.base == zhan.top)
{
cout << "栈为空,没有元素可以输出!" << endl;
}
else
{
cout << "栈中的元素(从栈底到栈顶)为:";
for (int i = zhan.top - zhan.base; i > 0; i--)
{
cout << Stackvisit(zhan, i) << " ";
}
}
}
cout << endl << endl;
break;
case 10://10.进制转换
system("cls");
int num;
cout << "请您输入一个十进制整数:";
cin >> num;
if (num <= 0)
{
cout << "您输入的数据不合法!" << endl;
}
else
{
int choose;
Stack jinzhi;//构造进制转换的栈。
jinzhi.base = NULL;
jinzhi.top = NULL;
cout << endl;
cout << "1.转化成二进制" << endl;
cout << "2.转化成八进制" << endl;
cout << "3.转化成十六进制" << endl << endl;
cout << "请输入您的选择:";
cin >> choose;
switch (choose)
{
case 1:
conversion(jinzhi, choose, num);
cout << endl;
cout << "转化结果为:";
while (StackEmpty(jinzhi) == 1)
{
cout << Pop(jinzhi);
}
cout << endl;
break;
case 2:
conversion(jinzhi, choose, num);
cout << "转化结果为:";
while (StackEmpty(jinzhi) == 1)
{
cout << Pop(jinzhi);
}
cout << endl;
break;
case 3:
conversion(jinzhi, choose, num);
cout << "转化结果为:";
while (StackEmpty(jinzhi) == 1)
{
num = Pop(jinzhi);
if (num >= 10)
{
switch (num)
{
case 10:
cout << "A";
break;
case 11:
cout << "B";
break;
case 12:
cout << "C";
break;
case 13:
cout << "D";
break;
case 14:
cout << "E";
break;
case 15:
cout << "F";
break;
}
}
else
{
cout << num;
}
}
cout << endl;
break;
default:
cout << "您输入的选择不正确哦!" << endl;
break;
}
}
cout << endl;
break;
default:
system("cls");
if (select < 0)//退出程序
{
in = -999;
cout << "☆☆☆您已经退出程序,欢迎下次使用!☆☆☆" << endl;
break;
}
else
{
cout << "您的选择有误,请重新输入!" << endl << endl;
}
break;
}
}
}
//1.初始化栈
void Initstack(Stack& s)
{
s.base = (elemtype*)malloc(STACK_INIT_SIZE * sizeof(elemtype));
s.top = s.base;
s.stacksize = STACK_INIT_SIZE;
}
//2.销毁栈
void Destroystack(Stack& s)
{
s.stacksize = 0;
s.base = NULL;
s.top = NULL;
free(s.base);
free(s.top);
}
//3.清空栈
void Clearstack(Stack& s)
{
s.stacksize = 0;
s.base = s.top;
}
//4.栈判空
int StackEmpty(Stack s)
{
if (s.base == s.top)
{
return 0;//栈为空。
}
else
{
return 1;//栈不为空。
}
}
//5.求栈长度
int Stacklength(Stack s)
{
elemtype* p = s.top;
int i = 0;//计数。
while (p != s.base)
{
p--;
i++;
}
return i;
}
//6.获取栈顶元素
elemtype GetTop(Stack s)
{
return *(s.top - 1);
}
//7.插入一个元素
void Push(Stack& s, elemtype e)
{
*s.top = e;
s.top++;
}
//8.删除一个元素
elemtype Pop(Stack& s)
{
s.top--;
return *s.top;
}
//9.输出所有元素
elemtype Stackvisit(Stack& s, int i)
{
elemtype* p = s.top;
for (int j = 1; j <= i; j++) {
p--;
}
return *p;
}
//10.进制转换
void conversion(Stack& jinzhi, int choose, int num)
{
Initstack(jinzhi);
int njinzhi;
switch (choose)
{
case 1:
njinzhi = 2;
break;
case 2:
njinzhi = 8;
break;
case 3:
njinzhi = 16;
break;
}
while (num)
{
Push(jinzhi, num % njinzhi);
num = num / njinzhi;
//n=(n div d)*d + n mod d
//十进制n和其他进制d的转换机制。div为整除运算,mod为求余运算。
}
}