zoukankan      html  css  js  c++  java
  • DS博客作业02--栈和队列

    0.PTA得分截图

    1.本周学习总结(0-4分)

    1.1 总结栈和队列内容:

    1.1.1 栈

    • 栈的定义:
      栈的本质还是线性表:限定仅在表尾进行插入或删除操作。 俗称:后进先出 ,也可说是先进后出。
    • 栈的声明(栈的声明有两种):
      第一种:
    typedef struct sta
    {
        int stack[SIZE];    /* 存放栈中元素的一维数组 */
        int top;            /* 存放栈顶元素的下标 */
    }stack;
    

    第二种:

    typedef struct sta
    {
        int *top;            /* 栈顶指针 */
        int *bottom;        /* 栈底指针 */
        int stack_size;        /* 栈的最大容量 */
    }stack;
    
    • 栈的分类:
      与线性表同样的,栈也分为顺序和链式两大类。其实和线性表大同小异,只不过限制在表尾进行操作的线性表的特殊表现形式。
    • 顺序栈:
      利用一组地址连续的存储单元依次存放自栈底到栈顶的数据元素,同时附设指针 top 指示栈顶元素在顺序栈中的位置,附设指针 base 指示栈底的位置。 同样,应该采用可以动态增长存储容量的结构。且注意,如果栈已经空了,再继续出栈操作,则发生元素下溢,如果栈满了,再继续入栈操作,则发生元素上溢。栈底指针 base 初始为空,说明栈不存在,栈顶指针 top 初始指向 base,则说明栈空,元素入栈,则 top++,元素出栈,则 top--,故,栈顶指针指示的位置其实是栈顶元素的下一位(不是栈顶元素的位置)。
    • 链式栈:
      其实就是链表的特殊情形,一个链表,带头结点,栈顶在表头,插入和删除(出栈和入栈)都在表头进行,也就是头插法建表和头删除元素的算法。显然,链栈还是插入删除的效率较高,且能共享存储空间。

      是栈顶在表头!栈顶指针指向表头结点。栈底是链表的尾部,base 就是尾指针。还有,理论上,链式结构没有满这一说,但是理论上是这样的,也要结合具体的内存,操作系统等环境因素。
    • 栈的基本操作函数(仅针对顺序栈):
      • InitStack(&s):初始化栈。构造一个空栈s。
        函数实现:
    void InitStack(SqStack &s)
    {  s=new Stack;     
        s->top=-1;
    } 
    
    • DestroyStack(&s):销毁栈。释放栈s占用的存储空间。
      函数实现:
    void DestroyStack(SqStack &s)
    {
      delete s;
    }
    
    • StackEmpty(s):判断栈是否为空:若栈s为空,则返回真(1);否则返回假(0)。
      函数实现:
    bool StackEmpty(SqStack s)
    {
      return(s->top==-1);
    }
    
    • Push(&S,e):进栈。将元素e插入到栈s中作为栈顶元素。
      函数实现:
    bool Push(SqStack &s,ElemType e)
    {
      if (s->top==MaxSize-1)  
        return false;
       s->top++;           //栈顶指针增1
       s->data[s->top]=e;     
       return true;
    }
    
    • Pop(&s,&e):出栈。从栈s中退出栈顶元素,并将其值赋给e。
      函数实现:
    bool Pop(SqStack &s,ElemType &e)
    {
       if (s->top==-1)  //栈为空的情况,栈下溢出
        return false;
       e=s->data[s->top];//取栈顶指针元素     
       s->top--;        //栈顶指针减1
       return true;
    }
    
    • GetTop(s,&e):取栈顶元素。返回当前的栈顶元素,并将其值赋给e。
      函数实现:
    bool GetTop(SqStack *s,ElemType &e)
    {   
       if (s->top==-1)  //栈为空的情况    
        return false;
        e=s->data[s->top];      
        return true;
    }
    
    • 栈的头文件(C++):stack操作模板:
    #include<stack>
    1.stack<int>  s:初始化栈,参数表示元素类型。//后续的函数引用你的初始化
    2.s.push(t):入栈元素t。
    3.s.top():返回栈顶元素。
    4.s.pop():出栈操作只是删除栈顶元素,并不返回该元素。
    5.s.empty(),当栈空时,返回true。
    6.s.size():访问栈中的元素个数。
    
    • 栈的应用:
      • 字符匹配:在C语言中有一些符号是成对匹配出现的,利用栈可以实现类似编译器括号是否匹配的能力。
      • 小型计算器的实现:将中缀表达式转后缀表达式。
      • 十进制正整数N进制:进制转换可以用很多方法来实现,其中也能用栈的方式实现。

    1.1.2 队列

    • 队列的定义:
      只允许在表的一端进行插入,而在表的另一端进行删除的线性表。

    • 队列的声明:

    struct QNode {
        ElementType *Data;  /* 存储元素的数组   */
        Position Front;     /* 队列的头指针     */
        int Count;          /* 队列中元素个数   */
        int MaxSize;        /* 队列最大容量     */
    };
    
    • 队列的基本操作函数:
      • InitQueue(&Q):构造一个空队列Q。
        函数实现:
    void InitQueue(SqQueue *&Q){  
        Q=(SqQueue *)malloc(sizeof(SqQueue));  
        Q->front=Q->rear=-1;  
    }  
    
    • DestroyQueue(&Q):销毁队列Q。
      函数实现:
    void DestroyQueue(SqQueue *&Q){  
        free(Q);  
    }  
    
    • QueueEmpty(Q):判断队列Q是否为空。
      函数实现:
    void QueueEmpty(SqQueue *Q){  
        return (Q->front==Q->rear);  
    }  
    
    • EnQueue(&Q, e):插入元素e为Q的新的队尾元素。
      函数实现:
    bool EnQueue(SqQueue *&Q,ElemType e){    
        if(Q->rear==MaxSize) return false;   //队满上溢   
        Q->rear++;    
        Q->data[Q->rear]=e;    
        return true;    
    }   
    

    • DeQueue(&Q, &e):删除Q的队头元素,并用e返回其值。
      函数实现:
    bool EeQueue(SqQueue *&Q,ElemType &e){  
        if(Q->front==Q->rear) return false;  
        Q->front++;  
        e=Q->data[Q->front];  
        return true;  
    }  
    

    1.2.谈谈你对栈和队列的认识及学习体会。

    学习了栈和队列,发现两个本质上都是线性表,两者的功能上相似的地方,也有不同的地方。它们都可以用线性表的顺序存储结构来实现,但都存在着顺序存储的一些弊端。
    在对栈和队列的学习中,扩展了眼界,对一些题目有了新的理解,如线性表中6-8 jmu-ds-链表倒数第m个数,如果这题用栈或者队列来编译,将更容易,时间复杂度上将更低,这或许就是算法学习的意义:找到时间复杂度更低的算法来实现要求。
    在对栈和队列的学习后,了解了日常网络中有很多的事情都是可以通过栈和队列实现的,例如网页的返回,就是通过可以栈来实现的。

    2.PTA实验作业(0-2分)

    2.1 7-6 jmu-报数游戏 (15分)

    2.1.1 代码截图

    2.1.2 本题PTA提交列表说明。

    Q1:编译错误
    A1:再次将C++按C提交
    Q2:部分正确
    A2:m>=n的点题目要求输出为error!但我输出为error

    2.2 7-7 银行业务队列简单模拟

    2.2.1 代码截图

    2.2.2 本题PTA提交列表说明。

    Q1:编译错误
    A1:将C++按C提交
    Q2:部分正确
    A2:用了多个while导致运行超时
    Q3:格式错误
    A3:将while删除几个重新编译,但空格没掌握好
    Q4:答案正确
    A4:将空格处理了一下,虽然PTA对了,但我发现我自己输入3个数(两奇一偶)中最后一个偶数后还有空格
    Q5:编译错误
    A5:在上一个代码中加上if判断但用q.empty代码后没加小括号
    Q6:部分正确
    A6:加上一个限定条件后运行发现如果奇数数列不为空时,最后一个偶数和它之后的奇数键没有空格,所以我加在加上了判断奇数数列是否为空的条件,不仅PTA过了,我自己加的测试点也过了

    3.阅读代码(0--4分)

    3.1 题目及解题代码


    解题代码:

    class Solution {
    public:
        bool canMeasureWater(int x, int y, int z) {
            // assumed if z = a * x  + b * y, then return true; otherwise, gives false
            // if x = t1 * __gcd(x,y), y = t2 * __gcd(x,y);
            // z = __gcd(x,y) *  (a * t1 + b * t2) ==> z % __gcd != 0 ==> false
            // x = 3, y = 5, z = 4  ===> z = -1 * x + 2 * y
            // x = 2, y = 6, z = 5  ===> failed
            if (z < 0 || x + y < z) return false;
            if (x == z || y == z || x + y == z) return true;
            return z % __gcd(x, y) == 0; 
        
        }
    };
    

    3.1.1 该题的设计思路

    将本问题转化为ax+by=z是否有解,
    定理:a b x y 均为整数,如果ax+by=z有解,那么z一定是gcd(a,b)的倍数,否则无解。//gcd(a,b)函数为求a和b的公约数的函数
    时间复杂度为:O(log(min(x,y)),取决于计算最大公约数所使用的辗转相除法。
    空间复杂度为:O(1)

    3.1.2 该题的伪代码

    if z小于0或者x+y小于z then
       返回false
    if x等于z或y等于z或x+y等于z then
       返回true
    返回 z是否对x和y的公约数的倍数//即是返回true,否返回false
    

    3.1.3运行结果

    3.1.4 分析该题目解题优势及难点。

    解题优势:该题的设计思路通俗易懂,但凡有点数学基础都能立马通过该解题思路理解复杂的题干要求,在计算最大公约数小的情况加该题的时间复杂度会相对更低。
    难点:如果没想到求z和x,y最大公约数的关系,将会不容易下手,并且可能会陷入僵局。计算最大公约数所使用的辗转相除法大的话,时间复杂度相应增大。

    3.2 题目及解题代码

    解题代码:

    class Solution {
    public:
        bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
            stack<int> st;
            int n = popped.size();
            int j = 0;
            for (int i = 0; i < pushed.size(); ++i){
                st.push(pushed[i]);
                while(!st.empty() && j < n && st.top() == popped[j]){
                    st.pop();
                    ++j;
                }
            }
            return st.empty();
        }
    };
    

    3.2.1 该题的设计思路

    尝试按照 popped 中的顺序模拟一下出栈操作,如果符合则返回 true,否则返回 false。这里用到的贪心法则是如果栈顶元素等于 popped 序列中下一个要 pop 的值,则应立刻将该值 pop 出来。
    使用一个栈 st 来模拟该操作。将 pushed 数组中的每个数依次入栈,同时判断这个数是不是 popped 数组中下一个要 pop 的值,如果是就把它 pop 出来。最后检查栈是否为空。
    时间复杂度:O(N)。将所以元素一遍入栈,一遍出栈,需要 O(2N)。
    空间复杂度:O(N)。使用了辅助栈 st。

    3.2.2 该题的伪代码

    初始化栈st
    定义n并赋值要出栈的数量
    定义j并赋值0
    for 定义i从0到要入栈的数量,完成循环后对i前缀递增
        将push[i]入栈st
        while st栈不为空并且j小于n并且st栈顶等于pop[j]
            将st栈顶出栈
            对j前缀递增
        end while
    end for
    return 判断st栈是否为空的结果
    

    3.2.3 运行结果


    3.2.4 分析该题目解题优势及难点。

    解题优势:思路简单清晰:直接对题目的条件来一边入栈出栈的操作,在调试时更好地去调试。
    难点:时间复杂度和空间复杂度上欠缺,对题目所给的条件设计入栈出栈操作时的循环条件不便于掌控。

  • 相关阅读:
    优化!优化!
    JavaScript 错误
    js 学习总结
    JavaScript join() 方法
    JavaScript shift() 方法
    JavaScript split() 方法
    arTemplate解析语法
    getTime 方法
    PHP 5 数据类型
    thinkphp 实现微信公众号开发(二)--实现自定义菜单
  • 原文地址:https://www.cnblogs.com/ye736660997/p/12542253.html
Copyright © 2011-2022 走看看