实验目的
- 栈的顺序存储结构实现;
- 栈的链式存储结构实现;
- 理解栈的LIFO (后进先出) 特征,并熟练运用栈解决一些实际算法问题。
实验内容
验证题: 用本实验提供的5个文件(.cpp、.h)新建项目,并按以下步骤调试程序,分别验证顺序存储结构和链式存储结构栈的入栈和出栈操作。
1. 顺序存储结构实现栈:
1)入栈bool Push(SqStack &S, ElemType item);
在入栈接口Push(my_stack1,i); 处设置断点①,按“F5”启动调试,按“F10”逐句执行,直到数据1~10全部入栈。程序暂停时观察栈顶数据my_stack1.data[my_stack1.top]和栈顶位置my_stack1.top;
入栈序号 | 栈中全部数据(底至顶排列my_stack1.data | 栈顶位置my_stack1.top | 栈顶数据 my_stack1.data [ my_stack1.top] |
---|---|---|---|
0 | 无 | -1 | 无 |
1 | 1 | 0 | 1 |
2 | 1,2 | 1 | 2 |
3 | 1,2,3 | 2 | 3 |
4 | 1,2,3,4 | 3 | 4 |
5 | 1,2,3,4,5 | 4 | 5 |
6 | 1,2,3,4,5,6 | 5 | 6 |
7 | 1,2,3,4,5,6,7 | 6 | 7 |
8 | 1,2,3,4,5,6,7,8 | 7 | 8 |
9 | 1,2,3,4,5,6,7,8,9 | 8 | 9 |
10 | 1,2,3,4,5,6,7,8,9,10 | 9 | 10 |
图示:可以看到入栈的过程。(以下实验类似)
2) 出栈bool Pop(SqStack &S, ElemType &item);
在Pop(my_stack1, result); 处设置断点②,按“F5”启动调试,按“F10”逐句执行,直到所有数据完全出栈;
出栈序号 | 栈中全部数据(底至顶排列my_stack1.data | 栈顶位置my_stack1.top | 栈顶数据 my_stack1.data [ my_stack1.top] |
---|---|---|---|
0 | 1,2,3,4,5,6,7,8,9,10 | 9 | 10 |
1 | 1,2,3,4,5,6,7,8,9 | 8 | 9 |
2 | 1,2,3,4,5,6,7,8 | 7 | 8 |
3 | 1,2,3,4,5,6,7 | 6 | 7 |
4 | 1,2,3,4,5,6 | 5 | 6 |
5 | 1,2,3,4,5 | 4 | 5 |
6 | 1,2,3,4 | 3 | 4 |
7 | 1,2,3 | 2 | 3 |
8 | 1,2 | 1 | 2 |
9 | 1 | 0 | 1 |
10 | 无 | -1 | 无 |
图示:注意:顺序存储时,出栈并不会清除原来存储的值,由top指向栈顶即可。只有当有新值入栈时才会覆盖掉旧值。
2. 链式存储结构实现栈:
- 入栈bool Push(LinkStNode S, ElemType item);
在入栈接口Push(my_stack2,i);* 处设置断点③,按“F5”启动调试,按“F10”逐句执行,直到所有数据全部入栈。当程序暂停时观察栈中各结点的数据、栈顶指针的变化情况;
入栈序号 | 栈中全部数据(底至顶排列)my_stack2 | 栈顶数据 my_stack2->next->data |
---|---|---|
0 | 无 | 无 |
1 | 1 | 1 |
2 | 1,2 | 2 |
3 | 1,2,3 | 3 |
4 | 1,2,3,4 | 4 |
5 | 1,2,3,4,5 | 5 |
6 | 1,2,3,4,5,6 | 6 |
7 | 1,2,3,4,5,6,7 | 7 |
8 | 1,2,3,4,5,6,7,8 | 8 |
9 | 1,2,3,4,5,6,7,8,9 | 9 |
10 | 1,2,3,4,5,6,7,8,9,10 | 10 |
图示:可以看到链栈的入栈过程。
2) 出栈bool Pop(LinkStNode S, ElemType &item);
在Pop(my_stack2, result);处设置断点④*,按“F5”启动调试,按“F10”逐句执行,直到所有数据完全出栈;
出栈序号 | 栈中全部数据(底至顶排列)my_stack2 | 栈顶数据my_stack2->next->data |
---|---|---|
0 | 1,2,3,4,5,6,7,8,9,10 | 10 |
1 | 1,2,3,4,5,6,7,8,9 | 9 |
2 | 1,2,3,4,5,6,7,8 | 8 |
3 | 1,2,3,4,5,6,7 | 7 |
4 | 1,2,3,4,5,6 | 6 |
5 | 1,2,3,4,5 | 5 |
6 | 1,2,3,4 | 4 |
7 | 1,2,3 | 3 |
8 | 1,2 | 2 |
9 | 1 | 1 |
10 | 无 | 无 |
图示:可以看到链栈的出栈过程。出栈时,会清除栈顶结点,释放空间。
编程题:
1. 设计新接口并在content.cpp文件中测试:
1)设计顺序栈的遍历接口:
void TraverseStack(SqStack S);
实现栈中数据按出栈的顺序输出,但保留栈中的数据;
顺序栈的遍历函数代码如下:
//按出栈顺序遍历栈
void TraverseStack(SqStack S)
{
if (StackEmpty(S))
{
cout<<"栈空"<<endl;
return; // 栈空,遍历失败
}
for (int i=S.top; i>=0; i--)
cout<<S.data[i]<<" ";
cout<<endl;
// 遍历成功
}
2)设计链栈的遍历接口:
void TraverseStack(LinkStNode S);
实现栈中数据按出栈*的顺序输出,但保留栈中的数据。
//按出栈顺序遍历栈
void TraverseStack(LinkStNode *S)
{
if (StackEmpty(S))
{
cout<<"栈空"<<endl;
return; //栈空,遍历失败
}
LinkStNode *p=S->next; //从头结点后一个位置开始,即从第一个元素结点开始
while(p)
{
cout<<p->data<<" ";
p=p->next;
}
cout<<endl;
//遍历成功
}
2. 链栈的应用:编写函数,判断给定的字符串是否是“回文”。
如字符串“pop”、“madam”、“level”、“refer”均为中心对称,将中心对称的字符串称为回文。
字符串“abcdba”不中心对称,不是回文。
【要求】利用本实验已实现的链栈基本操作来实现,并进行测试;
【函数原型】bool IsReverse(char *s);
【函数功能】判断字符串s是否为回文,是返回true,否则返回false;
【提示】先将字符串中的每个字符依次全部入栈,然后执行出栈操作,依次判断每次出栈的字符是否与字符串中对应正向字符相同,如果出现不相同的情况则说明字符串不是回文,无需继续比较。全部都相同则是回文。
#include "LinkStack.h"
//判断字符串s是否为回文
bool IsReverse(char *s)
{
LinkStNode *S; //定义管理链栈的栈顶指针
ElemType t;
InitStack(S); //初始化链栈
int i;
for(i=0; s[i]!='\0'; i++) //将字符串中的内容入栈
Push(S, s[i]);
i=0;
while( !StackEmpty(S) )
{
Pop(S, t); //出栈
//比较出栈元素与字符串正向元素是否相同
if (t!=s[i])
return false;//不是回文
else
i++;
}
return true; //是回文
}
int main()
{
char str[20];
cout<<"输入一个字符串:";
cin>>str;
if(IsReverse(str))
cout<<str<<"是回文"<<endl;
else
cout<<str<<"不是回文"<<endl;
return 0;
}