• DS博客作业02--栈和队列


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

    0.PTA得分截图

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

    1.1 栈

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

    栈--又被称为后进先出的线性表(LIFO表,Last In First Out)

    1.1.1顺序栈的结构、操作函数

    声明顺序栈的类型SqStack

    typedef struct{
      	ElemType data[MaxSize];
      	int top;
      }Stack;
    typedef Stack *SqStack;
    

    操作函数

    (1)初始化栈initStack(&s)
    void InitStack(&s)
    {
        s=new Stack;
        s->top=-1;
    }
    
    (2)销毁栈ClearStack(&s)
    void DestroyStack(SqStack &s)
    {
        delete s;
    }
    
    (3)判断栈是否为空StackEmpty(s)
    bool StackEmpty(s)
    {
        return(s->top==-1)
    }
    
    (4)进栈Push(&s,e)
    bool Push (SqStack &s,ElemtType e)
    {
        if(s->top==MaxSize-1)       //顺序栈务必考虑栈满
        return false;
        s->top++;                   //栈顶指针增1
        s->Data[s->top]=e;
        return true;
    }
    
    (5)出栈Pop(&s,&e)
    bool Pop(SqStack &s,ElemType &e)
    {
        if(s->top==-1)    //栈为空,栈下益出
        return false';
        e=s->Data[s->top];//取栈顶指针元素
        s->top--;         //栈顶指针减一
        return true;
    }
    
    (6)取栈顶元素GetTop(s)
    //在栈不为空的条件下,将栈顶元素赋给e
    bool GetTop(SqStack *s,ElemType &e)
    {
      if (s->top==-1)   //栈为空的情况
      return false;
      e=s->data[s->top];
      return true;
    }
    
    (7)建立栈CreateStack
    Stack CreateStack(int MaxSize)
    {
        Stack s=(Stack)malloc(sizeof(struct SNode));
        s->Data=(ElementType *)malloc (MaxSize*sizeof(ElementType));
        s->top=0;
        s->MaxSize = MaxSize;
        return s;
    }
    

    链栈的结构、操作函数

    链栈的四要素

    链栈中的数据节点的类型LiStack定义

    typedef int ElemType;
    typedef struct Linknode
    {
        ElemType data;
        struct Linknode *next;
    }LinkNode, *LiStack;
    

    链栈的基本运算算法

    (1)初始化栈initStack(&s)
    void InitStack(LiStack &s)
    {
        s=new LiNode;
        s->next=NULL;
    }
    
    (2)销毁栈ClearStack(&s)
    void DestroyStack(LiStack &s)
    {
        LiStack node;
        whilw(s!=NULL)
        {
          node=s;
          s=s->next;
          delete node;
         }
    }
    
    (3)判断栈是否为空StackEmpty(s)
    bool StackEmpty(LiStack s)
    {
        return (s->next==NULL);
    }
    
    (4)进栈Push(&s,e)
    //该运算新建一个节点,用于存放元素e,将其插入到头节点之后作为新的首结点
    void Push (LiStack &s)
    {
        LiStack p;
        p=new LiNode;
        p->data=e;
        p->next=s->next;
        s->next=p;
    }
    
    (5)出栈Pop(&s,&e)
    //在栈不为空的条件下,将头节点后继数据节点的数据域赋给e
    
    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;          //删除*p节点
        delete p;
        return true;
    }
    
    (6)取栈顶元素GetTop(s,e)
    //在栈不为空的条件下,将头节点后继数据节点的数据域赋给e
    bool GetTop(LiStack s,ElemType &e)
    {
        if(s->next==NULL)         //栈空的情况
        return false;
        e=s->next->data;
        return true;
    }
    

    1.2 栈的应用

    栈作为一种存放临时数据的容器。如果后存入的元素先处理,则采用栈。

    表达式

    1.2.1中缀表达式

    (1)算术表达式中,运算符位于两个操作数中间的表达式称为中缀表达式,例如1+2*3。

    (2)中缀表达式的运算一般遵循“先乘除,后加减,从左到右计算,先括号内,后括号外”的规则。

    (3)中缀表达式依赖运算符优先级,还需处理括号。

    1.2.2后缀表达式

    (1)后缀表达式又称为逆波兰表达式,即为在算术表达式中运算符在操作数的后面,如1+2*3的后缀表达式为1 2 3 * +。

    (2)后缀表达式在书写过程中已经考虑了运算符的优先级,没有括号,只有操作数和运算符,而且放在前面的运算符越优先执行。

    1.2.3前缀表达式

    如果运算符在操作数的前面,称为前缀表达式,如1+2*3的前缀表达式为+ 1 * 2 3。

    1.2.4将算术表达式转换成后缀表达式

    将一个中缀表达式转换成后缀表达式时,需要从左到有扫描算术表达式,将遇到的操作数直接存放到后缀表达式中,将遇到的每一个运算符或者左括号都暂时保存到运算符栈,而且先执行的运算符先出栈。

    1.2.5后缀表达式求值

    后缀表达式求值过程是从左到右扫描后缀表达式postexp,若读取到的是一个操作数,将它进操作数栈,若读取的是一个运算符op,从操作数栈中连续出栈两个操作数,当整个后缀表达式扫描结束时,操作数栈中的栈顶元素就是表达式的计算结果。

    1.3 队列

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

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

    顺序队结构

    typedef struct
    {
        ElemType data[MaxSize];
        int front,rear;         //队首和队尾指针    
    }Queue;
    typedef Queue *SqQueue;
    

    操作函数

    1. 初始化队列
    void InitQueue(SqQueue &q)
    {
        q=new Queue;
        q->front=q->rear=-1;
    }
    
    2.销毁队列
    void DestroyQueue(SqQueue &q)
    {
        delete q;
    }
    
    3.判断队列是否为空
    bool QueueEmpty(SqQueue q)
    {    
        return (q->front==q->rear);
    }
    
    4.进队列
    bool enQueue(SqQueue &q,ElemType e)
    {
        if(q->rear+1==MaxSize)
        return false;           //从队满上溢出
        q->rear=q->rear+1;
        q->data[q->rear]=e;
        return true;
    }
    
    5.出队列
    bool deQueue(SqQueue &q,ElemType &e)
    {
        if(q->front==q->rear)
        return false;             //从队空上溢出
        q->front=q->front+1;
        e=q->data[q->front];
        return true;
    }
    

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

    环形队列 结构体
    typedef struct
    {
     ElemType data[MaxSize];
     int front,rear;
    } Queue;
    typedef Queue *SqQueue;
    

    操作函数

    进环形队列
    bool enQueue(SqQueue &q,ElemType e)
    {
        if((q->rear+1)%MaxSize==0)   //队满溢出
        return false;
        q->rear=(q->rear+1)%MaxSize;
        q->data[q->rear]=e;
        return true;
    }
    
    bool deQueue(SqQueue &q,ElemType &e)
    {
        if(q->front==q->rear)  
        return false;
        q->front=(q->front+1)%MaxSize;
        e=q->data[q->front];
        return true;
    }
    

    链队列的结构、操作函数

    结构
    typedf struct qnode
    {
     ElemType data;
     struct qnode *next;
    } QNode;
    typedef struct Queue *LiQueue;
    LiQueue front,rear;
    
    入队
    Q.rear->next=node;
    Q.rear=node;
    
    出队
    node =Q.font->next;
    Q.font->next=node->next;
    delete node;
    

    队列应用--配对舞伴

    int QueueLen(SqQueue Q)
    {
        int len = 0;
        int i = Q->front;
        int j = Q->rear;
        while(i != j)
        {
            i = (i+1)%MAXQSIZE;
            len++;
        }
        return len;
    }//队列长度
    
    int EnQueue(SqQueue &Q, Person e)
    {
        if((Q->rear+1)%MAXQSIZE == Q->front)
            return ERROR;
    
        Q->rear = (Q->rear+1)%MAXQSIZE;
        Q->data[((Q->rear))] = e;
        return OK;
    }//加入队列
    int QueueEmpty(SqQueue &Q)
    {
        return (Q->front == Q->rear);
    }//队列是否为空
    
    int DeQueue(SqQueue &Q, Person &e)
    {
        if(QueueEmpty(Q))
            return -1;
        Q->front = (Q->front+1)%MAXQSIZE;
        e = Q->data[Q->front];
    
        return OK;
    }
    //出队列
    void DancePartner(Person dancer[], int num)
    {
        int i;
        for(i = 0 ; i < num; ++i)
        {
            if(dancer[i].sex == 'F')
                EnQueue(Fdancers,dancer[i]);  //女生入队
            else
                EnQueue(Mdancers,dancer[i]);  //男生入队
        }
        Person e;
        while((!QueueEmpty(Fdancers)) && (!QueueEmpty(Mdancers)))
        {
          
            DeQueue(Fdancers,e);
            cout<<e.name<<"  ";
            DeQueue(Mdancers,e);
            cout<<e.name<<endl;
        }
    
    } //配对舞伴
    

    2.PTA实验作业

    2.1 符号配对

    2.1.1 解题思路及伪代码

    解题思路

    1.对于左符号直接进行入栈操作
    2.读入右符号,判断情况:
    /用>来代替;
    /
    用<来代替;
    如果栈空,则缺少对应的左括号。
    如果栈顶元素不匹配,缺少与栈顶元素对应的右括号
    读入结束,如果栈空,则完全匹配,如果有剩余,则缺少右括号。

    #include<stdio.h>
    #define maxsize 1003
    #include<stdlib.h>
    typedef struct node *stack;
    struct node
    {
    	char ch[maxsize];
    	int top;
    };
    stack creat()
    {
    	stack s;
    	s=(stack)malloc(sizeof(struct node));
    	s->top=-1;
    	return s;	
    } 
    void push(stack s,char cht)
    {
    	s->top++;
    	s->ch[s->top]=cht;	
    } 
    
    int main()
    {
    	int i,k=0,j;
    	static char ch1[1000],ch2[1000],ch[10000];
    	struct node *s1=NULL;
    	s1=creat();
    	ch1['(']=')';
    	ch1['{']='}';
    	ch1['[']=']';
    	
    	ch1['<']='>';
    	for(i=0;;i++)
    	{
    		gets(ch);
    		if(ch[0]=='.'&&ch[1]=='') break;
    		for(j=0;ch[j]!='';j++)
    		{
    			if(ch[j]=='('||ch[j]==')'||ch[j]=='['||ch[j]==']'||ch[j]=='{'||ch[j]=='}')
    			{
    				ch2[k++]=ch[j];
    			}
    			else if(ch[j]=='/'&&ch[j+1]=='*')
    			{
    				ch2[k++]='<';
    				j++;
    			}
    			else if(ch[j]=='*'&&ch[j+1]=='/')
    			{
    				ch2[k++]='>';
    				j++;
    			}
    		}
    	}
    	int flag=1;
    	for(i=0;i<k;i++)
    	{
    		if(ch2[i]=='('||ch2[i]=='['||ch2[i]=='{'||ch2[i]=='<')
    		{
    			push(s1,ch2[i]);
    		}
    		else if(ch2[i]==')'||ch2[i]==']'||ch2[i]=='}'||ch2[i]=='>')
    		{
    			if(s1->top!=-1&&ch1[s1->ch[s1->top]]==ch2[i])
    			{
    				s1->top--;
    			}
    			else 
    			{
    				printf("NO
    ");
    				
    				if(s1->top==-1)
    				{
    					if(ch2[i]==')') printf("?-)");
    					else if(ch2[i]=='}') printf("?-}");
    					else if(ch2[i]==']') printf("?-]");
    					else if(ch2[i]=='>') printf("?-*/"); 
    				}
    				
    				else if(ch1[s1->ch[s1->top]]!=ch2[i])
    				{
    					if(s1->ch[s1->top]=='(') printf("(-?");
    					else if(s1->ch[s1->top]=='[') printf("[-?");
    					else if(s1->ch[s1->top]=='{') printf("{-?");
    					else if(s1->ch[s1->top]=='<') printf("/*-?");
    				}
    				flag=0;
    				break;
    			}
    		}
    	}
        
    	if(flag==1&&s1->top==-1) printf("YES");
            else if(flag==1&&s1->top!=-1)
        {
            printf("NO
    ");
            if(s1->ch[s1->top]=='(') printf("(-?");
    		else if(s1->ch[s1->top]=='[') printf("[-?");
    					else if(s1->ch[s1->top]=='{') printf("{-?");
    					else if(s1->ch[s1->top]=='<') printf("/*-?");
        }
    	return 0;
    }
    
    #include<stdio.h>
    #define maxsize 1003
    #include<stdlib.h>
    创建队列
    
    定义ch1[1000], ch2[1000]存放符号, ch[10000]判断符号的匹配
    int flag=1
     for j from 0 to ch[j]!=''
       if ch[j]== 除/* */ 以外的符号
        then
         ch2[k++]=ch [j]
          j++
        else if ch[j]=='/' && ch [j+1]=='*'
          ch2[k++]='<'
          j++
        else if ch[j]=='*' && ch [j+1]=='/'
         ch2[k++]='>'
         j++
    
     end for
    
    for i from 0 to k
      if   ch2[i] 为 左符号
       then  
        直接放入 栈中
      else if ch2[i]为右符号
       then
       if  栈中存在符号,且ch2中符号与栈符号对应
        then
         出栈
       else
        输出NO 
         判断缺少的符号 
         输出 ?-缺失符号
          flag =0 
           break
          end for
    
    if flag==1 且栈空
       then 
        输出 yes
    else if 栈不为空
      then
       输出NO
       判断栈中剩余符号,
       输出?-缺失符号
    

    2.1.2 总结解题所用的知识点

    使用malloc函数进行空间的动态申请
    判断字符为左符号,右符号,对其进行相应的入出栈操作
    使用替换的方式使判断更简单

    2.2 银行业务队列简单模拟

    2.2.1 解题思路及伪代码

    解题思路

    偶数顾客一次两个,奇数顾客一次输出一个。
    那么则创建两个队列,一个存放A窗口的客户,另一个存放B窗口的客户,并分别统计两个窗口的人数。

      #include<iostream>
      #include<string>
      #include<queue>
      using namespace std;
     定义数组a[]存放顾客数字
     定义队列qa  //存放奇数
     定义队列qb  //存放偶数
     输入 N     
     for i from 0 to N-1 
       输入 a[i]
       do if (a[i]为奇数)
       进入qa
        else
        进入qb
        end for
     
     int x,y  存放队列头
    if(qa队列长度大于qb队列长度的两倍)
    
      while(qa队列或qb队列不为空队列情况)
    
       if(qa不为空队列)
        then
         x = qa.front();
         输出x
         出队
    
         if(qa长度不为0)
          then
          输出 " "
    
         if(qa长度不为0)
          then
           输出 " "
        
        if(qb不为空队列)
         then
          y = qb.front();
          输出y
           出队
           输出" "
         
       
     else  //qa队列长度不大于qb队列长度两倍时
    
       while (qa队列或qb队列不为空队列情况)
         if(qa不为空队列)
          then
          x = qa.front();
          输出x
          出队
          输出" "
         
         x = qa.front();
          输出x
          出队
          输出" "
      
         if(qb不为空队列)
          then
           y = qb.front();
           输出y
           出队
    
         if(qb长度不为0)
              输出 " "
    
        
           return 0;
    
    

    2.2.2 总结解题所用的知识点

    c++库函数

    出队列函数pop(),

    判断队列是否为空队列函数empty()

    使用队列头部进行判断

    3.阅读代码----无法吃午餐的学生数量

    来自于leetcode--队列

    https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch/

    3.1 题目及解题代码

    题目如下

    解题代码

    逛了一圈,发现大佬们的解法各不相同,这里选择了几种方法比较阅读

    int countStudents(int* students, int studentsSize, int* sandwiches, int sandwichesSize){
        int arr[2];
        memset(arr, 0, sizeof(arr));
        for (int i=0; i<studentsSize; ++i) {
            ++arr[students[i]];
        }
        for (int i=0; i<sandwichesSize; ++i) {
            if (arr[sandwiches[i]] == 0) break;
            --arr[sandwiches[i]];
        }
        return arr[0] + arr[1];
    }
    
    作者:dong-feng-32
    链接:https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch/solution/c-zhi-xu-yao-pan-ding-xi-huan-zhan-ding-iffdu/
    来源:力扣(LeetCode)
    
    #include<stdlib.h>
    #define MAX 102		
    struct Queue
    {
            int a[MAX];
            int front;		
            int rear;	
    };
    //队列的基本操作
    void Init_Queue(struct Queue *q)
    {
            q->front=q->rear=0;			
    }
    
    int Queue_Length(struct Queue *q)
    {
            return (q->rear-q->front+MAX)%MAX;	
    }
    
    int Is_Empty(struct Queue *q)
    {
            if(q->front == q->rear)		
                    return 1;
            else
                    return 0;
    }
    
    int Is_Full(struct Queue *q)
    {
            if(q->front == (q->rear+1)%MAX)		
                    return 1;
            else
                    return 0;
    }
    
    int En_Queue(struct Queue *q,int x)
    {
            if(Is_Full(q))				
                return 0;
            q->a[q->rear] = x;			
            q->rear = (q->rear+1)%MAX;
            return 1;
    }
    
    int De_Queue(struct Queue *q)
    {
            if(Is_Empty(q))			
                    return 0;		
            q->front = (q->front+1)%MAX;
            return 1;
    }
    //将队头元素移至队尾
    int De_Queue1(struct Queue *q)
    {
            if(Is_Empty(q))			
                    return 0;		
            q->a[q->rear] = (q->a[q->front]);
            q->rear = (q->rear+1)%MAX;
            q->front = (q->front+1)%MAX;
            return 1;
    }
    //循环结束条件的判断
    int judge(struct Queue *q,int *sandwiches,int j){
    	int n,i;
    	int count=0;
    	n = Queue_Length(q);
        int n1 = q->front;
    	for(i = 0;i < n;i++){
    		if(q->a[n1] != sandwiches[j]){
    			count++;
    			n1 = (n1+1)%MAX;
    		}
    	}
    	if(count == n)
    	return 1;
    	else 
    	return 0;
    }
    
    int countStudents(int* students, int studentsSize, int* sandwiches, int sandwichesSize){
        int i,j=0;
        struct Queue *q = (struct Queue *)malloc(sizeof(struct Queue ));
        Init_Queue(q);
        for(i = 0;i < studentsSize;i++){
            En_Queue(q,students[i]);
        }
    
    作者:fzst
    链接:https://leetcode-cn.com/problems/number-of-students-unable-to-eat-lunch/solution/cyu-yan-shi-xian-4ms59mb-by-fzst-en7d/
    来源:力扣(LeetCode)
    
    

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

    第一版作者的解题思路很简单:若喜欢栈顶的甜点的学生存在,那么不管他们在队伍的哪个位置,必定会遍历到他。否则,一定无法继续拿掉栈顶甜点。

    直接遍历,通过循环结构实现,不喜欢圆形和不喜欢方形三明治的被统计出。
    这种解法的时间复杂度为o(n),相当简单。

    void *memset(void *s, int ch, size_t n);
    函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
    memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法 [1] 。
    memset()函数原型是extern void *memset(void *buffer, int c, int count) buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.

    第二版作者用了比较标准且详细的队列解决,但相比第一版作者的方法代码量较大。不过两者思路个人感觉其实差距不大。

    先将学生的喜好依次入队,然后将队列中的元素依次和三明治数组的头元素比较,如果相等,则让此学生出队,三明治数组元素后移一位。如果不相等,则将学生队列中的队头移至队尾,重复比较。
    当学生队列中的每一个都不喜欢三明治数组里的头元素则循环结束,所以可定义一个用来判断循环能否结束的函数来控制循环次数。最后如果学生队列为空,则返回0,反之,则返回学生队列中的元素个数。
    使用了多个函数封装处理,时间复杂度是o(n);

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

    题目的解题条件明显,需要考虑的元素数量其实不多,就是两种三明治与人的对应,均是从栈顶考虑

    难点在于不喜欢栈顶三明治的人回重新回到队列尾部,会进行多轮筛选。

  • 相关阅读:
    BZOJ 3674: 可持久化并查集加强版 可持久化并查集
    Codeforces Round #228 (Div. 1) C. Fox and Card Game 博弈
    Codeforces Round #228 (Div. 1) B. Fox and Minimal path 构造
    Codeforces Round #228 (Div. 1) A. Fox and Box Accumulation 贪心
    2016 UESTC Training for Data Structures 题解
    Codeforces Round #349 (Div. 1) B. World Tour 暴力最短路
    HDU 5344 MZL's xor 水题
    Codeforces Round #349 (Div. 1) A. Reberland Linguistics 动态规划
    Codeforces Beta Round #11 B. Jumping Jack 数学
    Codeforces Beta Round #11 A. Increasing Sequence 贪心
  • 原文地址:https://www.cnblogs.com/keepgoingccc/p/14619539.html
Copyright © 2020-2023  润新知