DS博客作业02--栈和队列
0.PTA总分
1.本周学习总结
1.1 总结栈和队列内容
- 栈的存储结构及其操作
先进后出。栈只能在栈顶进行删除(pop),插入(push)操作。
顺序栈
- 顺序栈的结构定义
typedef struct
{
int data[MAXSIZE];
int top;//栈顶元素位置
}SqStack,*Stack;
- 顺序栈的初始化
void InitStack(Stack &S)
{
S->top=-1;
}
- 顺序栈的插入
bool PushStack(Stack &S,int e)
{
if(s->top==MAXSIZE)return false;//当栈达到最大容量
S->top++;
S->data[S->top]=e;
return true;
}
- 顺序栈的删除
bool PopStack(Stack &S,int e)
{
if(s->top==-1)return false;//当栈空时
S->top++;
S->data[S->top]=e;
return true;
}
链栈
- 链栈的定义
typedef struct StackNode
{
int data;
struct StackNode *next;
}LinkStack,LStack;
- 链栈的初始化
void InitStack(LStack &S)
{
S=new LinkStack;
S->next=NULL;
}
- 链栈的插入
bool push(LStack &S,int e)
{
LStack temp;
temp=new LinkStack; //结点申请空间
temp->data=e;
temp->next=S->next; //采用头插法存储元素
S->next=temp;
return ture;
}
- 链栈的删除
bool pop(LStack S,int *e) //栈顶元素出栈
{
LStack temp;
if(S->next==NULL)return fasle;
temp=S->next;
*e=temp->data;//储存出栈元素
S->next=temp->next;
free(temp);
return true;
}
- C++ STL stack
c++ stl栈stack的头文件为:
#include <stack>
c++ stl栈stack的成员函数介绍
s.empty() 堆栈为空则返回真
s.pop() 移除栈顶元素
s.push() 在栈顶增加元素
s.size() 返回栈中元素数目
s.top() 返回栈顶元素
- 栈的应用
1.递归:如n的阶乘;n的k次幂;斐波那契数列等。
int fun(int n)//计算斐波那契数列第n项的值
{
if(n==1||n==2)
{
return 1;
}
else
{
return fun(n-1)+fun(n-2);
}
}
2.表达式求值;括号匹配;进制转换等。
以十进制转二进制为例
- 队列的存储结构及其操作
先进后出,只允许在队头出队,在队尾入队。
循环队列(本质就是顺序队列)
循环仅是通过对数组下标的循环实现。
- 循环队列的定义
typedef struct Queue
{
int data[MaxSize];
int fornt; //队头指针
int rear; //队尾指针
}SeqQueue,*Sq;
- 循环队列的初始化
void InitQueue(Sq &Q)
{
Q->fornt = Q->rear = -1; //把对头和队尾指针同时置0
}
- 循环队列的插入
bool EnQueue(Sq &Q,int e)
{
if ((Q->rear+1)%MAXSIZE==Q->front)return false; //队列已满
Q->rear=(Q->rear+1)&MAXSIZE; //队尾指针后移一位
Q->data[Q->rear] = e; //在队尾插入元素data
}
- 循环队列的删除
这里的删除并没有真正意义上的删除,仅是改变下标而已
bool DeQueue(Sq Q,int *e)
{
if(Q->front==Q->rear)return false; //队列为空
Q->fornt = (Q->fornt+1)%MAXSIZE; //队头指针后移一位
*e = Q->data[Q->fornt]; //出队元素值
return true;
}
![](https://img2020.cnblogs.com/blog/1774965/202003/1774965-20200322133012095-723371142.png)
链队列
- 链队列的定义
typedef struct Node
{
int data;
struct Node* next;
}LinkQueueNode,*LQNode;
typedef struct
{
LQNode front;//队头指针
LQNode rear;//队尾指针
}LinkQueue,*LQ;
- 链队列的初始化
void InitLQueue(LQ &Q)
{
//创建一个头结点
LQ Head = new LinkQueueNode;
Q->front = Q->rear = Head; //队头和队尾指向头结点
Q->front->next = NULL;
}
- 链队列的插入
void EnLQueue(LQ &Q, int e)
{
//创建一个新结点
LQ temp = new LinkQueueNode;
temp->data = data; //将数据元素赋值给结点的数据域
temp->next = NULL; //将结点的指针域置空
Q->rear->next = temp; //将原来队列的队尾指针指向新结点
Q->rear = temp; //将队尾指针指向新结点
}
- 链队列的删除
bool DeleteLQueue(LQ &Q,int* e)
{
if (Q->front->next == NULL)return false;//队空返回错误
LQ temp = Q->front->next;
*e = temp->data; //将要出队的元素赋给e
Q->front->next = temp->_next; //使指向头结点的指针指向temp(被删除节点)的下一个结点
if (Q->rear == temp) //如果队列中只有一个元素,将队列置空
{
Q->rear = Q->front;
}
free(temp); //释放temp指向的空间
}
- C++ STL queue
c++ stl栈queue的头文件为:
#include <queue>
c++ stl栈queue的成员函数介绍
q.empty() 堆栈为空则返回真
q.push(); 在末尾加入一个元素
q.front(); 返回第一个元素
q.back();返回最后一个元素
q.pop(); 删除第一个元素
q.size();返回队列中元素的个数
-
队列的应用
1.如PTA中银行问题,迷宫的广度搜索等。
1.2 栈和队列的认识及学习体会。
刚开始接触的时候感觉还算可以,能理解其具体的含义跟部分操作,但越往后遇见更加实际的问题如PTA银行问题等,突然感觉难度就上来了。发现要想把栈跟队列各种操作熟悉运用,以及相应题目如何定义合适的结构体还是有一段距离。
2.PTA实验作业
2.1 7-3 jmu-ds-符号配对
2.1.1 代码截图
2.1.2本题PTA提交列表说明
1.部分正确:3/5的代码不知道如何使用栈的知识经行编写,没有涉及到出入栈等。仅仅做了简单的个数判断,导致代码完全不能符合题意。
2.编译错误:3/9 开始真正使用栈来进行操作,这里的两个编译错误是因为PTA编译器没有选择C++导致。
3.段错误:经过调试后才发现C++的cin无法读入回车,导致程序运行不下去。后来还是改用scanf函数。
4.段错误:采用scanf函数时忘记添上&。
5.答案正确:虽然说已经正确,但是代码较为繁琐。到3/16,我想加入map或许能简化代码。
6.编译错误:一个是没有设C++编译器,另一个是map头文件不小心大写导致。
7.答案正确。
2.2 7-5 表达式转换
2.2.1 代码截图
2.2.2本题PTA提交列表说明
1.部分正确(5分):刚开始的代码只能说是写了一个整体的思路,并没有深入完善到正负号,以及空格的处理也不准确。根据测试点逐步完善。
2.部分准确(17分):我将正负判断先放一边,先从简入手,根据样例进行简单的处理。在嵌套括号中,我每当输出是忘记将 ’(‘ 出栈,导致错误。这个问题也提交了好几次才看出来。解决:每次输出完,栈顶若是’(‘则出栈。
3.部分正确(22分):这次处理完嵌套循环问题。开始写正负号相关代码,采用判断两个连续的运算符,将后一个运算符存入。
4.部分正确(22分):没有考虑到+号无需输出,所以改成仅有 - 号输出。
5.部分正确(22分):这中间其实卡了一会儿不知道从何下手,于是去完善一个数字测试点。由于是数字是字符类型,不好判断是否仅有一个数字。随后我采用判断前一个是数字后一个是字符时才输出空格。
6.部分正确(6分):虽然解决一个数字,但其他测试点显示格式错误。后来我想倒不如每次数字输出完输出空格,每次运算符输出完输出空格,将所有结果保存一个输出数组out中,最终输出时仅需输出到out长度前一位即可,省去很多不必要的讨论。在此也考虑到了正负号问题可能出现’+ (‘情况,这会将 ( 输出导致错误。随后添加判断,当后一个运算符非(并且是 - 时存入out。
7.答案正确。:这算是写的心累的一题有好多坑都踩了一遍。
3.阅读代码
3.1 1381. 设计一个支持增量操作的栈
代码
3.1.1 该题的设计思路
出入栈操作直接调用stack容器中的函数,当遇到增量操作时,无需暴力遍历累加,只需在pop时累加即可。
空间复杂度O(n)时间复杂度O(n)
3.1.2 该题的伪代码
//由于该部分主要核心代码为pop 跟inc。所以其余操作函数不做解释。
int pop()
{
if 栈空 return-1;
else
{
记录val值;
val=val+栈顶值;
st.pop();
return val;
}
}
void increment(int k, int val)
{
取k跟s.size中的最小值
if 栈空 返回
else
{
储存当前第k个元素的val值
}
}
3.1.3 运行结果
3.1.4分析该题目解题优势及难点。
在leetcode上面看该题的题解时发现大多数人是用数组完成,增量操作时将所有k个数都进行了增加。直到我看到了这份代码,该代码熟悉使用栈,使得增量操作时变得更加有效率。
难点即在于增量操作时如何不用暴力累加,提升效率。
3.2 406. 根据身高重建队列
代码
3.2.1 该题的设计思路
先排序,然后插入。
假设候选队列为 A,已经站好队的队列为 B.
从 A 里挑身高最高的人 x 出来,插入到 B. 因为 B 中每个人的身高都比 x 要高,因此 x 插入的位置,就是看 x 前面应该有多少人就行了。
由于有些函数看不太懂,复杂度具体也不太清楚;时间复杂度O(n) 空间复杂度O(n)
3.2.2 该题的伪代码
先将队伍按身高降序,人数升序排列;//记为A队
for 遍历A队
{
按 前面人数多少 进行插入B队
}
3.2.3 运行结果
3.2.4分析该题目解题优势及难点。
难点在于如何对数据进行预处理。起初我看到题目时,没有想到可以按身高降序,人数升序排列经行预处理。这也使得我也不懂得如何解决。直到看题解中解析后才恍然大悟。