3.1栈
3.1.1 抽象数据类型栈的定义
栈是限定仅在表尾进行插入或者删除操作的线性表。表尾端称为栈顶(top),表头端称为栈底(bottom),不含元素的空表称为空栈。
栈又称为后进先出的线性表,他的特点类似于铁路调度站
退栈的第一个元素为栈顶元素。
3.1.2栈的表示和实现
和线性表类似,栈也有两种存储表示方法。
顺序栈:栈的顺序存储结构,利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素(与顺序表一样),同时附设指针top知识栈顶元素在顺序栈中的位置。
栈在使用过程中所需最大空间难以估计,合理做法为不够再扩充(类似于线性表动态扩充)
顺序栈的定义:
//---------------------------顺序栈结构体定义 ----------------------------------
typedef struct {
SElemType* base;//栈底指针,始终指向栈底位置
SElemType* top;//栈顶指针,初始值指向栈底,所以top=base是栈空的标志
//新元素入栈,top指针增1,所以非空栈栈顶指针始终再栈顶元素的下一个位置
int stacksize;//栈当前最大容量
}SqStack ;
顺序栈基本操作:
#include<iostream>
using namespace std;
typedef int SElemType;
typedef int Status;
#define MAXSIZE 100//顺序栈存储空间的初始分配量
#define STACKINCREMENT 10;
#define OK 1;
//顺序栈结构体定义
typedef int Status;
typedef int SElemType;
typedef struct {
SElemType* base;//指针构造销毁之后base的值为null
SElemType* top;
int stacksize;
}SqStack;
//初始化栈
Status InitStack(SqStack& S)
{
S.base = (SElemType*)malloc(MAXSIZE * sizeof(SElemType));//这里创建了一个SElemType(栈)型结点并把地址赋值给栈底指针
if (!S.base)
{
exit(OVERFLOW);//存储分配失败返回错误值
}
S.top = S.base;//初始栈底等于栈顶
S.stacksize = MAXSIZE;//设置最大容量
return OK;
}
//将元素e入栈
Status Push(SqStack& S, SElemType e)//传入栈的地址和元素e
{
if (S.top - S.base >= S.stacksize)
{
//S.base = (SElemType*)realloc(S.base,(S.stacksize + STACKINCREMENT) * sizeof(SElemType));//如果栈满,追加存储空间
}
if (!S.base)
{
exit(OVERFLOW);//存储分配失败返回错误值
}
*S.top = e;//e赋值给当前栈顶
S.top++;//栈顶指针+1
return 0;
}
//出栈,用e返回出栈元素
Status Pop(SqStack& S, SElemType& e)
{
if (S.top == S.base)
{
return 0;//空栈,返回错误值
}
S.top--;//栈顶指针-1
e = *S.top;//
return OK;
}
//返回栈顶元素
Status GetTop(SqStack S, SElemType& e)
{
if (S.top == S.base)
{
return 0;//空栈
}
e = *(S.top - 1);//栈顶元素在栈顶指针-1的位置
return OK;
}
//清空栈,变为空栈
void Clear(SqStack& S)
{
if (S.base)
{
S.top = S.base;//脑袋等于屁股直接删干净
cout << "清空结束" << endl;
}
}
//遍历栈元素 (从栈底到栈顶)
void Traverse(SqStack S)
{
if (S.base == NULL)
{
cout << "栈不存在" << endl;
}
if (S.top == S.base)
printf("空栈\n");
SElemType* P;//设置一个指针P
P = S.top;//P指向栈顶指针
while (P > S.base)//只要P大于栈底指针
{
P--;
std::cout << *P << endl;
}
}
//进制转换函数,将十进制数dec转化为n进制数,并输出转换后结果
void Convert(SqStack& S, int dec, int n)
{
SElemType e;//整形变量e用来存放中间值
while (dec) //十进制数不为0时
{
int i = dec % n;
Push(S, i);//将最后一位数传入栈
dec = dec / n;
}
cout << "转换结果为:" << endl;;
while (S.top != S.base) //栈不为空时
{
cout << Pop(S, e);//按顺序出栈
}
}
Status EmptyStack(SqStack& S)//判断栈是否为空
{
if (S.top == S.base)
{
return OK;
}
else
return 0;
}
int main(void)
{
SElemType e;
SqStack st;
InitStack(st);//初始创建一个栈
int c = 0;
while (c != 7)
{
cout << endl << "1. 入栈";
cout << endl << "2. 出栈";
cout << endl << "3. 读栈顶";
cout << endl << "4. 遍历栈";
cout << endl << "5. 清空顺序栈";
cout << endl << "6. 进制转换";
cout << endl << "7. 退出";
cout << endl << "选择功能(1~6):";
cin >> c;
switch (c)
{
case 1:
{
cout << "输入入栈元素" << endl;
cin >> e;
Push(st, e);
break;
}
case 2:
{
cout << "元素:" << Pop(st, e) << "已经出栈" << endl;;
break;
}
case 3:
{
cout << "栈顶元素为:" << GetTop(st, e) << endl;
break;
}
case 4:
{
Traverse(st);
break;
}
case 5:
{
Clear(st);
break;
}
case 6:
{
int dec, n;
cout << " 请输入待转换的十进制数:" << endl;
cin >> dec;
cout << " 请输入转换的进制:" << endl;
cin >> n;
Convert(st, dec, n);
break;
}
case 7:break;
}
}
}
链栈基本操作:
#include<iostream>
#include <stdlib.h>
#include<string.h>
#include<malloc.h>
#include<string>
using namespace std;
typedef char SElemType;
typedef int Status;//一般Status表示成功与失败
#define OK 1;
#define FALSE 0;
//链栈结构体定义 注意这里是链栈而不是线性栈
typedef struct SNode
{
SElemType data; //存放数据的数据域
SNode* next; //存放下一个结点地址的指针域
}SNode, * LinkStack;
//将元素e入栈
Status Push(LinkStack& S, SElemType e)
{
SNode* P;//生成一个SNode形的指针
P = (LinkStack)malloc( sizeof(SNode));//这个指针指向一个新的SNode类新的结点
P->data = e;//这个结点的数据域上的指针指向传进来的元素e
P->next = S;//新结点插向栈顶,这里新节点的P指针的地址域指向了栈顶S指针
S = P;//S这个头指针重新指向栈顶
//注意,链栈的指针是一直指向栈顶的,通过从栈顶指向下一个来实现栈的先进后出!!!
return OK;
}
//出栈,用e返回出栈元素
Status Pop(LinkStack& S, SElemType& e)
{
if (S == NULL)
{
cout << "栈不存在" << endl;
}
else
{
e = S->data; //把头指针(指向栈顶)的数据域赋值给e
SNode* P; //生成一个新的SNode形的指针
P = S; //让这个P指针指向栈顶
S = S->next; //头指针的位置向栈底移动一位
free(P); //删除P结点,实现“出栈“
}
return e;
}
//返回栈顶元素
Status GetTop(LinkStack S, SElemType& e)
{
if (S != NULL)
{
return S->data;//只要栈不为空直接输出栈顶头指针所致数据域
}
else
cout << "数组为空" << endl;
}
//清空栈,变为空栈
void Clear(LinkStack& S)
{
SNode* P;//新建一个P指针用来遍历一遍栈
while (S)//当s栈不为空
{
P = S;//指针P指向栈顶准备开始
S = P->next;//头指针下移动
free(P);//删除P指针实现释放栈顶
//不断重复此过程
}
cout << "删除结束" << endl;
}
//遍历栈元素 (从栈顶到栈底)
void Traverse(LinkStack S)
{
SNode* P;//新建一个P指针用来遍历一遍栈
P = S;//指针P指向栈顶准备开始
cout << "当前栈为" << endl;
while (P != NULL)
{
cout << P->data << endl;//输出指针P当前所指的数据域
P = P->next;//指针P下移,准备输出下一位
}
cout << "遍历结束" << endl;
}
//回文是指正读反读均相同的字符序列,如"acdca"、"dceecd"均是回文,但"book"不是回文。
//试写一个算法判定输入的字符串是否为回文,并将结果输出,例如:"acdca"是回文
int HuiWen(LinkStack s, string str)
{
int i;
char c;//用来接受出栈的
for (i = 0; i < (str.length() / 2); i++)//字符前半段入栈
{
Push(s, str[i]);
}
if (str.length() % 2) //奇数长度字符串跳过中间元素
{
i++;
}
for (i=0; i < str.length(); i++) {
Pop(s, c);//前半段出栈与后半段比较
if (c != str[i])
{
return false;
}
}
}
int main(void)
{
LinkStack st = NULL;//新建了一个叫st的栈并且为空
int st_num = 0;
SElemType e;
int c = 0;
while (c != 7)
{
cout << endl << "1. 入栈";
cout << endl << "2. 出栈";
cout << endl << "3. 读栈顶";
cout << endl << "4. 遍历栈";
cout << endl << "5. 清空顺序栈";
cout << endl << "6. 回文判断";
cout << endl << "7. 退出";
cout << endl << "选择功能(1~6):";
cin >> c;
switch (c)
{
case 1:
{
cout << "请输入进栈元素总数" << endl;
cin >> st_num;
for (int i = 1; i <= st_num; i++)
{
cout << "请输入第" << i << "个元素" << endl;
cin >> e;
if (Push(st, e))
{
cout << "入栈成功" << endl;
}
else
cout << "入栈失败" << endl;
}
break;
}
case 2:
{
cout << "元素:" << (char)Pop(st, e) << "已成功出栈" << endl;;
break;
}
case 3:
{
cout << "栈顶元素为:" << GetTop(st, e) << endl;
break;
}
case 4:
{//遍历栈
Traverse(st);
break;
}
case 5:
{
Clear(st);
break;
}
case 6:
{
LinkStack s = NULL;
char str[100];
cout << "输入数组" << endl;
cin >> str;
if (HuiWen(s, str))
cout << str << "是回文。" << endl;
else
cout << str << "不是回文。" << endl;
break;
}
case 7:
break;
}
}
}
括弧检测:
int main()
{
LiStack L;
InitStack(L);//初始化
cout << "请输入你想检测的括号(输入'-'结束程序)\n";
char x;
cin >> x;
while (x != '-') {
if (x == '(' || x == '[' || x == '{') {
Push(L, x);
cin >> x;
}
if (x == ')' || x == ']' || x == '}') {
char a;
a = GetTop(L);
//cout << a;
if ((x == ')' && a == '(') || (x == ']' && a == '[') || (x == '}' && a == '{')) {
char b;
int c = Pop(L, b);
cout << "左括号\t\t" << b << "\t匹配成功!\n";
cin >> x;
}
else {
cout << "右括号\t\t" << x << "\t匹配失败!\n";
return 0;
}
}
}
if (L == NULL) {
cout << "全部括号匹配成功!\n";
}
else {
char y;
y = GetTop(L);
cout << "左括号\t\t" << y << "\t匹配失败!\n";
}
return 0;
}