0.PTA得分截图
1.本周学习总结(0-4分)
1.1 总结栈和队列内容
栈的存储结构及操作
- 栈就好像是一个杯子,只有一边是通的,你往里面放东西,一个个放进去,也只能一个个拿出来,先放进去的在杯子底部,后放进去的反而在上面,也就是所谓的先进后出。
- 栈,在出栈进栈时要判断是否为空,如果是顺序栈,要注意栈满。
顺序栈:在内存中用一组地址连续的存储单元依次存放从栈底到栈顶的元素
- 定义:
虽然它这个定义像是用到了数组的样子,但它并不是数组,也并不能够像数组那样用下标来取对应位置的元素,它惟一能够取到的数,是栈顶的元素。typedef struct { ElemType data[MaxSize]; int top; //存放栈顶元素在数组中的下标 }SqStack;
- 主要:
- 栈空条件:top=-1
- 栈满条件:top=MaxSize-1
- 进栈e操作:top++; 将e放在top处
- 退栈操作:从top处取出元素e; top--;
基本操作:
- 初始化:
void InitStack(SqStack &s){ s=(SqStack *)malloc(sizeof(SqStack)); s->top = 0; }
- 进栈:
int Push(SqStack &S,ElemType e) /*将数据元素e压入栈顶*/ { if(S.top==MaxSize) return 0; S.elem[S.top]=e;/*栈是先存后加下标*/ S.top++; return 1; }
- 出栈:
int Pop(SqStack &s,ElemType &e)/*若栈不空,则删除S的栈顶元素,用e返回其值,并返回1,否则返回0*/ { if(S.top !=0)/*栈空*/ { return 0; } else { S.top--; e= S.elem[S.top]; } return 1; }
- 取栈顶元素:
int GetTop(SqStack &S,ElemType &e) { if(S.top == 0) return 0; e=S.elem[S.top-1]; return 1; }
链式栈:优点是不存在栈满上溢出的情况。
- 定义:
typedef struct linknode { ElemType data; struct linknode *next; }LinkStNode; /*链栈的结点类型*/
基本操作:
- 初始化:
void InitStack(LinkStNode &s) { s= (LinkStNode *)malloc(sizeof(LinkStNode)); s->next = NULL; }
- 进栈:不需要判断是否满栈,它没有上限
void Push(LinkStNode &s,ElemType e) { LinkStNode *p; p=(LinkStNode *)malloc(sizeof(LinkStNode)); //新建结点 p->data = e; p->next =s->next; /*将结点p插入到头结点之后*/ s->next = p; }
- 出栈:需要判断是否为空
void Pop(LinkStNode &s,ElemType &e) { LinkStNode *p; if(s->next == NULL) return 0; p = s->next; e= p->data; /*存数据*/ s->next = p->next; free(p); /*释放被删结点的存储空间*/ return 1; }
- 取栈顶元素:
void GetTop(LinkStNode &s,ElemType &e) { if(s->next == NULL) return 0; e = s->next->data; return 1; }
- 判断是否为空:
bool StackEmpty(LinkStNode *s) { return (s->next== NULL); }
stack(使用时不要忘记带括号)
- 头文件:
#include<stack>
- 定义:
stack<类型> 变量名;
- bool empty() const:判断栈是否为空;如
p.empty()
- size_type size() const:返回栈中元素数量;如
p.size()
- value_type& top();const value_type &top() const;返回栈顶元素;如
p.top()
注:并没有删除 - void push(const value_type& val):在栈顶插入一个元素;如
p.push(需要插入的数)
- void pop()出栈,即删除栈顶元素;如:
p.pop()
;注:如果有用到栈顶元素,需要先取栈顶再出栈
栈的应用
- 表达式的转换;判断字符串是否对称(回文也可以用);迷宫问题找多条路径···
- 简单举例:如:7-2 jmu-字符串是否对称
-
图示:
-
具体代码:
-
队列的存储结构及操作
- 队列像一个管道,有两个通路,一边只允许进,一边只允许出,从一端进去,另外一端出来,也就是先进先出。跟它的名字相匹配,它的元素进出规则就像是排队一样,谁先到,谁先出来。
- 要注意的是,它只允许对队头和队尾进行操作,队头只能出,队尾只能进。
- 顺序栈的删除其实并非实际上的“删除”,而是修改了队头。
顺序队列
-
主要:
- 队空条件:front = rear
-队满条件:rear = MaxSize-1
-元素e进队:rear++; data[rear]=e;
-元素e出队:front++; e=data[front];
- 队空条件:front = rear
-
判断是否为空:front == rear 即为空;判断是否为满:(rear+1)%MaxSize == front 即为满
- 定义:
struct QueueNode { ElementType *Data; int MaxSize; int front; int rear; };
- 建空队列:
struct QueueNode* createQueue() { struct QueueNode* q=malloc(sizeof(struct QueueNode)); q->Data=(ElementType*)malloc(MaxSize*sizeof(ElementType)); q->front=q->rear=0; q->MaxSize=Size; return q; }
- 判断是否满:
bool isFull(struct QueueNode* q) { return ( q->rear==MaxSize-1 ); }
- 判断是否空:
bool isEmpty(struct QueueNode* q) { return ( q->rear == q->front ); }
- 入队:
void addQueue(struct QueueNode* q,ElementType x) { if (isFull(q)) { return false; } else { q->rear = (q->rear+1)%q->MaxSize;/*先加再入*/ q->Data[q->rear]=x; } }
- 出队:
ElementType deleteQueue(struct QueueNode* q) { if (isEmpty(q)) { return false; } else { q->front = (q->front+1)%q->MaxSize; return q->Data[q->front]; } }
-
循环队列:
- 定义:
typedef int QElemType; typedef struct { QElemType data[MAXSIZE]; int rear; //头指针 int front; //尾指针,若队列不为空,指向队尾元素的下一个元素 }SqQueue;
- 初始化:
Status InitQueue(SqQueue *Q) { Q->rear = 0; Q->front = 0; return OK; }
- 入队:
Status insertQueue(SqQueue *Q, QElemType e) { if ((Q->rear + 1) % MAXSIZE == Q->front)/*需要判断队列是否已满*/ { return ERROR; } Q->data[Q->rear] = e; Q->rear = (Q->rear + 1) % MAXSIZE; return OK; }
- 出队:
Status deleteQueue(SqQueue *Q, QElemType *e) { if (Q->rear == Q->front) /*需要判断是否为空*/ { return ERROR; } *e = Q->data[Q->front]; Q->front = (Q->front + 1) % MAXSIZE; return OK; }
链式队列
- 定义:
typedef int QElemType;
typedef struct QNode { /*结点结构*/
QElemType data;
struct QNode *next;
}QNode;
typedef struct QNode * QueuePtr;
typedef struct { /*队列的链表结构*/
QueuePtr rear;
QueuePtr front;
}LinkQueue;
基本操作:
- 建空队列:
struct QueueNode* createQueue()
{
struct QueueNode* q=malloc(sizeof(struct QueueNode));
q->front = q->rear = NULL;
q->size=0;
return q;
}
- 入队:
Status EnQueue(QueuePtr Q, QElemType e)
{
QueuePtr q = (QueuePtr)malloc(sizeof(QNode));
if (!q)/*存储分配失败*/
{
exit(OVERFLOW);
}
q->data = e;
q->next = NULL;
Q->rear->next = q;
Q->rear = q;
return OK;
}
- 出队:
Status DeQueue(QueuePtr Q, QElemType *e)
{
QueuePtr q;
if (Q->rear == Q->front) /*判断是否为空队列*/
{
return ERROR;
}
q = Q->front->next; /*q指向第一个结点*/
*e = q->data;
Q->front->next = q->next;
if (Q->rear == q)/*若队头就是队尾,删除后,需要将rear指针指向头结点*/
{
Q->rear = Q->front;
}
free(q);
return OK;
}
queue(同样,在使用时不要忘记带括号)
- 头文件:
#include<queue>
- 定义:
queue<类型> 变量名;
- bool empty() const判断队列是否为空;如
p.empty()
- size_type size() const返回队列中元素个数;如
p.size()
- value_type& front();const value_type& front() const;返回队列中第一个元素,即最后插入到队列中的那个元素;如
p.front()
- value_type& back(); const value_type& back() const;返回队列中最后一个元素,即最先入队的那个元素;如
p.back()
- void push (const value_type& val)插入一个新元素在队尾;如
p.push(需要插入的数)
- void pop()移除队首元素;如:
p.pop()
队列应用
- 报数游戏;银行业务模拟;迷宫问题找最短路径···
- 简单举例:如:7-6 jmu-报数游戏
-
图示:
-
代码如下:
-
1.2.谈谈你对栈和队列的认识及学习体会。
- 栈和队列,作为容器,在解决某些问题的时候,真的很好用,只要理清楚思路,用对应的函数可以很快解决问题。(如果它允许我用那些写好的函数的话)但是在使用的时候,要常判断它是否为空或是已满(个别情况不用判断满),而且要记得,引用函数的时候,需要加上括号(或是按照对应格式),不能忘记!!!用栈和队列解决问题,我个人认为,它是很灵活的,我们要学会用它,不仅要吃透它的那些基本操作,也要摸清楚它的适用类型,在遇到题目时,根据它们的特点来决定是否用到它们。(我可能还不够灵活就是了。。)目前的话,我们是按照模块学的,老师给的题目也都是对应的、分类好的,但是总有一天,当我们需要独自解决问题的时候,我们就需要自己判断对应题目需要用对应的哪种方法来解决了。
2.PTA实验作业(0-2分)
2.1.7-4 符号配对
2.1.1代码截图
2.1.2本题PTA提交列表说明。
错误分析说明:
- 部分正确:忘记在缺少左边符号时,也需要考虑输出的是不是,(我用来代替/和/)
- 部分正确:死循环了,我的输入出了问题,while(1)跳不出去,停不下来。
- 部分正确:我以为是我没有考虑遇到换行符也结束的情况,但是其实是我的换行符全被吸收掉了。
- 答案正确:我把cin.get()换成了cin,这样就不会读如换行符,没有了干扰。
2.2 7-5 表达式转换
2.2.1代码截图
2.2.2本题PTA提交列表说明。
错误分析说明:
- 部分正确:出现段错误,即访问错误,这里的问题是,我在取栈顶的时候,忘记判断栈是否为空了。
- 部分正确:我这会儿是改了一小个地方,然后粘贴过了的时候,按成了Ctel+C,然后提交。(我为什么会知道呢,因为我看提交的代码的时候,发现我改的地方没有变化)
- 部分正确:然后我就又复制了一遍,改动的地方,是我判断正负数的时候,有用到字符串下标的
i-1
,我以为我没有判断它造成了段错误,其实不是。 - 部分正确:这会儿没有段错误了,但我的正负数出错了,我就上网找了一份代码,把出现负数的例子运行得到的结果和我自己的对比,然后我就发现,如果正数前面有
+
,这个正号不用输出。我那会儿有点懵,但是真的很想吐槽,这种输出上面的要求,题目就不能给嘛!! - 答案正确:然后我把判断符号为正的那部分代码改了改,让它遇到正号不输出,答案就正确了。
注:这道题给我提了个醒,不仅在出队的时候需要判断队列是否空,在取队列首元素的时候,也需要判断,不能忘记啊!!
3.阅读代码(0--4分)
找2份优秀代码,理解代码功能,并讲出你所选代码优点及可以学习地方。主要找以下类型代码:
考研题
PTA赛题目,可以自己做法,实现 不了也可以找题解研究。题目放2019-ds-难题集中.
ACM题解
leecode--栈
leecode--队列
注意:不能选教师布置在PTA的题目。完成内容如下。
3.1 题目及解题代码
-
题目:
-
代码:
3.1.1 该题的设计思路
3.1.2 该题的伪代码
思路:
if 两个序列长度是否相同
如果不同直接返回false
end if
建一个新栈
先把pushed序列的第一个元素存入新栈
for 0 to poped序列结束
if 新栈不为空
while 新栈的栈顶不等于poped序列当前需要出栈的元素
if pushed序列已经全部入栈
说明序列出栈顺序不匹配,直接返回false
end if
将pushed序列的下一个元素入新栈
end while
将栈顶元素出栈
end if
if poped序列每个元素都可能出栈
返回true
end if
if 栈为空
if pushed序列已经全部入栈
说明序列出栈顺序不匹配,直接返回false
end if
将pushed序列的下一个元素入新栈
end if
end for
for循环正常执行完毕,说明poped序列可能存在,返回true
3.1.3 运行结果
3.1.4分析该题目解题优势及难点。
- 优势:我们学过栈的出入特点,也做过对应的选择填空题,对这一道题目的做法有比较清楚的思路,不同的是,现在需要把我们的思路改写成为代码。
- 难点:
- 我们要知道,什么时候可以判定栈的输出序列不成立
- 怎样定位比较两个序列的元素
- 入栈顺序一定,怎样确定出栈顺序?
- 当比较两个序列的元素不同时,应该怎么样处理
3.2 题目及解题代码
-
题目:
-
代码:(我真的不敢相信,它真的就这么短!!!)
3.2.1 该题的设计思路
- 思路:因为身高矮的人,不会影响高的人的k值,比较矮的人才需要考虑k值的变化。所以先把高的人排好之后,再排矮的。
3.2.2 该题的伪代码
//有身高h和队伍前比这个人高的人数k
定义一个函数sort先按照升高的降序排列,同等身高的,按照k值的递增排序
for 身高的最大值 to最小值
定义一个函数用于插入,根据k值决定插入顺序
//比如k=0,则这个人先入队,原队列再入队,k=3,则原队列先入队3人,然后这个人入队,剩下的人再入队
end for
3.2.3 运行结果
3.2.4分析该题目解题优势及难点。
- 优势:
最开始题目就让我有点懵,然而它只是个中等难度排序我们做过很多次,学过的方法也很多,自己的思路可能会有点复杂,但是应该也能做出来。 - 难点:
- 我们应该先怎么排,先排高的还是矮的
- 怎么安排k值
- 排序时应该根据什么来排
- 插入队列时,应该怎么插?