DS博客作业02--栈和队列
0.PTA得分截图
1.本周学习总结
1.1 总结栈和队列内容
1、栈的存储结构及操作
栈(后进先出的线性表)
栈是一种只能在一端进行插入或删除操作的线性表。
进行插入、删除操作的一端称为栈顶。
出栈规律
1、栈顶出栈,栈底最后出栈;
2、时进时出,元素未完全进栈时,当前栈顶元素即可出栈。
①顺序栈
注意:顺序栈栈底可以设置在栈的任意一端,但不能设置在中间。
顺序栈结构体定义
typedef struct
{
ElementType *Data; /* 存储元素的数组 */
Position top; /* 栈顶指针 */
int MaxSize; /* 堆栈最大容量 */
} SNode,*Stack;
若Stack S
栈空条件:S->top=-1
栈满条件:S->top=S->MaxSize-1
进栈e操作:S->top++; S->data[S->top]=e
退栈操作:取栈顶元素e=S->data[S->top]; S->top--;
②链栈(不考虑栈满)
链栈结构体定义
typedef struct linknode
{ ElemType data; //数据域
struct linknode *next; //指针域
} LiNode,*LiStack;
若LiStack s,LiStack p
栈空条件:s->next=NULL
栈满条件:不考虑
进栈e操作:p->data=e; p->next=s->next;s->next=p;头插法
退栈,取栈顶元素操作:p=s->next;e=p->data; s->next=p->next; free(p);取出头结点之后结点的元素并销毁节点
③栈的应用
c++模板类:stack
头文件#include< stack>
stack<int(栈中元素类型)>st:初始化栈,参数表示
st.push(e):入栈元素e
st.top():返回栈顶元素
st.pop():出栈操作只是删除栈顶元素,并不返回该元素。
st.empty(),当栈空时,返回true,否则false。
st.size():访问栈中的元素个数
注意:功能后的()不能漏掉
一个数组中实现两个堆栈
结构体定义
struct SNode {
ElementType *Data; /* 需要动态申请 */
Position Top1, Top2;
int MaxSize;
};
初始化:(栈空)
S->Top1 = -1;
S->Top2 = MaxSize;
S->MaxSize = MaxSize;
入栈:
S->Top1++;S->Data[S->Top1] = X;
S->Top2--;S->Data[S->Top2] = X;
出栈:
S->Data[S->Top1--]
S->Data[S->Top2++]
栈满:
S->Top1++=S->Top2
特殊应用特点:
1、需要暂存中间状态
2、可以利用栈的“时进时出”规则
①、符号配对
while (cin >> totalStr && totalStr != ".")遍历所有字符
定义一个新的字符数组str[MAX],并将符合条件的符号装入新的字符数组中
(把特殊符号/**/转化为<>方便判断)
for i = 0 to str[i]!='\0'
若为左符号,入栈st.push(str[i])
若为右符号
若与栈顶元素配对且栈不空,出栈st.pop()
若不配对
判断缺失符号, return false
End for
遍历完且栈空说明完全配对
return true
遍历完栈还没空
ch = st.top(),return false
②、表达式转换
while(遍历输入表达式 != '\0')
判断第一个数是否为负数
带负号直接加入后缀表达式,若带加号之间略过
若str[i]为数字(包括小数点)
加入后缀表达式,空格隔开
若为左括号'('
进栈
判断左括号后第一个数是否为负数
若为乘除或加减
栈顶比较级相同或更大,出栈,自身进栈
若为右括号')'
左括号之后运算符全部出栈
while (!st.empty())栈不空
栈内全部符号出栈
2、队列的存储结构及操作
队列只能选取一个端点进行插入操作,另一个端点进行删除操作
把进行插入的一端称做队尾
进行删除的一端称做队首或队头
队列的主要特点是先进先出,两端都在变化
①顺序队
顺序队结构体定义
typedef struct
{ ElemType data[MaxSize];
int front,rear; //队首和队尾指针
}Queue,*SqQueue;
front指向第一个元素前一个位置,rear指向最后一个元素的位置
若SqQueue Q
队空条件:Q->front = Q->rear
队满条件:Q->rear = MaxSize-1
元素e进队:Q->rear++; Q->data[Q->rear]=e;将e放在rear处
元素e出队:Q->front++; e=Q->data[Q->front];取出front处元素e;
顺序队可能造成假溢出:顺序队可能造成假溢出:若将rear==MaxSize-1作为队满条件时,队中可能还有空位置。
解决方法:
循环队列:
前端和后端连接起来,形成一个环形的顺序表(逻辑上看成一个环,并不是一个真正的环)
优点:更有效利用内存空间
若SqQueue Q
约定队空条件:Q->front = Q->rear
队满条件:(Q->rear+1)%MaxSize = Q->front
进队e操作:Q->rear=(Q->rear+1)%MaxSize; Q->front = Q->rear将e放在rear处
出队操作:Q->front=(Q->front+1)%MaxSize; e=Q->data[Q->front];取出front处元素e;
元素个数count:count=(Q->rear-Q->front+MaxSize)%MaxSize
②链队
数据结点类型DataNode结构体定义
typedef struct qnode
{ ElemType data; //数据元素
struct qnode *next;
} DataNode;
链队结构体定义
typedef struct
{ DataNode *front; //指向单链表队头结点
DataNode *rear; //指向单链表队尾结点
} QuNode, LinkQuNode;
若LinkQuNode Q
队空条件:Q->front=Q->rear=NULL
队满条件:不考虑
进队e操作:p->data=e; p->next=rear->next;rear->next=p;rear=p; 将包含e的结点插入到单链表表尾
出队操作:q=rear->next;x=q->data;rear->next=q->next;free(q);删除单链表首数据结点
③队列应用
c++模板类:queue(链队列)
头文件#include< queue>
queue<int(队列中元素类型)> qu,初始化栈,参数表示
qu.push(x),将x 接到队列的末端。
qu.pop(),弹出队列的第一个元素,注意,并不会返回被弹出元素的值。
qu.front(),访问队首即最早被压入队列的元素。
qu.back(),访问队尾即最后被压入队列的元素。
qu.empty(),判断队列空,当队列空时,返回true。
qu.size(),访问队列中的元素个数
另类循环队列
typedef struct
{ ElementType *Data; /* 存储元素的数组 */
Position Front; /* 队列的头指针 */
int Count; /* 队列中元素个数 */
int MaxSize; /* 队列最大容量 */
} QNode, *Queue;
若Queue Q
队空条件:Q->Count == 0
队满条件:Q->Count == Q->MaxSize
进队e操作:Q->Count++;Q->Data[(Q->Front+Q->Count)%Q->MaxSize] = ;
出队操作:Q->Count--;Q->Front = (Q->Front + 1) % Q->MaxSize;e=Q->Data[Q->Front];
/*这样的环形队列中最多可放置MaxSize个元素*/
3、map容器
头文件#include<map>
提供很好的自动建立一对一(key键值-value映照数据)对应关系,类似hash表,可以实现高效的增删改查功能
定义map:map<key数据类型,value数据类型>MP(名称)
数组方式插入:MP[key]=value
容器大小:MP.size()
搜索key为x的元素:MP.find(x)
清空容器:mp.clear();
4、string型(不以'\0'结尾)
include \<string\>
string s1;
string s2;
字符串连接:s1+s2
//s1 + “ and ” + s2 + ‘e’
字符串比较:s1==s2;s1!=s2
返回字节/字符数量,代表该字符串的长度:s1.length()/s1.size()
判断是否为空:empty()
1.2.谈谈你对栈和队列的认识及学习体会。
对栈和队列的认识:
栈(Stack):之能在表的一端进行插入和删除操作的线性表(物品叠放,叠在最上面的可先取)先进后出
队列(Queue):只能在表的一端进行插入和另一端删除操作的线性表 (类似于排队取票,先排的可以先取票)先进先出
学习体会:
学完栈和队列,可以理解运用基本操作出入栈,出入队等,但是在实际应用上还不是很熟练,比较没思路
我感觉栈和队列也是画图很重要画图很重要
栈和队列注意点:
1、在出入数据时,要判断是满或空后再进行操作
2、链式储存可以不考虑最大容积,但是若知道具体数量,顺序存储还是比较方便
3、环形队列时,进队的元素可能被覆盖,所以如果需要用队列中全部进队的元素求解问题,应该采用非环形队列(例如用队列求解迷宫路径)
2.PTA实验作业
2.1.题目1: 7-4 符号配对
2.1.1代码截图
2.1.2本题PTA提交列表说明。
1、编译错误:使用string型变量头文件没加#include
2、输出答案错误:应该缺左符号输出右符号,缺右符号输出左符号
3、/符号判断错误:/字符不好判断,两端都是/(原本思路是想用一个字符串表示/符号,后来遍历太乱了没成功,后来就改成把/转为 < 符然后再进行判断)
4、没有及时输出不配对符号,而输出了最后一个不配对的左符号:
(例如 { ( } [ 应输出 ( 而不是 [ 在遍历时检测到不匹配符号应立即输出
2.2 题目2: 7-5 表达式转换
2.2.1代码截图
2.2.2本题PTA提交列表说明。
1、运行超时:遍历到‘)’时只出栈了()之间的运算符,在区间运算符出栈后‘(‘没出栈,导致死循环
2、没考虑小数点部分:在数字入后缀表达式的判断语句中再添加一条小数点也可直接入后缀表达式
3、正负号输出错误:负号要输出,而正号应该则直接舍去;原本只考虑符号输出,正号没处理,导致程序把正号当作运算符处理
3.阅读代码
3.1 求前缀表达式的值
3.1.1 该题的设计思路
3.1.2 该题的伪代码
将表达式存入数组ch中
while((c=getchar())!= '\n')
ch[i++] = c;
从后往前遍历数组
for j=i-1 to j>=0
若为空格 continue
若为数值
判断当前数为几位数,是否为小数或负数
若为加减乘除
栈顶元素出栈
double temp = st1.top()
st1.pop();
出栈元素和当前栈顶元素运算
st1.qush()将运算后的数值入栈
end for
保留一位小数输出结果printf("%.1lf",st1.top());
3.1.3 运行结果
3.1.4分析该题目解题优势及难点。
优势:
利用栈保存中间量
if-else结构分明,可读性强
小数和多位数处理很巧妙
难点:
需要考虑小数和负数的情况
1、小数:因为是按字符输入,例如小数3.2 的格式为3.2,这里‘.’的前后没有空格,但是读取是从右至左,所以会先读到2然后是‘.’,最后是3;所以只需要让2变成0.2,然后再加上3
2、负数:例如-1 格式是就是-1 中间也没有空格;遍历时如果遇到数字和‘-’挨着,那就一定是负数
3.2 列车调度
3.2.1 该题的设计思路
3.2.2 该题的伪代码
逆序入栈s1,s2
s1.push(src[i]);
s2.push(dst[i]);
若道2不为空while (!s2.empty())
若道1车厢未完全移出if (!s1.empty())
如果S1和S2栈顶元素相同,记录输出1->2,s1,s2出栈pop()
若s3和S2栈顶元素相同,记录输出3->2,s3,s2出栈pop()
否则S1栈顶元素入栈到S3,s1出栈
当S1为空
若s3和S2栈顶元素相同,记录输出3->2,s3,s2出栈
若S2和S3的栈顶元素不想等,说明不能成功
3.2.3 运行结果
3.2.4分析该题目解题优势及难点。
优势:
利用栈保存中间量
栈运用熟练
c++的vector库应用,存储移动路径
难点:
读题并理解是一个问题
设计移动路线,且能够直接1->2不能用1->3,3->2表示
栈应用要非常熟练