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

    这个作业属于哪个班级 数据结构--网络2011/2012
    这个作业的地址 DS博客作业02--栈和队列
    这个作业的目标 学习栈和队列的结构设计及运算操作.
    姓名 陈宇杭

    0. PTA得分截图

    1. 本周学习总结

    1.1 栈

    ① 顺序栈

    • 顺序栈通常用数组来存放数据,栈内数据在栈顶进行交互;

    操作函数

    • 顺序栈结构体
    struct SNode {
        ElementType* Data;  /* 存储元素的数组   */
        Position Top;     /* 栈顶指针 */
        int MaxSize;
    };
    
    • 创建栈并初始化
    Stack CreateStack(int MaxSize)
    {
        Stack S = (Stack)malloc(sizeof(struct SNode));
        S->Data = (ElementType*)malloc(MaxSize * sizeof(ElementType));
        S->Top = -1;//将栈空时的栈顶指针设为 -1 
        S->MaxSize = MaxSize;
        return S;
    }
    
    • 入栈
    void PushStack(Stack S, ElementType x)//入栈
    {
        if (S->Top == S->MaxSize)
        {
            printf("Stack Full
    ");
            return;
        }
        S->Top++;
        S->Data[S->Top] = x;
    }
    
    • 出栈
    ElementType PopStack(Stack S)//出栈,并将栈顶元素作为返回值
    {
        if (S->Top == -1)
        {
            printf("Stack Empty
    ");
            return 0;
        }
        return S->Data[S->Top--];
    }
    
    • 栈空
    int StackEmpty(Stack S)//当栈为空时返回1
    {
        if (S->Top == -1)
            return 1;
        else
            return 0;
    }
    

    ② 链栈

    • 相比于顺序栈,链栈没有预申请空间不足的顾虑;头插法也保证入栈出栈操作的一步到位;

    操作函数
    由于C++标准库的栈函数就是以链栈结构为基础,此处只介绍操作函数;

    #include<stack>//头文件
    stack<int> s;//创建一个int变量类型的链栈 s ;
    s.empty(); //如果栈为空则返回true, 否则返回false;
    s.size(); //返回栈中元素的个数
    s.top(); //返回栈顶元素, 但不删除该元素
    s.pop(); //弹出栈顶元素, 但不返回其值
    s.push(); //将元素压入栈顶,大多是使用头插法
    

    链栈稍微牺牲空间,换来条理分明的结构与更快的操作速度

    1.2 栈的应用

    • 中缀表达式改写为后缀表达式
      在数学计算中,我们习惯与通过中缀表达形式计算算式,即数字在运算符号的两边,而对于计算机而言,后缀表达式更适合处理算式,因此必然有,从中缀表达式到后缀表达式的过程,并且计算机利用后缀表达式计算的过程,,而这些都可以通过栈实现。
      通过一个预先设定好的优先级入栈出栈,'+''-'优先级最低,'*''/'较高,括号内的算式优先级更高,在进行比较出栈入栈操作

    • 括号匹配检验
      在辅助编程的软件中,总会有一个括号匹配的判断检验,如果有括号没有对应的另一半进行配对,编译器就会报错来提醒那些粗心的程序员;而对于括号来说,每一个左括号都需要一个相应的右括号与之匹配,表达式中越迟出现并且没有得到匹配的左括号匹配的优先级越高,这种先进先出的特点正与栈结构匹配;
      基本思路:创建一个栈,在读入字符的过程中,如果是左括号,则直接入栈,等待相匹配的同类右括号;如果是右括号,且与当前栈顶左括号匹配,则将栈顶左括号出栈;

    • 迷宫求解
      对迷宫来说,所有的迷宫都有一个特点,即从入口出发,顺某一方向向前探索,若能走通,则继续往前走;否则沿原路退回,换一个方向再继续探索,直至所有可能的通路都探索到为止;原路返回的操作,显然需要个先进先出的结构来储存上一级信息,所以栈自然可以来求解迷宫;

    伪代码

    初始化,将起点加入堆栈;
    while(堆栈不为空){
        取出栈顶位置为当前位置;
        if(当前位置是终点)
            使用堆栈记录的路径标记从起点至终点的路径;
        else
        {
            按照某个顺序将当前位置下一个可以探索的位置入栈;
            if(当前位置的四周均为死路)
                当前位置出栈;
        }
    }
    

    1.3 队列

    队列是一种特殊的线性表,特殊之处在于它只允许在表的前端进行删除操作,而在表的后端进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头.

    ① 顺序队列

    • 结构体定义
    typedef struct
    {
        ElemType data[MaxSize];
        int front, rear;
    }SqQueue;
    typedef SqQueue* Queue;
    
    • 初始化队列
    void InitQueue(Queue Q)
    {
        Q = (Queue)malloc(sizeof(SqQueue)*Max);
        Q->front = Q->rear = 0;
    }
    
    • 销毁队列
    void DestroyQueue(Queue Q)
    {
        free(Q);
    }
    
    • 判断队列是否为空
    bool QueueEmpty(Queue Q)
    {
        return (Q->front == Q->rear);
    }
    
    • 入队
    bool EnQueue(Queue Q,ElemType e)
    {
        if(Q->rear == MaxSize)
            return false;
        Q->data[Q->rear++] = e;
        return true;
    }
    
    • 出队
    bool DeQueue(Queue Q,ElemType &e)
    {
        if(Q->front == Q->rear)
            return false;
        e = Q->data[Q->front++];
        return true;
    }
    

    ② 环形队列

    • 结构体定义
    typedef struct
    {
        ElemType data[MaxSize];
        int front, rear;
    }SqQueue;
    typedef SqQueue* Queue;
    
    • 初始化队列
    void InitQueue(Queue Q)
    {
        Q = (Queue)malloc(sizeof(SqQueue)*Max);
        Q->front = Q->rear = 0;
    }
    
    • 销毁队列
    void DestroyQueue(Queue Q)
    {
        free(Q);
    }
    
    • 判断队列是否为空
    bool QueueEmpty(Queue Q)
    {
        return (Q->front == Q->rear);
    }
    
    • 入队
    bool EnQueue(Queue Q,ElemType e)
    {
        if((Q->rear +1) % MaxSize == Q->front)
            return false;
        Q->data[Q->rear] = e;
        Q->rear = (Q->rear + 1) % MaxSize;
        return true;
    }
    
    • 出队
    bool DeQueue(Queue Q,ElemType &e)
    {
        if(Q->front == Q->rear)
            return false;
        e = Q->data[Q->front];
        Q->front = (Q->front + 1) % MaxSize;
        return true;
    }
    

    ③ 链式队列

    • 结构体定义
    typedef struct QNode    /* 声明链式队列的结点 */
    {
        int data;
        struct QNode *next;
    }Node;
    typedef struct QueuePoint    /* 声明链式队列的首尾指针 */
    {
        Node *front;
        Node *rear;
    };
    typedef QueuePoint* Queue;
    
    • 初始化队列
    Queue InitQueue (Queue Q)    
    {                        
        Q = (Queue)malloc(sizeof(QueuePoint));
        Q->front = Q->rear = NULL;
    
        return Q;
    }
    
    • 销毁队列
    void DestroyQueue(Queue Q)
    {
        Node* pre = Q->front,* p;
        if(pre != NULL)
        {
            p = pre->next;
            while(p != NULL)
            {
                free(pre);
                pre = p;p = p->next;
            }
            free(pre);
        }
        free(Q);
    }
    
    • 判断队列是否为空
    bool QueueEmpty(Queue Q)
    {
        return (Q->rear == NULL);
    }
    
    • 入队
    void EnQueue(Queue Q,ElemType e)
    {
        Node* p;
        p = (Node*)malloc(sizeof(Node));
        p->data = e;
        p->next = NULL;
        if(Q->rear == NULL)
            Q->front = Q->rear = p;
        else
        {
            Q->rear->next = p;
            Q->rear = p;
        }
    }
    
    • 出队
    bool DeQueue(Queue Q,ElemType &e)
    {
        Node* p;
        if(Q->rear == NULL)
            return false;
        p = Q->front;
        if(Q->front == Q->rear)
            Q->front = Q->rear = NULL;
        else
            Q->front = Q->front->next;
        e = p->data;
        free(p);
        return true;
    }
    

    ④ 队列应用

    • 银行业务队列简单模拟
      某银行有A、B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客。编号为奇数的顾客需要到A窗口办理业务,为偶数的顾客则去B窗口;给出顾客人数与编号,顺序输出顾客办理完成业务的编号;
    创建队列A,B;
    读入人数n;
    for (int i = 0; i < n; i++)//入列
        {
            cin >> numb;
            if (numb % 2 == 1)
                EnQueue(WindowA, numb);//奇数号入A列
            else
                EnQueue(WindowB, numb);//偶数号入B列
        }
    按照AAB的顺序输出即可;
    

    2. PTA实验作业

    2.1 符号配对

    2.1.1 解题思路及伪代码

    • 解题思路
      后缀表达式,顾名思义是运算符在数字后的表达式,即取运算符前的两个数字作为被运算数和运算数;
      在中缀表达式转后缀表达式的过程中,同样需要考虑运算符优先级的问题,这就可能导致优先度高的运算符先于优先度低的运算符输出,先入先出的特性,适合用栈结构来辅助转换;
      令'+'与'-'作为低级运算符,优先度为0;'*'与'/'作为高级运算符,优先度为1;括号内式子优先度最高,在我的思路里将括号内的算式看做新的算式,进行递归转换;
      将按序读取到的运算符与栈顶运算符进行对比,优先度低的运算符入栈,优先度高的运算符输出,优先度相等则先出栈后入栈,遇到括号则递归调用函数;
      数值数据则直接输出,不进行栈操作;

    • 伪代码

    创建字符串并将算式读入字符串内;
    某函数()
    {
        创建并初始化栈;
        遍历字符串
        {
            if(读到''或')')
                返回;
            if(字符为数字,小数点或正负值的符号)
                输出字符;
            else if(栈内为空 或 字符优先级高于栈顶字符)
                入栈;
            else if(字符优先级低于栈顶字符)
            {
                do 出栈并输出 while (字符优先级高于栈顶 或 栈为空);
                入栈;
            }
            else if(字符为左括号)
                递归调用 某函数();
        }
    }  
    
    • 源代码
    展开
    
    #include
    #include
    #include
    #include
    using namespace std;
    #define Max 1000
    #define ERROR -1
    typedef char ElementType;
    typedef int Position;
    struct SNode {
        ElementType* Data;  /* 存储元素的数组   */
        Position Top;     /* 栈顶指针 */
        int MaxSize;
    };
    typedef struct SNode* Stack;
    Stack CreateStack(int MaxSize);
    void EnStack(Stack S, char x);
    char PopStack(Stack S);
    void SymbolPairing(Stack S);
    void NotesSymbol(Stack S);
    int main()
    {
        Stack S;
        S = CreateStack(Max);
        SymbolPairing(S);
        return 0;
    }
    void SymbolPairing(Stack S)
    {
        char chL = 0, chR = 0;
        char leftSymbolL, leftSymbolR;
        while ((chR = getchar()) && chR != EOF)
        {
            if (chL == '.' && chR == '
    ')
                break;
            if (chR == '[' || chR == '{' || chR == '(')
                EnStack(S, chR);
            else if (chL == '/' && chR == '*')
            {
                EnStack(S, chL);
                EnStack(S, chR);
                //NotesSymbol(S);
                chR = ' ';
            }
            else if (chR == ']' || chR == '}' || chR == ')' || (chL == '*' && chR == '/'))
            {
                if (S->Top == -1)
                {
                    cout << "NO" << endl;
                    if (chL == '*' && chR == '/')
                        cout << "?-" << chL << chR << endl;
                    else
                        cout << "?-" << chR << endl;
                    return;
                }
                leftSymbolL = PopStack(S);
                if ((leftSymbolL == '[' && chR != ']') || (leftSymbolL == '{' && chR != '}') || (leftSymbolL == '(' && chR != ')') || (leftSymbolL == '*' && !(chL == '*' && chR == '/')))
                {
                    cout << "NO" << endl;
                    cout << leftSymbolL << "-?" << endl;
                    return;
                }
                else if (leftSymbolL == '*')
                {
                    if (chL == '*' && chR == '/')
                        PopStack(S);
                    else
                    {
                        cout << "NO" << endl;
                        cout << PopStack(S) << leftSymbolL << "-?" << endl;
                        return;
                    }
                }
                chR = ' ';
            }
            chL = chR;
        }
        if (S->Top != -1)
        {
            cout << "NO" << endl;
            if (S->Data[S->Top] != '*')
                cout << PopStack(S) << "-?" << endl;
            else
                cout << PopStack(S) << PopStack(S) << "-?" << endl;
        }
        else
            cout << "YES" << endl;
        return;
    }
    Stack CreateStack(int MaxSize)
    {
        Stack S = (Stack)malloc(sizeof(struct SNode));
        S->Data = (ElementType*)malloc(MaxSize * sizeof(ElementType));
        S->Top = -1;
        S->MaxSize = MaxSize;
        return S;
    }
    void EnStack(Stack S, char x)
    {
        if (S->Top == S->MaxSize)
        {
            printf("Stack Full
    ");
            return;
        }
        S->Top++;
        S->Data[S->Top] = x;
    }
    char PopStack(Stack S)
    {
        if (S->Top == -1)
        {
            printf("Stack Empty
    ");
            return 0;
        }
        return S->Data[S->Top--];
    }
    /*void NotesSymbol(Stack S)
    {
        char chL = 0, chR = 0;
        while ((chR = getchar()) && chR != EOF)
        {
            if (chL == '.' && chR == '
    ')
            {
                cout << "NO" << endl;
                cout << PopStack(S) << PopStack(S) << "-?" << endl;
                exit(0);
            }
            if (chL == '*' && chR == '/')
            {
                PopStack(S);
                PopStack(S);
                return;
            }
            chL = chR;
        }
    }*/
    

    2.1.2 总结解题所用的知识点

    • 四则运算法则;
    • 顺序栈的结构;
    • 顺序栈的出栈入栈操作;
    • 递归函数的调用;
    • 标准输入输出流的运用;

    2.2 符号配对

    2.2.1 解题思路及伪代码

    • 解题思路
      这题啊,这题比上面那题好搞多了;
      弄两个队列A、B,读入数据,将奇数编号的入A列,将偶数编号的入B列;
      在按A、A、B的顺序输出(若队列为空则跳过);
      结束
    • 伪代码
    创建队列 A, B;
    读入人数 n;
    for(从0到n)
    {
        读入数据x;
        如果x为奇数
            入A列;
        如果x为偶数
            入B列;
    }
    按AAB的顺序输出;
    结束;
    
    • 源代码
    展开
    
    #include
    #include
    #include
    #include
    using namespace std;
    #define Max 2000
    #define ERROR -1
    typedef int ElementType;
    typedef int Position;
    struct QNode {
        ElementType* Data;  /* 存储元素的数组   */
        Position Front, rear;     /* 队列的头、尾指针 */
        int MaxSize;        /* 队列最大容量     */
    };
    typedef struct QNode* Queue;
    Queue CreateQueue(int MaxSize);
    void EnQueue(Queue Q, int x);
    int PopQueue(Queue Q);
    int QueueEmpty(Queue Q);
    int main()
    {
        int n;
        cin >> n;
        int flag = 0;
        int numb;
        Queue WindowA, WindowB;
        WindowA = CreateQueue(Max);
        WindowB = CreateQueue(Max);
        for (int i = 0; i < n; i++)
        {
            cin >> numb;
            if (numb % 2 == 1)
                EnQueue(WindowA, numb);
            else
                EnQueue(WindowB, numb);
        }
        while (!QueueEmpty(WindowA) || !QueueEmpty(WindowB))
        {
            if (!QueueEmpty(WindowA))
            {
                if (flag++)
                    cout << ' ';
                cout << PopQueue(WindowA);
            }
            if (!QueueEmpty(WindowA))
            {
                if (flag++)
                    cout << ' ';
                cout << PopQueue(WindowA);
            }
            if (!QueueEmpty(WindowB))
            {
                if (flag++)
                    cout << ' ';
                cout << PopQueue(WindowB);
            }
        }
        return 0;
    }
    Queue CreateQueue(int MaxSize)
    {
        Queue Q = (Queue)malloc(sizeof(struct QNode));
        Q->Data = (ElementType*)malloc(MaxSize * sizeof(ElementType));
        Q->Front = 0;
        Q->rear = 0;
        Q->MaxSize = MaxSize;
        return Q;
    }
    void EnQueue(Queue Q, int x)
    {
        if (Q->rear == Q->MaxSize)
        {
            printf("Queue Full
    ");
            return;
        }
        Q->Data[Q->rear++] = x;
        return;
    }
    int PopQueue(Queue Q)
    {
        if (Q->rear == Q->Front)
        {
            printf("Queue Empty
    ");
            return -1;
        }
        return Q->Data[Q->Front++];
    }
    int QueueEmpty(Queue Q)
    {
        if (Q->rear == Q->Front)
            return 1;
        else
            return 0;
    }
    

    2.2.2 总结解题所用的知识点

    • 顺序队列的结构
    • 顺序队列的入列出列操作
    • 奇数和偶数的定义
    • 生活常识

    3.阅读代码

    3.1 题目及解题代码

    bool validateStackSequences(int *pushed, int pushedSize, int *popped, int poppedSize)
    {
        if (pushed == NULL || pushedSize < 0 || popped == NULL || poppedSize < 0) {
            return false;
        }
        if (pushedSize > 1000 || poppedSize > 1000){
            return false;
        }
        int tmpStack[1000] = {0};
        int tmpStackTop = -1;
        int pushedIter = 0;
        int poppedIter = 0;
        while (pushedIter < pushedSize) {
            // 入栈一个数
            tmpStack[++tmpStackTop] = pushed[pushedIter++];
    
            // 当前栈顶如果和pop当前位置相同,则出栈
            while (tmpStackTop >= 0 && poppedIter < poppedSize && tmpStack[tmpStackTop] == popped[poppedIter]) {
                // 出栈后,栈顶下移,pop序列增加
                tmpStack[tmpStackTop--] = 0;
                poppedIter++;
            }
        }
        // 最终栈底回到-1位置,否则没有完全匹配
        if (tmpStackTop != -1) {
            return false;
        }
        return true;
    }
    

    3.2 该题的设计思路及伪代码

    • 思路
      考察程序员对栈结构的理解,以及栈的基础操作的应用;

    • 伪代码

    创建栈 S;
    创建队列 Q;//图个方便
    将popped的数据入队列Q;
    while(队列不空)
    {
        若pushed还有数据输入
            入栈;
        否则
            将栈顶元素与队头元素匹配,若不同
                返回false;
        将栈顶元素与队头元素匹配,若相同
            出栈且出列;
        
    }
    返回true;
    

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

    解题优势:Java以及Python中的库函数(类似)可以大幅简化代码(10行)

    难点:考察栈的基础知识以及应用,难点在于理解深度以及循环跳出(false)条件判断

  • 相关阅读:
    tomcat的systemctl启动脚本
    vmware中虚拟化的问题
    zabbix-3.4.14源码安装
    tomcat启动后8005端口未被占用
    Centos7初始化脚本
    CentOS7.3上如何安装Apache/2.4.34
    js完整教程一 : 基本概念和数组操作
    浅入浅出Lambda表达式
    这些基础却重要的面向对象概念,你还记得多少
    MVC5+EF6 入门完整教程11--细说MVC中仓储模式的应用
  • 原文地址:https://www.cnblogs.com/YasakaKiyokaze/p/14642883.html
Copyright © 2011-2022 走看看