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分析该题目解题优势及难点。

难点在于如何对数据进行预处理。起初我看到题目时,没有想到可以按身高降序,人数升序排列经行预处理。这也使得我也不懂得如何解决。直到看题解中解析后才恍然大悟。

posted @ 2020-03-22 18:36  1911-黄荣煌  阅读(219)  评论(0编辑  收藏  举报