一.栈的表示与实现(顺序栈)
1.栈的顺序结构定义
typedef struct
{
SElemType *base;//栈底指针
SElemType *top;//栈顶指针
int stacksize;//当前最大容量
} SqStack;
2.栈的初始化(构建空栈)
Status InitStack(SqStack &S)
{
S.base=(SElemType *)malloc(sizeof(SElemType)*STACK_INIT_SIZE);//申请空间
if(!S.base)
exit(OVERFLOW);
S.top=S.base;//头尾指针相等,代表空栈
S.stacksize=STACK_INIT_SIZE;//当前容量为初始最大容量
return OK;
}
3.栈的插入操作
Status Push(SqStack &S,SElemType e)
{
if(S.top-S.base>=S.stacksize)//空间不够的话要考虑扩容
{
S.base=(SElemType*)malloc(sizeof(SElemType)*(S.stacksize+STACKINCREMENT));
if(!S.base)
exit(OVERFLOW);
S.top=S.base+S.stacksize;
S.stacksize+=STACKINCREMENT;
}
//把e插入栈顶
*S.top++=e;//相当于S.top = e;top++;
return OK;
}
4.栈的删除操作
Status Pop(SqStack &S,SElemType &e)
{
if(S.top==S.base)
return ERROR;
e = *S.top--;
return OK;
}
5.返回栈顶元素
Status GetTop(SqStack &S,SElemType &e)
{
if(S.base==S.top)
return ERROR;
e=*(S.top-1);//当栈不空时,栈顶指针总是指在栈顶元素的下一个位置
return OK;
}
6.栈的判空
bool JudgeEmpty(SqStack &S)
{
if(S.top == S.base)
return true;
else
return false;
}
二.栈的应用举例
1.数值转换
所以这个转换过程符合栈的原理
这里有一道例题,我写的应该算很详细了,看懂的话这块应该就ok了
https://blog.csdn.net/weixin_42110638/article/details/83030406
关于其他进制转换的原理,想了解的话大家也可以看这个
https://jingyan.baidu.com/article/495ba84109665338b30ede98.html
2.括号匹配检验
基本原理:
思路:1.在算法中设置一个栈
2.每读入一个括号,若是右括号,则要看是否匹配。当栈不空时,如果匹配,则栈顶元素出栈,如果不匹配(即不合法),说明缺少右括号,输出左符号-?(因为如果是右括号,说明之前已经读入左括号,但是两个括号不匹配)。当栈为空时,说明缺少左括号,输出?-右括号。若是左括号,则压入栈中。
3.对于/*符号,可用“<”代替,读到/时记得先i++;
4.算法的开始于结束,栈都应该为空
举两个例题,会了应该就差不多了
例题一:习题3.8 符号配对 (20 分)
pta原题链接:https://pintia.cn/problem-sets/434/problems/5869
该题答案与解析https://blog.csdn.net/weixin_42110638/article/details/83054360
例题二:练习题 10:括号画家
该题解析与答案:https://blog.csdn.net/weixin_42110638/article/details/83119150
3.行编辑程序
这里还没仔细研究,思路日后补充
具体的例题日后补充
4.迷宫求解(回溯算法)
这里还没仔细研究,思路日后补充
具体的例题日后补充
5.表达式转换(非常重要,也比较难)
思路:
从头到尾读取中缀表达式的每个对象,对不同对象按不同的情况处理。
1.运算数:直接输出
2.左括号:压入栈中
3.右括号:将栈顶的运算符弹出并输出,直到遇到左括号(出栈,不输出)
4.运算符:
若优先级大于栈顶运算符时,则把它压栈;
若优先级小于等于栈顶运算符时,将栈顶运算符弹出并输出;再比较新的栈顶运算符,直到该运算符大于栈顶运算符优先级为止,然后将该运算符压栈
5.若各对象处理完毕,则把堆栈中存留的运算符一并输出
这里会这道例题就可以了,不太好做
pta原题链接:习题3.11 表达式转换 (25 分)https://pintia.cn/problem-sets/434/problems/5893
该题超详细答案与解析:https://blog.csdn.net/weixin_42110638/article/details/83089498
6.其他应用:
a:函数调用及递归实现
b:图的深度优先搜索
二.链队列的表示与实现
1.链队列的结构定义
typedef struct QNode
{
QElemType data;
struct QNode *next;
} QNode,*QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
} LinkQueue;
2.链队列的初始化(构建空队列)
Status InitQueue(LinkQueue &Q)
{
Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
if(!Q.front)
exit(OVERFLOW);
Q.front->next = NULL;
return OK;
}
3.链队列的入队操作
Status EnQueue(LinkQueue &Q,QElemType e)
{
QueuePtr p;
p = (QueuePtr)malloc(sizeof(QNode));
if(!p)
exit(OVERFLOW);
p->data = e;
p->next = NULL;
Q.rear->next = p;//尾部插入
Q.rear = p;
return 1;
}
4.链队列的出队操作
Status DeQueue(LinkQueue &Q,QElemType &e)
{
if(Q.front == Q.rear)
return 0;
QueuePtr p = Q.front->next;//指向队头
e = p->data;
Q.front->next = p->next;
//如果队头是队尾,删除后将rear指向头结点
if(Q.rear == p)
Q.rear = Q.front;
free(p);
return 1;
}
5.链队列的判空操作
bool JudgeEmpty(LinkQueue &Q)
{
if(Q.front == Q.rear)
return true;
else
return false;
}
6.链队列的销毁操作
Status DestroyQueue(LinkQueue &Q) {
while(Q.front) {
Q.rear = Q.front->next;
free(Q.front);
Q.front = Q.rear;
}
return true;
}
三.循环队列的表示与实现(顺序队列)
1.循环队列的结构定义
typedef struct{
QElemType *base;
int front;
int rear;
}SqQueue;
2.循环队列的初始化
SqQueue InitQueue(SqQueue &Q)
{
Q.base=(QElemType *)malloc(MAXQSIZE*sizeof(QElemType));//为队列的数据存储空间分配内存
if(!Q.base)
exit(OVERFLOW);
Q.front = Q.rear = 0;
return OK;
}
3.循环队列的入队操作
Status EnQueue(SqQueue &Q,QElemType e)
{
if((Q.rear + 1)% MAXQSIZE == Q.front)//队列满的判断
return 0;
Q.base[Q.rear] = e;//将e赋值给队尾
Q.rear = (Q.rear + 1) % MAXQSIZE;//rear指针向后移一位,若到最后则转到数组头部
return 1;
}
4.循环队列的出队操作
Status DeQueue(SqQueue &Q,QElemType &e)
{
if(Q.front == Q.base)//队列空的判断
return 0;
e = Q.base[Q.front];//将队头元素赋值给e
Q.front = (Q.front + 1) % MAXQSIZE;//front指针向后移一位,若到最后则转到数组头部
return 1;
}
5.循环队列返回队列元素个数
Status QueueLength(SqQueue Q)//返回队列长度
{
return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}
后续还会更新例题以及栈与队列的总结