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

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

    0.PTA得分截图

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

    1.1 栈

    1.1.1顺序栈

    顺序栈的结构体定义:

    
    /* 存储空间初始分配量 */
    #define MAXSIZE 20
    
    /* SElemType类型根据实际情况而定,这里假设为int */
    typedef int SElemType;
    
    /* 顺序栈结构 */
    typedef struct
    {
        SElemType data[MAXSIZE];
        int top; /* 用于栈顶指针 */
    }SqStack;
    
    

    顺序栈的基本操作:

    • 初始化栈
    /*顺序栈*/
    void InitStack(SNode &s)
    {
         s.top=-1;//一般的顺序表栈顶指针的初始化为-1,
    }
    
    • 判断是否为空栈
    /*顺序栈*/
    bool IsEmpty(SNode s)//如果为空返回true,不为空则返回false;
    {
        if(s.top==-1)
            return true;
        else
            return false;
    }
    
    • 判断是否栈满
      对于顺序栈来说,是用数组来保存数据,因为数组在被定义时就需要预先申请一段连续的空间,所以如果我们要往里面进行插入的操作,必须要先判断该栈是否已经满了,否则就会出现数组溢出,访问错误的情况。
    /*顺序栈*/
    bool IsFull(sNode s)
    {
        if(s.top==MaxSize-1)
           return true;
        else
           return false;
    }
    
    • 进栈
      对栈的一端进行插入。
    bool Push(SNode &s,Elemtype e)
    {
        if(IsFull(s))//在进栈之前一定要先判断是否栈满
            return false;
        else
            s.data[++s.top] = e;
        return true;//说明进栈成功;
    }
    
    • 取栈顶
      取得栈顶元素
    /*顺序栈*/
    bool Gettop(SNode &s, Elemtype &e)
    {
         if(IsEmpty(s))//取栈顶时要判断是否为空栈!
           return false;
         else 
           e = s.data[s.top];
         return true ;
    }
    
    
    • 出栈

    /*顺序栈*/
    bool Pop(SNode &s,Elemtype &e)//出栈并返回该栈顶元素;
    {
        if(IsEmpty(s))//在出栈之前一定要判断是否为空栈
           return false ;
        else
          e = s.data[s.top--];//这里只是移动了栈顶指针,并没有真正的删除数据; 
        return true;//出栈成功;
    }
    
    • 销毁栈
      将栈顶元素删除,并移动栈顶指针。
    void DestroyStack(SNode &s)
    {
        delete s;
    }
    

    1.1.2链栈

    链栈的结构体定义:

    typedef struct stack
    {
         Elemtype  data;
         struct stack* next;
    }SNode,*Stack;
    

    链栈的基本操作:

    • 初始化栈
    /*链栈*/
    void InitStack(Stack &s)
    {
         s = new SNode;//申请空间;
         s->next=NULL;
    }
    
    • 判断是否为空栈
    
    /*链栈*/
    bool IsEmpty(Stack s)//如果为空返回true,不为空则返回false;
    {
        if(s->next==NULL)
            return true;
        else 
            return false;
    
    
    • 判断是否栈满

    因为是链式存储结构,不用预先设定需要多少的存储空间来保存数据,都是现用现配,空间利用效率比较高。所以只要一个数据我们就可以直接进栈,不必考虑是否会栈满。

    • 进栈
    void Push(Stack &s,Elemtype e)//使用头插法;
    {
        Stack str;
        str=new Stack;
        str->data = e;
        str->next= s->next;//先将原来的链栈连接到str后面;
        s->next = str;//再将str连接到头结点后面成为新的栈顶;
    }
    
    
    • 出栈
    /*链栈*/
    void Pop(Stack & s,Elemtype &e)
    {
        Stack str;
        if(IsEmpty(s))//出栈之前要判断是否为空栈;
             return false;
        else
        {
             e = s->next->data;
             str = s->next;
             s->next = str->next;//让头结点连接栈顶的下一个结点,使s->next->next成为新的栈顶;
             delete str;//释放空间,这里数据是真的被删除
        }
    }
    
    
    • 取栈顶
    bool Gettop(Stack &s,Elemtype &e)
    {
       if(IsEmpty(s))//取栈顶时要判断是否为空栈!
          return false;
       else
          e = s->next->data;
       return true;
    }
    
    • 销毁栈
    /*链栈*/
    void DestroyStack(Stack &s)
    { 
        ListStack str;
        while(s!=NULL)
        {
              str = s;//str保存当前删除的结点
              s = s->next;//s指向下一个需要删除的结点;
              delete str;
        }
    }
    
    

    1.1.3 C++类模板:stack

    头文件 #include <stack>
    stack <Elemtype> s;初始化栈,保存Elemtype类型的数据;
    s.push(x);入栈元素t;
    s.top();返回栈顶指针;
    s.pop();出栈操作,只做删除栈顶元素的操作,不返回该删除元素;
    s.empty();判断是否栈空,如果为空返回true;
    s.size();返回栈中元素个数;
    
    

    1.2 栈的应用

    表达式转换
    运算符在操作数中间,这种表达式叫做中缀表达式,如果计算机要跳过数据去判断所有运算符的优先级,再按顺序取运算符两边的数据进行运算的话,对计算机来说工作量是很大的。于是如果我们能把运算符的优先级先排好,然后直接取该运算符的前两个数据运算,这样就使得运算变的简便起来。像这样 运算符位于两个运算数之后的表达式式叫做后缀表达式。
    我们可以设置一个栈来保存运算符,利用运算符的优先级来进行运算符进栈入栈的操作。这里我们可以用到map容器,对运算符进行赋值,以此来判断栈内栈外运算符优先级的高低。

    • 伪代码
    结合运算符优先级用map容器给运算符赋值;
    mp<char,int>in;//已入栈运算符的优先级;
    mp<char,int>un;//未入栈时运算符优先级;
    while(str[i])
    {
        if(str[i]为数字或者小数点'.')
              while(str[i]为数字或者小数点'.')
                  str[i]写入后缀表达式中,继续读取下一字符;
        else if(str[i]为正负号)
              将负号写入后缀表达式中,读取下一字符;
        else//都是运算符
        {
              if(栈空 || 栈顶运算符的优先级比str[i]低)
                  str[i]进栈,再读取下一字符;
              else if(栈顶运算符的优先级比str[i]高)
                  while(栈顶运算符的优先级比str[i]高)
                       将栈顶元素写入后缀表达式,读取下一字符;
              else //栈顶运算符的优先级等于str[i]的优先级,说明是左右括号配对的情况;
                  将栈顶元素'('出栈;读取下一字符;
        }
        如果栈不空,则出栈所有元素,写入后缀表达式中;
    }
    
    
    • 代码



    1.3 队列

    队列也是一个运算受限的线性表,它只能选取一端进行插入操作,另一端做删除操作,是先进先出的一种结构。我们把进行删除的一段叫做队头,进行插入的一端叫做队尾。

    1.3.1顺序队列

    顺序队结构体定义

    typedf struct
    {
       Elemtype data[MaxSize];
       int front;//队头指针;
       int rear;//队尾指针;
    }QNode;
    

    顺序队初始化

    void InitQueue(Queue &q)
    {
        q.front=q.rear=-1;
    }
    

    判断是否为空队

    bool IsEmpty(Queue &q)
    {
         if(q.rear==q.front)//队空
             return true;
         else//队不空
             return false;
    }
    

    判断是否队满

    /*顺序队*/
    bool IsFull(Queue &q)
    {
          if(q.rear==MaxSize-1)//队满
              return true;
          else
              return false;
    }
    

    进队

    bool Push(Queue &q,Elemtype e)
    {
        if(IsFull(q))//在进队之前一定要先判断是否队满;
            return false;//表示入队失败;
        else
            q.data[++q.rear] = e;
        return true;//表示入队成功;
    }
    

    出队

    bool Pop(Queue &q,Elemtype &e)
    {
        if(IsEmpty())//出栈是要先判断是否为空栈;
            return false;
        else
            e = q.data[++q.front];
        return true;//表示出队成功;
    }
    

    取队头元素

    bool GetFront(Queue q,Elemtype &e)
    {
        if(IsEmpty(q))//取队头是要判断是否为空队;
           return false;
        else
           e = q.data[q.front + 1];
        return true;
    }
    
    

    销毁顺序队

    void DestroyQueue(Queue &q)
    {
        delete q;
    }
    
    

    1.3.2链队列

    顺序队结构体定义

    typedef struct qnode//用于保存每个结点;
    {
        Elemtype data;
        struct qnode *next;
    }Node,*LinkNode;
    
    typedef struct 
    {
       LinkNode front;//队头指针;
       LinkNode rear;//队尾指针;
    }Queue;
    
    

    顺序队初始化

    void InitQueue(Queue &q)
    {
        q.front->next = NULL;
        q.rear->next = NULL;
    }
    
    

    判断是否为空队

    
    bool IsEmpty(Queue &q)
    {
          if(q.front->next==NULL)//队空
            return true;
          else
            return false;
    }
    
    

    判断是否队满

    因为是链式存储结构,不用预先设定需要多少的存储空间来保存数据,都是现用现配,空间利用效率比较高。所以只要一个数据我们就可以直接进队,不必考虑是否会队满。
    

    进队

    void Push(Queue &q,Elemtype e)
    {
        LinkNode qtr;
        qtr->data=e;  
        qtr->next=NULL;
        if(IsEmpty(q))//先判断是否为空栈,如果为空栈要对队头指针一起修改;
           q.front->next = qtr;
        q.rear->next = qtr;
        q.rear =  qtr;
    }
    

    出队

    bool Pop(Queue &q,Elentype &e)
    {
        LinkNode qtr;
        if(IsEmpty())
            return false;
        else
        {
            qtr=q.front->next;//先用qtr保存要出队的结点;
            q.front->next=qtr->next;//修改队头指针;
            e = qtr->data;
            delete qtr;//删除结点;
        }    
    }
    
    

    取队头元素

    
    bool GetFront(Queue q.Elemtype &e)
    {
         if(IsEmpty(q))//取队头要先判断是否为空栈;
            return false;
         else
            e= q.front->next->data;
         return true;
    }
    
    

    销毁顺序队

    void DestroyQueue(Queue &q)
    { 
        LinkNode qtr;
        while(q.front!=NULL)
        {
              qtr = q.front;//str保存当前删除的结点
              q.front = q.front->next;//s指向下一个需要删除的结点;
              delete qtr;
        }
    }
    
    

    1.3.3环形队列

    由于队列进行插入和删除的操作不在同一端口进行,所以在顺序链中,当队尾指针rear指向数组的最后一个位置作时,存在队头指针front不在数组的第一个位置上,也就是front!=0,队中还存在若干空位置,这种情况我们称为假溢出。所以,为了提高空间的利用率,我们引入一个特殊的队列————循环队列。

    顺序队结构体定义

    typedef struct 
    {
        Elemtype data[MaxSize];
        int front;
        int rear;
    }Queue;
    
    

    初始化

    void InitQueue(Queue &q)
    {
       front = rear = 0;//指向0位置;
    }
    
    

    判断是否为空队

    bool IsEmpty(Queue &q)
    {
        if(front == rear)
           return true;
        else
           return false;
    }
    

    判断是否队满

    bool IsFull(Queue &q)
    {
        if((q.rear+1)%MaxSize == q.front)
            return true;
        else
            return false;
    }
    

    进队

    bool Push(Queue &q, Elemtype e)
    {
         if(IsFull(q))//先判断是否队满;
              return false;
         else
         {
              q.data[q.rear] = e;//先保存e,再移动rear指针,所以操作完的rear指针指向的是下一个需要插入的位置,也就是队尾元素的下一个位置。
              q.rear = (q.rear+1)%MaxSize;
         }
         return true;
    }
    

    出队

    bool Pop(Queueu &q, Elemtype &e)
    {
         if(IsEmpty(q))
             return false;
         else
             e = q.data[q.front];
             q.front = (q.front+1)%MaxSize;//操作完的front指向的是队头元素。
    }
    

    1.3.4 C++容器:queue

    
    头文件:#include <queue>
    q.push(x);将x插入到队列末端,成为新的队尾元素;
    q.pop();弹出队列的第一个元素,注意!!这里不返回被弹出元素;
    q.front();返回队头元素;
    q.back();返回队尾元素;
    q.empty();当队空是,返回true;
    q.size();返回队列的元素个数;
    
    

    1.3.5队列应用

    7-5 jmu-报数游戏

    • 思路:
      定义队列,将游戏人数按编号依次进队,定义变量i循环自增,
      用i求余m来判断要出队的是几号,i求余m=0时,输出号数,再将此数出队,求余m不等于0时,
      定义临时变量k来存放这个数,再将其出队,之后再让k进队构成循环,直至队列为空。


    2.PTA实验作业(4分)

    2.1 符号配对

    2.1.1 解题思路及伪代码

    • 伪代码
    使用map容器将符号进行配对;
    while(str[i])
    {
        if(str[i]==左括号)
            s.push(str[i])//左括号进栈;
        else if(str[i]==右括号)
        {
            if(s.empty())//栈空;
                 缺少左括号,不匹配,退出循环;
            else
            {
                 if(左右括号匹配)
                    s.pop();//弹出栈顶元素
                 else//不匹配
                    退出循环;
             }
         }
         读取下一字符;   
    }
    
    



    2.1.2 总结解题所用的知识点

    1.使用C++容器map
    2.左右符号配对的判断条件

    2.2 银行业务队列简单模拟

    2.2.1 解题思路及伪代码

    • 伪代码
    输入n的数值
    for i=1 to n
    输入一个数num;
    if(n为奇数)进入q1队列
    else 进入q2队列
    while(q1,q2均不为空时)
    输出q1中的第一个数, 输出后让该数出队列   
    
    if(q1出队列的次数为偶数倍)
            q2出队一个元素
    end while
    
    while(q1不为空)
        将q1中剩余元素输出 
    while(q2不为空)
        将q2中剩余元素输出 
    return 0;
    
    
    • 代码



    2.2.2 总结解题所用的知识点

    1.queue 模板运用
    2.考虑队列空满情况
    3.注意数据输出的格式

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

    3.1 题目及解题代码

    题目


    解题代码

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

    3.2.1 该题的设计思路

    先排身高更高的,这是要防止后排入人员影响先排入人员位置
    每次排入新人员[h,k]时,已处于队列的人身高都>=h,所以新排入位置就是people[k]
    时间复杂度:O(N)。 理由:循环地从头读取people,根据people[i][1]也就是k,插入list
    空间复杂度:O(N)。 理由:这里将完成所有插入操作的list重建为vector返回

    3.2.2 该题的伪代码

    class Solution {
    public:
            先将people按照身高降序排序,
            又由于每次插入的位置是k,所以相同身高需要按k升序排序,否则插入位置会越界
            确定循环次数
            新建容器tmp用来存放数据
            // 循环插入
            for i = 0 to len
                使用advance()找到应插入位置
                插入数据
            end for
            // 重建vector返回
            将完成所有插入操作的list重建为vector返回
        }
    };
    
    

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

    3.3.1优势:

    并没有直接使用vector,而是将完成所有插入操作的list重建为vector,这样的操作使得整个代码的运行效率大大提高
    先利用了sort函数进行排序,大大减少了后续代码的执行的难度.

    3.3.2难点:

    每次排入新人员[h,k]时,如何确定新排入的位置
    相同身高需要按k升序排序,否则插入的位置会越界

  • 相关阅读:
    剑指Offer_#7_重建二叉树
    剑指Offer_#6_从尾到头打印链表
    剑指Offer_#5_替换空格
    剑指Offer_#4_二维数组中的查找
    Redis详解(十三)- Redis布隆过滤器
    Redis详解(十二)- 缓存穿透、缓存击穿、缓存雪崩
    Redis详解(十一)- 过期删除策略和内存淘汰策略
    Redis详解(十)- 集群模式详解
    Redis详解(九)- 哨兵(Sentinel)模式详解
    Redis详解(八)- 主从复制
  • 原文地址:https://www.cnblogs.com/chtdeboke/p/14613976.html
Copyright © 2011-2022 走看看