• 栈和队列


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

    0.PTA得分截图

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

    1.1 栈

    画一个栈的图形,介绍如下内容:

    (1)顺序栈的结构、操作函数
    顺序栈:

    栈空条件:s->top==-1;
    栈满条件:s->top==MaxSize-1;
    进栈操作:s->top++;s->data[s->top]=e;
    出栈操作:e=s->data[s->top];s->top--;
    

    共享栈:

    栈空条件:top1==-1;top2==MaxSize;
    栈满条件:top1==top2-1;
    进栈操作:top++;data[top1]=x; top2--;data[top2]=x;
    出栈操作:x=data[top1];top1--; x=data[top2];top2++; 
    
    

    数据类型:

    typedef struct
    {
    	ElemType data[MaxSize];//存放栈中元素
    	int top;//栈顶指针,存放栈顶元素下标
    }SqStack;
    

    初始化栈:

    void InitStack(SqStack*&s)
    {
    	s = (SqStack*)malloc(sizeof(SqStack));//分配顺序栈空间,首地址存放在s中
    	s->top = -1;//栈顶置-1处
    }
    

    销毁栈:

    void DestoryStack(SqStack*&s)
    {
    	free(s);
    }
    

    判断是否为空:

    void StackEmpty(SqStack*s)
    {
    	return (s->top == -1);
    }
    

    进栈:

    bool Push(SqStack*& s, ElemType e)
    {
    	if (s->top == MaxSize - 1)//栈满
    		return false;
    	s->top++;//向上移动一个位置
    	s->data[s->top] = e;//放在顶指针处
    	return true;
    }
    

    出栈:

    bool Pop(SqStack*& s, ElemType e)
    {
    	if (s->top == - 1)//栈空
    		return false;
          e=s->data[s->top] ;//取栈顶元素
    	s->top--;//移动
    	return true;
    }
    

    取栈顶元素:

    bool GetTop(SqStack*& s, ElemType e)
    {
    if (s->top == - 1)//栈空
    		return false;
        e=s->data[s->top] ;//取栈顶元素
         return true;
    }
    

    (2)链栈的结构、操作函数
    条件:

    栈空条件:s->next==NULL;
    栈满条件:无栈满
    进栈操作:p->next=e;
        p->next=s->next;//p结点插入作为首节点
        s->next=p;
    出栈操作: p=s->next;//p指向首结点
      e=p->data;//取首结点值
       s->next=p->next;//删除首结点
    free(p);
    

    类型:

    typedef struct linknode
    {
    Elem Type data;//数据域
    struct linknode;//指针域
    }LinkStNode;//结点类型
    
    

    初始化栈:

    void IniStack(LiStack &s)
    {
       s=new LiNode;//新建头结点
        s->next=NULL;//初始化为空
    }             
    

    销毁链栈:

    void DestroyStack(LiStack *&s)
    {
    LiStack node;
    while(s!=NULL)
    {
       node=s;
        s=s->next;//遍历
      delete node;
    }
    }  
    

    判断栈是否为空:

    bool StackEmpty(LiStack* s)
    {
    return (s->next==NULL);
    }              
    

    进栈:

    void Push(LiStack*& s, ElemType *e)
    {
      LiStack p;
        p=new LiNode;//新建结点
       p->next=e;
       p->next=s->next;//p结点插入作为首节点
       s->next=p;
    }
    

    出栈:

    bool Pop(LiStack*& s, ElemType& e)
    {
      LiStack p;
        if(s->next==NULL)
       return false;
       p=s->next;//p指向首结点
      e=p->data;//取首结点值
       s->next=p->next;//删除首结点
    free(p);
    return true;
    }
    

    取栈顶元素:

    bool GetTop(LiStack*& s, ElemType& e)
    {
    if(s->next==NULL)
      return false;
      e=s->next->data;
    return false;
    }
    

    1.2 栈的应用

    表达式

    • 中缀表达式
      例如:1+3*3 最常用的表达式
    • 后缀表达式
      例如:1+23的后缀表达式为 123+ 没有括号 已经考虑了运算符号的优先级 越放在前面的运算符越优先执行
    • 前缀表达式
      例如: 1+23的前缀 +123

    (1)中缀转后缀表达式
    转换时需要从左到右扫描算数表达式,遇到操作数直接存放到后缀表达式
    1.优先级比栈顶运算符高入栈
    2.低或相等,一直出栈到栈顶为空或者更高,写入后缀表达式

    读入数时,将其放入到输出中,操作符不立即输出,将其放入栈中
    如果我们见到一个右括号,那么我们就从栈中弹出栈元素直至遇到一个左括号,左右括号都只被弹出而不输出
    如果见到任何其他的符号+ * (,那么从栈中弹出栈元素,直至发现优先级更低的元素为止, 但是有一个例外: 除非是在处理一个)的时候,否则绝不从栈中移除(,+的优先级最低,(的优先级最高,当从栈中弹出元素的工作完成后,我们再将其操作符压入栈中。
    最后,如果读到输入的末尾,我们将栈元素弹出直至该栈变成空栈,将符号写到输出中
    (2)举例:

    输入为a + b * c + (d * e + f)*g
     读a,输出
    读到+,入栈
    到b,输出
    到*,因为*优先级比+高,将至压入栈中
    到+,因为*高于+,弹出*,栈中下一个元素+ 与当前+一样,输出栈中这个+,再将刚刚的+入栈
    读到(,优先级最高,入栈
    读到*,因为只有遇到)时才会弹出,所以*继续压入栈中
    读到e,输出
    读到+,弹出*并输出,+压入
    到f输出
    读到)后,将到(之间元素全部输出
    到* 压入
    到g输出
    到末尾后,栈中还剩* +  直接输出
    

    1.3 队列

    画一个队列的图形,介绍如下内容

    (1)顺序队列的结构、操作函数

    条件

    队空条件:q->front==q->rear;
    队满条件:q->raer=MaxSize-1;
    进队操作:q->rear++;q->data[q->rear]=e;
    出队操作:q->front++;e=q->data[q->front];
    

    数据类型:

    typedef struct
    {
    Elem Type data[MaxSize];
    int front,rear;//头尾
    }SqQueue;
    

    初始化队列:

    void InitQueue(SqQueue &q)
    (  q=new Queue;
       q->front=q->rear=-1;//初始位置为-1
    }
    

    销毁队列:

        void Destory(SqQueue &q) 
    {
      delete q;
    }   
    

    判断队列是否为空:

    bool QueueEmpty(SqQueue q)
    {
    return (q->front==q->rear);
    }   
    

    进队列:

    bool enQueue(SqQueue &q,ElemType e)
    {
    //此时下标从-1开始,先增一再入值
      if(q->rear+1==MaxSize)
        return false;
       q->rear=q->rear+1;//队尾加1
       q->data[q->rear]=e;//rear插入元素e
        return true;
    }  
    

    出队列:

    booldenQueue(SqQueue &q,ElemType e)
    {
    if(q->front==q->rear)
      return false;
        q->front=q->front+1;
        e=q->data[q->data];
    return true;
    
    

    (2)环形队列的结构、操作函数

    初始化:

    void InitQueue(SqQueue &q)
    (  q=new Queue;
       q->front=q->rear=0;//开始时在同一位置当存入数时。front指向数的前一个位置,rear在尾部位置
    }
    

    销毁队列:

        void Destory(SqQueue &q) 
    {
      delete q;
    }   
    

    判断队列是否为空:

    bool QueueEmpty(SqQueue q)
    {
    return (q->front==q->rear);
    }   
    

    进队列:

    bool enQueue(SqQueue &q,ElemType e)
    {
      if((q->rear+1)%MaxSize==q->front)//队满条件
        return false;
       q->rear=(q->rear+1)%MaxSize;//循环增一
         q->]data[q->rear]=e;//存入
        return true;
    }  
    

    出队列:

    booldenQueue(SqQueue &q,ElemType e)
    {
    if(q->front==q->rear)//空队时
      return false;
        e=q->data[q->front];//取值
      q->front=(q->front+1)%MaxSize;//循环增一
    return true;
    
    

    (3)链队列的结构、操作函数

    条件:

    队空条件:q->rear==NULL;
    队满条件:不考虑
    进队操作:q->data=e;p->rear->data=q;p->next=q;
    出队操作:p->front=p->front->next;e=q->data;
    

    数据类型:

    typedef struct
    {
        QNode *front;//头指针
       QNode *rear;//尾指针
    }LinkQueue;
    
    typedef struct qnode
    {
       Elem data;//数据元素
      struct qnode *next;
    }QNode;
    

    链队初始化:

    Status InitQueue(LinkQueue &Q)
    {
    Q.front=Q.rear=new QNode;
    if(!Q.front)
    exit(OVERFLOW);
    Q.front->next=NULL;
    return OK;
    }
    

    或者

    void InitQueue(LinkQuNode *&q)
    {
        q=(LinkQueNode *)malloc(sizeof(LinkQueNode));//创建链队结点
        q->front=q->reaar=NULL;
    }
    

    判断链队是否为空:

    Status QueueEmpty(LinkQueue Q)
    {
    return (Q.front==Q.rear)//队空
    }
    
    

    求链队队头元素:

    Status GetQueue (LinkQueue Q,QElemType &e)
    {
        if(Q.front==Q.rear)
            retuen ERROR;
         e=Q.front->next->data;//取元素
        return OK;
    }
    

    链队列入队:

    Status EnQueue (LinkQueue &Q,QElemType e)
    {
           p=new QNode;//新建结点
         if(!p)
        exit(OVERFLOW)
        P->data=e;
       p->next=NULL;
          Q.rear->next=p;//尾指针指向p
         Q.rear=p;
    return OK;
    }
    

    链队出队:

      Status DeQueue (LinkQueue &Q,QElemType e)     
    {
        if(Q.front==Q.rear)//队空
             return ERROR;
         p=Q.front->next;
            e=p->data;//取队头元素
      Q.front->next=p->next;//结点指向p下一个
      if(Q.rear==p)//最后一个元素被删除,改队尾
         Q.rear=Q.front;
        delete p;//删除结点p
       return OK;
    }        
    

    (4)队列应用,要有具体代码操作。

    • 求解报数问题
     1.问题描述:
     n人站成一排,数1 2 1 2...数1的同学出列,2
    的同学靠右直到第n个人出列
     2.数据组织:
      使用环形队列
     3.设计运算算法:
     先将n个人编号进队,反复执行以下操作,直到队列为空
     出队一个元素  输出其编号
     若队列不为空,再出队一个元素,将刚出列的元素入队
    
    void number(int n)
    {
    	int i;
    	ElemType e;
    	SqQueue* q;
    	InitQueue(q);//初始化
    	for (i = 1; i <= n; i++)
    		enQueue(q, i);//进队
    	while (!QueueEmpty(q))
    	{
    		deQueue(q, e);//出
    		if (!!QueueEmpty(q))
    		{
    			deQueue(q, e);
    			enQueue(q, e);//将刚出的进队
    		}
    	}
    	DestoryQueue(q);//销毁
    }
    

    (2)求解迷宫问题
    使用链队解决
    1.数据组织

    //使用一个顺序队qu保存走过的方块
    typedef struct
    {
    	int i, j;//方块的位置
    	int pre;//本路径中上一方块在队列中的下标
    }Box;
    typedef struct
    {
    	Box data[MaxSize];
    	int front, rear;//队头队尾指针
    }QuType;
    // 此处qu不是环形队列,找出口时需要利用队列中所有方块找一条迷宫路径,
    

    2.设计运算算法

    搜索路径(xi,yi)->(xe,ye)从入口进队,队不为空时循环,出队一个方块,找其相邻方块,使其进队,将他们的pre都置为front



    2.PTA实验作业(4分)

    2.1 符号配对

    2.1.1 解题思路及伪代码
    从头遍历:
    1.遇到左符号:入栈;
    2.遇到右符号:若此时栈空则表示当前右符号缺少与之匹配的左符号,跳出循环;栈不空,则与栈顶元素进行配对,若配对成功则栈顶符号出栈,否则跳出循环。
    遍历结束后,若栈空(除上述栈空的情况外)则说明全部符号均配对成功




    2.1.2 总结解题所用的知识点
    注意第一个用例中/*/的判断,并且注意右字符与栈内字符不匹配时的情况。 右字符与栈内字符不匹配时有两种:栈内为空,则此右字符缺失左字符;栈不为空,则栈内左字符缺失右字符;

    2.2 银行业务队列简单模拟

    2.2.1 解题思路及伪代码

    解题思路:把偶数的数字存到B窗口,将奇数的数字存到A窗口,是先进先出,采用队列,将偶数的放在B队列,将奇数的放在A队列
      然后每输出两个A队列中的元素
     再输出一个B队列中的元素;
    还有一个点就是,最后是A队列中的元素结尾还是B队列中的元素结尾,主要是控制空格的问题
    

    伪代码:

    创建结构体
     data[1002]用于存队列的数据; 
     定义 rear来记录从尾部插入了多少个元素; 
      front计数队头,方便取出队头的元素; 
       实现队列的push用法;传入类型为 queue 的指针 q;传入要入队的数tmp; 
        q->tail ++/每入队一个元素,尾部计数器+1; 
           将元素入队; 
       函数pop(queue *q) //取出队列的数字,从前端取出;此时要利用head记数 
           返回队头的元素
       void init(queue *q) 初始化 
            将尾和头记数均初始化为-1
        notEmpty(queue *q)判断队列是否为空
     如果尾和头的记数一样,则队列为空
     
     用countA记录入A队列的个数;用countB  记录入B队列的个数
    
         queue A定义
        queue B定义 
         初始化A队列,并要用引用符号
         初始化B队列,并用引用符号 
        输入m,
       push(&b,c)如果是偶数,则进b队列
         countB相应+1
      否则A
      分情况,注意最后到底是A队列的数结尾还是B队列的数结尾
         if countA大于两倍countB,是A队列的元素结尾,则A最后一个元素后面不能加空格
          当A队列不空或者B队列不空时; 
        ifA 不为空
        输出
          ifB 不为空
        输出
      countA小于等于两倍countB,是B队列的元素结尾,则B最后一个元素后面不能加空格
    当A队列不空或者B队列不空时
        ifA 不为空
        输出 
         输出一个b队列的元素,注意b队列最后一个元素的后面不能加空格
                  
    





    3.1迷宫问题

    求出出口到入口的路径


    3.2 该题的设计思路及伪代码
    思路:从上一个节点开始,任意找下一个能走的点,当找不到能走的点时,退回上一个点寻找是否有其他方向的点。
      使用栈存储当前路径。后进先出,方便回退到上一个点

    typedef struct
    {
        定义 i,j//方块的位置
       pre//本路径中上一方块在队列中的下标
    } Box;//方块类型
        Box data[MaxSize];
        int front,rear;     //队头指针和队尾指针
                   //定义顺序队类型
      print(QuType qu,int front) //从队列qu中输出路径
               //反向找到最短路径,将该路径上的方块的pre成员设置成-1
       
        while (k!=0);
        printf("迷宫路径如下:
    ");
        
        while (k<=front)  //正向搜索到pre为-1的方块,即构成正向的路径
         //每输出每5个方块后换一行
           mgpath(int xi,int yi,int xe,int ye)搜索路径为:(xi,yi)->(xe,ye)
              //定义顺序队
          //(xi,yi)进队
           //将其赋值-1,以避免回过来重复搜索
        while (qu.front!=qu.rear && !find)  //队列不为空且未找到路径时循环
                         //出队,由于不是环形队列,该出队元素仍在队列中
                 //找到了出口,输出路径
                print(qu,qu.front)调用print函数输出路径
                return(1)找到一条路径时返回1
            for (di=0; di<4; di++)扫描每个方位,把每个可走的方块插入队列中
        if (mg[i][j]==0)
                    qu.rear++将该相邻方块插入到队列中
                    qu.data[qu.rear].i=i;
                    qu.data[qu.rear].j=j;
                    qu.data[qu.rear].pre=qu.front指向路径中上一个方块的下标
    

    3.3 分析该题目解题优势及难点。
    总结算法就是:创建一个空栈,首先将入口位置进栈。当栈不空时循环:获取栈顶元素,寻找下一个可走的相邻方块,如果找不到可走的相邻方块,说明当前位置是死胡同,进行回溯(就是讲当前位置出栈,看前面的点是否还有别的出路)
      使用栈来解决迷宫问题,虽然实现起来比较简单,但是它的路径并不是最短的,很可能会绕远,如果想走最短路径可以使用队列来做

  • 相关阅读:
    ASP连接mysql
    jsp中动态include与静态include的区别
    Create & Post free text invoice by code
    自定义Form作为Dialog
    动态多关联查询
    转到主表窗口
    获取当前用户组
    一个Job调用另外一个Job
    保存图片到硬盘
    在编辑框中增加右键菜单
  • 原文地址:https://www.cnblogs.com/lixinggio/p/14613225.html
Copyright © 2020-2023  润新知