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

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

  • 相关阅读:
    FetchApi 和XHR的主要区别
    关于面试mysql优化的几点纪要
    Python学习第二天数组
    windows7__32位下安装python2.6.6
    一致性哈希算法运用到分布式
    2019年的前端面试总结
    ant design vue + ts 时遇到的坑之from 表单
    vue/cli3 + typescript 中watch prop component computed 的用法
    简易的数据追踪和并发
    基于角色的安全体系
  • 原文地址:https://www.cnblogs.com/gdlkblue/p/12547566.html
Copyright © 2020-2023  润新知