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


    这个作业属于哪个班级 C语言--网络2011/2012
    这个作业的地址 DS博客作业02--栈和队列
    这个作业的目标 学习栈和队列的结构设计及运算操作
    名字 黎钊涵

    0. 展示PTA总分

    1.本章学习总结

    1.1 栈

    栈结构的定义和特点

    • 栈(stack)是一个特殊的线性表,是限定仅在一端(通常是表尾)进行插入和删除操作的线性表
    • 先进后出、后进先出
    • 插入元素到栈顶(即表尾)的操作,称为入栈
    • 从栈顶(即表尾)删除最后一个元素的操作,称为出栈
    顺序栈结构体
    struct SNode {
        ElementType* Data;  /* 存储元素的数组   */
        Position Top;     /* 栈顶指针 */
        int MaxSize;
    };
    
    初始化栈
    void InitStack(SqStack* S)
    {
       S=new SqStack;      //分配一个顺序栈空间,首地址放在S中
       S->top=-1;          //栈顶指针置为-1
    }
    
    入栈
    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)
    {
        if (S->Top == -1)
            return 1;
        else
            return 0;
    }
    

    链栈(链栈是运算受限的单链表,插入和删除仅在栈顶处执行,头指针就是栈顶,不需要头结点,空栈相当于头指针指向空)

    结构体定义
    typedef int Elmetype;
    struct SNode
    {
    	Elmetype data;
    	struct SNode* next;
    };
    typedef struct SNode* LinkStack;
    
    进栈
    void Push(LinkStack& S, Elmetype X)
    {
    	LinkStack NewS = new SNode;
    	/*数据载入*/
    	NewS->data = X;
    	/*头插法插入新数据*/
    	NewS->next = S->next;
    	S->next = NewS;
    }
    
    出栈
    bool Pop(LinkStack& S, Elmetype& e)
    {
    	/*首先要判断栈顶是否为空*/
    	if (S->next == NULL)
    	{
    		return false;
    	}
    	e = S->next->data;
    	LinkStack delSNode = S->next;
    	S->next = delSNode->next;
    	delete delSNode;
    	return true;
    }
    

    1.2 栈的应用

    • 数制转换
      十进制数转八进制数代码如下
    public class Conversion 
    {
        public static void conversion(int N) 
        {
            ArrayStack<Integer> stack = new ArrayStack<>();
            while (N != 0) 
            {
                stack.push(N % 8);
                N /= 8;
            }
            while (!stack.isEmpty()) 
            {
                System.out.print(stack.pop());
            }
        }
    
        public static void main(String[] args) 
        {
            conversion(2007);
        }
    }
    
    • 括号匹配检验
      在编程过程中,如果有括号没有对应的另一半进行配对,编译器就会报错,可以用栈来实现前后括号匹配的检验,如下
    public class Match 
    {
        public static boolean match(String s) 
        {
            ArrayStack<Character> stack = new ArrayStack<>();
            for (int i = 0; i < s.length(); i++) 
            {
                char c = s.charAt(i);
                switch (c) 
                {
                case ')':
                    if (!stack.isEmpty() && stack.pop() == '(') 
                    {
                        break;
                    }
                    else 
                    {
                        return false;
                    }
                case ']':
                    if (!stack.isEmpty() && stack.pop() == '[')
                    {
                        break;
                    }
                    else 
                    {
                        return false;
                    }
                case '}':
                    if (!stack.isEmpty() && stack.pop() == '{') 
                    {
                        break;
                    }
                    else 
                    {
                        return false;
                    }
                default:
                    stack.push(c);
                    break;
                }
            }
            return stack.isEmpty();
        }
    
        public static void main(String[] args)  
        {
            System.out.println(match("{[()]()[{}]}"));
            System.out.println(match("{[()]}}"));
        }
    }
    
    • 迷宫求解
      求迷宫从入口到出口的所有路径伪代码如下
    初始化,将起点加入堆栈;
    while(堆栈不为空)
    {
        取出栈顶位置为当前位置;
        如果 当前位置是终点,
        则 使用堆栈记录的路径标记从起点至终点的路径;
        否则
        {
            按照从下、右、上、左的顺序将当前位置下一个可以探索的位置入栈;
            如果 当前位置的四周均不通
            则 当前位置出栈;
        }
    }
    
    

    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;
    }
    
    入队
    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;
    }
    
    判断是否为空
    bool QueueEmpty(Queue Q)
    {
        return (Q->front == Q->rear);
    }
    
    销毁
    void DestroyQueue(Queue Q)
    {
        free(Q);
    }
    

    环形队列

    结构体定义
    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;
    }
    
    入队
    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;
    }
    
    判断是否为空
    bool QueueEmpty(Queue Q)
    {
        return (Q->front == Q->rear);
    }
    
    销毁
    void DestroyQueue(Queue Q)
    {
        free(Q);
    }
    

    链式队列

    结构体定义
    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 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;
    }
    
    判断是否为空
    bool QueueEmpty(Queue Q)
    {
        return (Q->rear == NULL);
    }
    
    销毁
    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);
    }
    

    舞伴问题

    int QueueLen(SqQueue Q)//队列长度
    {
    	int sum = 0;
        int i;
        for (i = Q->front + 1; i <= Q->rear; i++)//front总在数前一位
        {
            sum++;
       }
       return sum;
         //return Q->rear - Q->front;
     } 
    int EnQueue(SqQueue &Q, Person e)//加入队列 
    {
    	if(Q->rear >= MAXQSIZE)
            return 0;
         //if(Q->rear >= MAXQSIZE) return 0;
    	Q->data[Q->rear++] = e;
    	return 1;
    } 
    int QueueEmpty(SqQueue &Q)//队列是否为空 
    {
    	return (Q->front == Q->rear);
    }
    int DeQueue(SqQueue &Q, Person &e)//出队列 
    {
    	if(QueueEmpty(Q))
            return 0;
    	e = Q->data[Q->front++];
    	return 1;
    }
    void DancePartner(Person dancer[], int num) //配对舞伴 
    {
    	Person male,female;
    	int i;
         //将男生女生数组全部入队
    	for(i = 0; i < num; i ++)
        {
    		
    		if(dancer[i].sex == 'F')
    			EnQueue(Fdancers,dancer[i]);
    		else 
    			EnQueue(Mdancers,dancer[i]); 
    	}
    	while(QueueLen(Fdancers) != 0 && QueueLen(Mdancers) != 0)
        {
    		DeQueue(Fdancers,male);
    		cout<<male.name<<"  ";
    		DeQueue(Mdancers,female);
    		cout<<female.name <<endl;
    	} 
    }
    
    

    2.PTA实验作业

    2.1 符号配对(本题用C++作答,此段代码用C则编译错误)

    #include<iostream>
    #include<cstdlib>
    using namespace std;
    //#define ERROR NULL
    const int MaxSize=109;
    typedef char ElementType;
    
    struct Stack{
        ElementType Symbol[MaxSize];
        int Top;
    };
    
    Stack* Create();
    bool Push(Stack* S,ElementType X);
    ElementType Pop(Stack* S);
    ElementType getTop(Stack* S);///获取栈顶元素
    
    int main()
    {
        Stack* S=Create();
        char str[1000],stacktop;
        int i,flag=0,flag2=0,flag_i=0;
        while(true)
        {
            cin.getline(str,1000);  ///用gets发生编译错误
            if(str[0]=='.') 
                break;///一行一行地读取,遇到'.'时结束
            for(i=0;str[i]!='';i++)
            {
                flag_i=0;
                /** 遇到左符号,入栈*/
                if(str[i]=='('||str[i]=='['||str[i]=='{')
                    Push(S,str[i]);
                if(str[i]=='/'&&str[i+1]=='*')
                {
                    flag_i=1;///遇到/*的标志
                    Push(S,str[i]);
                    Push(S,str[i+1]);
                ///    i++; 若在此处使i++,则下面的if语句中i值被改变
                }
                /** 遇到右符号,与栈顶符号配对*/
                if(str[i]==')')
                {
                    if(S->Top==-1)///栈为空,则当前右符号缺少左符号,结束循环
                    {
                        cout<<"NO"<<endl;
                        cout<<"?-"<<str[i]<<endl;
                        flag=1;///栈空时判断是否YES的标志
                        flag2=1;///跳出while循环的标志
                        break;
                    }
                    stacktop=getTop(S);
                    if(stacktop!='(')///栈顶元素与当前右符号不匹配,结束循环
                    {
                        flag2=1;
                        break;
                    }
                    else
                        Pop(S); ///匹配则出栈
                }
                if(str[i]==']')
                {
                    if(S->Top==-1)
                    {
                        cout<<"NO"<<endl;
                        cout<<"?-"<<str[i]<<endl;
                        flag=1;
                        flag2=1;
                        break;
                    }
                    stacktop=getTop(S);
                    if(stacktop!='[')
                    {
                        flag2=1;
                        break;
                    }
                    else
                        Pop(S);
                }
                if(str[i]=='}')
                {
                    if(S->Top==-1)
                    {
                        cout<<"NO"<<endl;
                        cout<<"?-"<<str[i]<<endl;
                        flag=1;
                        flag2=1;
                        break;
                    }
                    stacktop=getTop(S);
                    if(stacktop!='{')
                    {
                        flag2=1;
                        break;
                    }
                    else
                        Pop(S);
                }
                if(str[i]=='*'&&str[i+1]=='/')
                {
                    if(S->Top==-1)
                    {
                        cout<<"NO"<<endl;
                        cout<<"?-*/"<<endl;
                        flag=1;flag2=1;
                        break;
                    }
                    stacktop=getTop(S);
                    if(stacktop!='*')
                    {
                        flag2=1;
                        break;
                    }
                    else
                    {
                        Pop(S);
                        Pop(S);
                    }
                    i++;/// */比较完毕后i同样++
                }
                if(flag_i)
                    i++;/// 缺少该语句将使 /*/ 被判定为配对成功
            }
            if(flag2)
                break;
        }
        if(S->Top!=-1)///栈不空,则栈顶元素缺少右符号
        {
            cout<<"NO"<<endl; ///YES NO 注意大写
            if(getTop(S)=='*')
                cout<<"/*-?"<<endl;
            else
                cout<<Pop(S)<<"-?";
        }
        else if(!flag)///栈空且flag==0,全部配对成功
            cout<<"YES";
    
        system("pause");
        delete S;
        
        return 0;
    }
    
    Stack* Create()
    {
        Stack* S=new Stack;
        S->Top=-1;
        return S;
    }
    
    bool Push(Stack* S,ElementType X)
    {
        if(S->Top==MaxSize-1)
            return false;
        S->Symbol[++(S->Top)]=X;
        return true;
    }
    
    ElementType Pop(Stack* S)
    {
       // if(S->Top==-1)
          //  return ERROR;
        return S->Symbol[(S->Top)--];
    }
    
    ElementType getTop(Stack* S)
    {
        ElementType top=Pop(S);
        Push(S,top);
        return top;
    }
    
    

    2.1.1解题思路及伪代码

    把比较特殊的/和/用< >代替,创建一个栈然后把找到的对应符号放入栈中,然后进行比较得到符号是否匹配

    int main
    {
      static char ch1[1000], ch2[1000], ch[10000];//ch放代码,ch2放找到的符号,ch1用于符号匹配
    for(i = 0;; i++)
      {
        找到对应符号然后放入ch2中//用<>代替两个的符号
      }
    int flag=1 用于记录
    for (i = 0; i < k; i++)
      {
        if ch2中符号是左符号,放入栈中
        else if ch2中符号是右符号
        {
          if 栈中存在符号,并且和ch2和栈中符号匹配,则消除栈中该符号
          else 输出NO 和对应缺少的符号,flag=0
        }
      }
    if flag=1同时栈中无符号 输出YES
    else
      {  输出  NO
         根据栈中情况输出对应缺少符号
      }
    }
    

    2.1.2总结解题所用的知识点

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

    2.2 银行业务队列简单模拟

    2.2.1 解题思路及伪代码

    思路

    伪代码

    输入人数k
    创建队列q,p
    for (i = 0; i < k; i++)
    {
        cin >> n;//输入编号
        if (n % 2)  编号为奇数则入奇数的栈;
        else  编号为偶数则入偶数的栈	;
    }
    for (i = 0; i < k; i++)
    {
    	if (i == 0)//对第一个数据输出处理空格
    	if ((i + 1) % 3)//对a窗口处理
    	{
    		if (!q1.empty()//判断是否处理完毕
                            未处理完毕打出a窗口的编号;
    	        else 处理完毕直接打出b窗口的所有编号;	
    	}
    	else//对b窗口处理
    	{
    		if (!q2.empty())//判断是否处理完毕
                            未处理完毕打出b窗口的编号
    		else 处理完毕直接打出b窗口的所有编号
    	}
    }
        return 0;
    }
    

    2.2.2 总结解题所用的知识点

    • 学会运用queue容器。
    • 掌握了队列的创建,判空,入队,出队等操作
    • 懂得了对两个队列的判断,当A或B两个有一个队列为空就退出循环,然后单独输出剩余队列

    3.阅读代码

    3.1 题目及解题代码

    Stack CreateStack(int MaxSize)//双栈结构即为两个栈共享一块空间
    {
        Stack stack = (struct SNode *)malloc(sizeof(struct SNode));//先为栈分配一个空间
        stack->Data = (int *)malloc(sizeof(ElementType)* MaxSize);//为栈分配一个Macsize大小的数组空间存放值
        stack->Top1 = -1;//栈1空
        stack->Top2 = MaxSize;//栈2空
        stack->MaxSize = MaxSize;//
        return stack;
    }
    
    bool Push(Stack S, ElementType X, int Tag)//入栈操作
    {
        if (!S)//这个栈空间不存在,分配失败的时候
            return false;
        if (S->Top1+1==S->Top2)//栈满的情况
        {
            printf("Stack Full
    ");
            return false;
        }
    
        if (Tag == 1)
           
            S->Data[++S->Top1] = X;//++在前先取数据使用后自加
     
         else 
             S->Data[--S->Top2] = X;
    
         return true;
    }
    
    ElementType Pop(Stack S, int Tag)
    {
        if (!S)
            return ERROR;
        if (Tag == 1)
        {
            if (S->Top1 == -1)//空栈时
            {
                printf("Stack %d Empty
    ",Tag);
                return ERROR;
            }
            return S->Data[S->Top1--];//出栈top1向前移动
        }
        
        if (S->Top2 == S->MaxSize)
        {
            printf("Stack %d Empty
    ", Tag);
            return ERROR;
        }
        return S->Data[S->Top2++];//出栈top2向后移动
        
    }
    
    

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

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

  • 相关阅读:
    糊涂的教授
    有趣的英语角
    聚会
    新年礼物
    三核苷酸
    数字编码
    【同行说技术】iOS程序员从小白到大神必读资料汇总
    【同行说技术】Android图片处理技术资料汇总(一)
    【同行说技术】swift最全学习资料汇集(一)
    【同行说技术】iOS程序员从小白到大神必读资料汇总(一)
  • 原文地址:https://www.cnblogs.com/jmlzh/p/14956214.html
Copyright © 2020-2023  润新知