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


    0.PTA得分截图

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

    1.1 栈

    • 定义:栈是一种只能在一端进行插入删除操作的线性表。
    • 组成:栈顶--Top进行操作; 栈底--不能进行任何操作
    • 特性:先进后出,后进先出;线性关系
    • 基本操作:初始化,销毁,判断是否为空,进栈,出栈,取栈顶元素
    • 存储结构:顺序栈与链栈,两者的不同与其存储结构有关

    1.1.1 顺序栈

    • 四要素:
      1. 栈空:top=-1
      2. 栈满:top=MaxSize-1
      3. 进栈:S.data[++S.top]=e
      4. 出栈:e=S.data[S.top--]
    • 结构体
    typedef struct                 
    {
       ElemType data[MaxSize];
       int top;   //栈顶指针
    }Stack,*SqStack;
    
    • 初始化
    void CreatStack(SqStack s) {
    	s = new Stack;
    	s->top = -1;
    }
    
    • 是否为空
      看top是否有增加即可判断
    bool StackEmpty(SqStack s) {
    	return (s->top == -1);
    }
    
    • 进栈
      元素e进栈,先将top++腾出空位,再将e放到栈顶
    bool Push(SqStack s, ElemType e) {
    	if (s->top == MaxSize-1) {
    		cout << "栈满";
    		return false;
    	}
    	s->data[++s->top] = e;
    	return true;
    }
    
    • 出栈
      直接让栈顶top--,即可,但不是物理删除
    bool Pop(SqStack s, ElemType e) {
    	if (s->top == -1) {
    		cout << "栈空";
    		return false;
    	}
    	e=s->data[s->top--];
    	return true;
    }
    

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

    1.1.2 链栈

    • 四要素:
      1. 栈空:S->next=NULL
      2. 栈满:不考虑
      3. 进栈:头插法
      4. 出栈:e=S->next->data,并删除结点
    • 结构体
    typrdef struct linkNode
    {
       ElemType data;
       struct linkNode *next;
    }LiNode,*Listack;
    
    
    • 初始化
    void CreatStack(LiStack &s)
    {  
       s=new LiNode;
       s->next=NULL;
    }
    
    • 是否为空
    bool StackEmpty(LiStack S)
    {
    	return (S->next == NULL);
    }
    
    • 进栈
    void Push(LiStack& S, ElemType e)
    {
    	LiStack p;
    	p = new LiNode;
    	p->data = e;
    	p->next = S->next;//头插法
    	S->next = p;
    }
    
    • 出栈
    bool Pop(LiStack& S, ElemType e)
    {
    	LiStack p;
    	if (S->next == NULL)return false;
    	p = S->next;
    	e = p->data;
    	S->next = p->next;
    	delete p;
    	return true;
    }
    
    • 取栈顶元素
    bool DetTop(LiStack& S, ElemType e)
    {
    	if (S->next == NULL)return false;
    	e = S->next->data;
    	return true;
    }
    

    1.1.3C++中的stack库

    函数 用法
    stack<int>S 定义int类型的栈
    S.push(x) X进栈
    S.pop() 弹出栈顶元素
    e=S.top() 取栈顶元素赋给e
    S.empty() 判断栈是否为空
    S.size() 判断栈的长度

    使用时加上头文件#include<stack>
    采用链栈的方式存储

    1.1.4 栈的应用

    1. 中缀表达式转后缀表达式

    • 数字:碰到数字就输出,对于多位数或小数采取循环解决
    • 正负号:开头正负号,flag标记,正号不输出,后面的正负号和前面一样
    • 加减号:优先级最低,所以进栈的时候,必须是空栈,除非是左括号
    • 乘除号:优先级最高,但栈顶如果也是乘除,则先弹出,再入栈
    • 左括号:进栈前优先级最高,直接进栈,进栈后优先级最低
    • 右括号:不入栈,将栈中元素弹出,直到碰到左括号
      代码如下
    #include<iostream>
    #include<stack>
    #include<string>
    using namespace std;
    stack<char>S;
    int main()
    {
    	int flag=0;
    	string str;
    	cin >> str;
    	int len = str.length();
    
    	for (int i = 0; i < len; i++) {//对字符进行遍历
    		/*判断有负号*/
    		if ((str[i] == '-'||str[i]=='+') && flag == 0){
                if(str[i]=='+') continue;//加号不输出
                    cout << str[i];//对第一个字符进行判断有无负号
            }
    		else if ((str[i] == '-'||str[i]=='+') && i - 1 >= 0 && str[i - 1] == '(') {//对后面数据进行判断,是否有负号
    			if(str[i]=='+'){ cout<<" ";
                    flag = 0;
                    continue;
                }
                    cout << " " << str[i];
    		}
    		/*判断是否是数字,包括小数*/
    		else if ((str[i] >= '0' && str[i] <= '9')||str[i]=='.') {
    			if (flag)cout << " ";
    			while ((str[i] >= '0' && str[i] <= '9') || str[i] == '.') cout << str[i++];
    			i--;//避免下一个数据被埋没
    			flag = 1;//除去第一个数不带空格,后面都要带
    		}
    		/*判断运算符*/
    		else if (str[i] == '-' || str[i] == '+') {//加减优先级相同,且优先级低
    			if (S.empty())S.push(str[i]);//当栈为空时,进行入栈	
    			else {//栈顶优先级高,进行出栈,直到空栈
    				while (!S.empty()) {
    					if (S.top() == '(')break;//左括号进栈后优先级最低
    					cout << " " << S.top();
    					S.pop();
    				}
    				S.push(str[i]);
    			}
    		}
    		else if (str[i] == '(')S.push(str[i]);//左括号进栈前优先级最高,直接入栈
    		else if (str[i] == '*' || str[i] == '/') {//遇到乘与除,优先级高,如果栈顶为乘或除,需要将它们输出,再入栈
    			while (!S.empty() && (S.top() == '*' || S.top() == '/')) {
    				cout << " " << S.top();
    				S.pop();
    			}
    			S.push(str[i]);
    		}
    		else if (str[i] == ')') {//遇到右括号,就让左括号上面的全部输出,并将左括号弹出
    			while (S.top() != '(') {
    				cout << " " << S.top();
    				S.pop();
    			}
    			S.pop();
    		}
    	}
    	while (!S.empty()) {//将栈中剩余输出
    		cout << " " << S.top();
    		S.pop();
    	}
    	return 0;
    }
    
    

    2. 符号配对

    • 当遇到左符号时:进行入栈,对于/*只需要入/即可
    • 当遇到右符号时:判断是否为空,不为空在进行符号匹配
    • 对/* 和*/特判
    • 匹配:1.匹配成功;2.栈空,缺少左符号;3.栈不空,缺少右符号
      代码如下
    #include<iostream>
    #include<string>
    #include<stack>
    using namespace std;
    stack<char>S;
    int IsMatch(char a, char b);
    int main()
    {
    	string s, str;
    	int len;
    	while (1) {//读入字符
    		getline(cin, s);
    		if (s == ".")break;
    		str += s;
    	}
    	len = str.length();
    
    	for (int i = 0; i < len; i++) {
    		if (str[i] == '(' || str[i] == '[' || str[i] == '{') S.push(str[i]);//左符号入栈
    
    		else if (str[i] == '/' && i + 1 < len && str[i + 1] == '*')S.push(str[i++]); //左符号入栈
    
    		else if (str[i] == ')' || str[i] == ']' || str[i] == '}') {//右符号进行匹配
    			if (!S.empty() && IsMatch(S.top(),str[i]))//匹配成功
    				S.pop();
    			else if (S.empty()) {//栈空
    				cout << "NO" << endl;
                    if(str[i]=='*')cout<<"?-*/";
                    else cout<<"?-"<<str[i];
                    return 0;
                }
                else if(!S.empty()){
                    cout << "NO" << endl;
                    if(S.top()=='/')cout<<"/*-?";
                    else cout<<S.top()<<"-?";
                    return 0;
                }
    		}
    
    		else if (str[i] == '*' && str[i + 1] == '/' && (i + 1 < len)) {//  /*进行匹配
    			if (!S.empty() && S.top() == '/')//匹配
    				S.pop();
    			else if (S.empty()) {//栈空
    				cout << "NO" << endl;
                    if(str[i]=='*')cout<<"?-*/";
                    else cout<<"?-"<<str[i];
                    return 0;
                }
                else if(!S.empty()){
                     cout << "NO" << endl;
                    if(S.top()=='/')cout<<"/*-?";
                    else cout<<S.top()<<"-?";
                    return 0;
    			}
    			i++;
    		}
    	}
    	if (S.empty())cout << "YES";
    	else {
    		cout << "NO" << endl;
    		if(S.top()=='*'||S.top()=='/')  cout <<"/*-?";
    		else cout << S.top() << "-?";
    	}
    	return 0;
    }
    int IsMatch(char a, char b)
    {
    	if (a == '[' && b == ']')return 1;
    	else if (a == '(' && b == ')')return 1;
    	else if (a == '{' && b == '}')return 1;
    	else return 0;
    }
    
    

    3. 迷宫求解
    深度搜索(DFS),又称回溯法。
    从上一个节点开始,任意找下一个能走的点,当找不到能走的点时,退回上一个点寻找是否有其他方向的点。
    使用栈存储当前路径。后进先出,方便回退到上一个点。
    这种找到的不是最短路,但却效率高

    #include <stdio.h>
    #define MaxSize 100
    #define M 8
    #define N 8
    int mg[M + 2][N + 2] =
    {
    	{1,1,1,1,1,1,1,1,1,1},
    	{1,0,0,1,0,0,0,1,0,1},
    	{1,0,0,1,0,0,0,1,0,1},
    	{1,0,0,0,0,1,1,0,0,1},
    	{1,0,1,1,1,0,0,0,0,1},
    	{1,0,0,0,1,0,0,0,0,1},
    	{1,0,1,0,0,1,1,0,0,1},
    	{1,0,1,1,1,0,1,1,0,1},
    	{1,1,0,0,0,0,0,0,0,1},
    	{1,1,1,1,1,1,1,1,1,1}
    };
    typedef struct
    {
    	int i;				//当前方块的行号
    	int j;				//当前方块的列号
    	int di;				//di是下一可走相邻方位的方位号
    } Box;
    typedef struct
    {
    	Box data[MaxSize];
    	int top;			//栈顶指针
    } StType;				//定义栈类型
    int mgpath(int xi, int yi, int xe, int ye)	//求解路径为:(xi,yi)->(xe,ye)
    {
    	int i, j, k, di, find;
    	StType st;					//定义栈st
    	st.top = -1;					//初始化栈顶指针
    	st.top++;      				//初始方块进栈
    	st.data[st.top].i = xi; st.data[st.top].j = yi;	st.data[st.top].di = -1;
    	mg[xi][yi] = -1;
    	while (st.top > -1)			//栈不空时循环
    	{
    		i = st.data[st.top].i; j = st.data[st.top].j; di = st.data[st.top].di;  //取栈顶方块
    		if (i == xe && j == ye)		//找到了出口,输出路径
    		{
    			printf("迷宫路径如下:
    ");
    			for (k = 0; k <= st.top; k++)
    			{
    				printf("	(%d,%d)", st.data[k].i, st.data[k].j);
    				if ((k + 1) % 5 == 0)	//每输出每5个方块后换一行
    					printf("
    ");
    			}
    			printf("
    ");
    			return(1);		//找到一条路径后返回1
    		}
    		find = 0;
    		while (di < 4 && find == 0)		//找下一个可走方块
    		{
    			di++;
    			switch (di)
    			{
    			case 0:i = st.data[st.top].i - 1; j = st.data[st.top].j; break;
    			case 1:i = st.data[st.top].i; j = st.data[st.top].j + 1; break;
    			case 2:i = st.data[st.top].i + 1; j = st.data[st.top].j; break;
    			case 3:i = st.data[st.top].i, j = st.data[st.top].j - 1; break;
    			}
    			if (mg[i][j] == 0) find = 1;	//找到下一个可走相邻方块
    		}
    		if (find == 1)					//找到了下一个可走方块
    		{
    			st.data[st.top].di = di;		//修改原栈顶元素的di值
    			st.top++;					//下一个可走方块进栈
    			st.data[st.top].i = i; st.data[st.top].j = j; st.data[st.top].di = -1;
    			mg[i][j] = -1;				//避免重复走到该方块
    		}
    		else							//没有路径可走,则退栈
    		{
    			mg[st.data[st.top].i][st.data[st.top].j] = 0;//让该位置变为其他路径可走方块
    			st.top--;					//将该方块退栈
    		}
    	}
    	return(0);							//表示没有可走路径,返回0
    }
    int main()
    {
    	mgpath(1, 1, 7, 5);
    	return 0;
    }
    

    1.3 队列

    • 定义:队列是一种只能在一端进行插入,另一端进行删除操作的线性表。
    • 组成:队头--front进行删除操作; 队尾--rear进行插入操作
    • 特性:先进先出,后进后出;线性关系
    • 基本操作:初始化,销毁,判断是否为空,进队列,出队列,取队头(或队尾)元素
    • 分类:顺序队列,环形队列,链队列

    1.3.1顺序队列

    • 四要素:
      1. 队空:front=rear
      2. 队满:rear=MaxSize-1
      3. 进队:Q->data[++Q->rear]=e
      4. 出队:e=Q->data[Q->front--]
    • 结构体
    typedef struct {
    	ElemType data[MaxSize];
    	ElemType front, rear;
    }Queue,*SqQueue;
    
    • 初始化队列
    void CreatQueue(SqQueue& Q) 
    {
    	Q == new Queue;
    	Q->front = Q->rear = -1;
    }
    
    • 判断是否为空
    bool QueueEmpty(SqQueue& Q)
    {
    	return (Q->front == Q->rear);
    }
    
    
    • 进队列
    bool EnQueue(SqQueue& Q, ElemType e)
    {
    	if (Q->rear + 1 == MaxSize)return false;
    	Q->data[++Q->rear]=e;
    	return true;
    }
    
    • 出队列
    bool DeQueue(SqQueue& Q, ElemType& e)
    {
    	if (Q->front == Q->rear)return false;
    	e = Q->data[Q->front--];
    	return true;
    }
    

    1.3.2环形队列

    由于顺序队列中,队头进行删除后,并不是物理删除,只是front指针后移,会导致前面空间的浪费,
    最后的结果是,当达到front=rear时,很大的空间并没有数据,造成假溢出,此时就要用环形队列啦!!!
    环形队列就像是一个大圆桌,有人来就找空位,有人走腾出空位,直到全部坐满。


    其存储结构与顺序表相同,在某些地方发生一些改变

    不同 顺序队列 循环队列
    初始化 rear=front=-1 rear=front=0
    队满 rear=front (rear+1)%MaxSize=front
    进队 rear++ rear=(rear+1)%MaxSize
    出队 front++ front=(front+1)%MaxSize

    1.3.1链队列

    • 结构体
    //定义节点结构
    typedef struct node {
        ElemType data;
        struct node* next;
    }QueueNode;
    //定义头节点
    typedef struct {
        QueueNode* front;
        QueueNode* rear;
    }LinkQueue;
    
    • 初始化队列
      初始化链队列,头节点置空
    void InitQueue(LinkQueue* Q)
    {
        Q->front = Q->rear = NULL;
    }
    
    • 判断是否为空
    int QueueEmpty(LinkQueue* Q)
    {
        return(Q->front == NULL && Q->rear == NULL);
    }
    
    • 进队列
    void EnLinkQueue(LinkQueue* Q, ElemType v)
    {
        QueueNode* p;
        p = new QueueNode;//为新的节点分配空间
        p->data = v;
        p->next = NULL;
        if (QueueEmpty(Q))
            Q->front = Q->rear = p;
        else
        {
            Q->rear->next = p;  //将新的节点连接到队列
            Q->rear = p;             //指向队列尾
        }
    }
    
    • 出队列
    bool DeLinkQueue(LinkQueue* Q, ElemType &e)
    {
        QueueNode* s;
        if (QueueEmpty(Q))return false;     //判断队列是否为空
        s = Q->front;
        e = s->data;
        if (Q->front == Q->rear)   //判断队列是否只有一个节点
            Q->front = Q->rear = NULL;
        else
            Q->front = s->next;
        delete s;
        return true;
    }
    

    1.3.4C++中的queue库

    函数 用法
    queue<int>Q 定义一个队列
    Q.push(X) X元素进队列尾
    Q.pop() 弹出队头元素
    e=Q.front() 队头元素赋给e
    e=Q.back() 队尾元素赋给e
    Q.empty() 判断是否尾空
    Q.size() 计算队列长度

    使用时加上头文件#include<queue>
    采用链式存储

    1.3.5队列应用

    1.报数问题
    运用的数据结构:环形队列
    只要不是出队列的数据,都先出队列,再进队列;
    满足要求就输出

    #include<iostream>
    #include<queue>
    using namespace std;
    queue<int>q;
    int main()
    {
        int n,m,t;
        cin>>n>>m;
        if(m>n){
            cout<<"error!";
            return 0;
            }
        for(int i=1;i<=n;i++) q.push(i);
        for(int i=1;i<n;i++){
            for(int j=1;j<m;j++){
                t=q.front();//保存
                q.pop();//弹出
                q.push(t);//进入
            }
            t=q.front();//第m个数
            cout<<t<<" ";
            q.pop();
        }
        cout<<q.front();
    }
    

    2.迷宫之最短路
    队列解决迷宫问题,广度搜索(BFS),能够找到最短路,效率不如DFS
    从一个节点开始,寻找所有接下来能继续走的点,继续不断寻找,直到找到出口。
    使用队列存储当前正在考虑的节点。

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

    2.PTA实验作业(4分)

    Gitee

    2.1 7-3 符号配对

    2.1.1 解题思路及伪代码

    • 思路
    1. 当遇到左符号时:进行入栈,对于/*只需要入/即可
    2. 当遇到右符号时:判断是否为空,不为空在进行符号匹配
    3. 对/* 和*/特判
    4. 匹配:1.匹配成功;2.栈空,缺少左符号;3.栈不空,缺少右符号
    • 伪代码
    stack<char>S
    将字符读入str字符数据中
    for i = 0 to str.length()
      if str[i]是(, [, { then S.push(str[i])                        
    
      else if str[i] = / && i + 1 < str.length() && str[i + 1] = *
      then S.push(str[i++])
    
      else if str[i] = ),], }
        if S不空且S.top()与str[i]匹配,弹出栈顶S.pop()
    
        else if S空
              cout << "NO"<<endl
              if str[i]=* cout<<"?-*/"
              else cout<<"?-"<<str[i]
              return 0
         else if
              cout << "NO"<<endl
              if S.top()=/ cout<<"/*-?"
              else cout<<S.top()<<"-?"
              return 0
    
      else if str[i] = *&&i + 1 < str.length() && str[i + 1] = /
         if  S不空且S.top() = / thenS.pop()//匹配成功
         else if S空
              cout << "NO"<<endl
              if str[i]=* cout<<"?-*/"
              else cout<<"?-"<<str[i]
              return 0
         else if
              cout << "NO"<<endl
              if S.top()=/ cout<<"/*-?"
              else cout<<S.top()<<"-?"
              return 0
         i++
    end for
    
    if 栈空 cout<<"YES"
    else
        cout<<"NO"
        if top是/ cout<<"/*-?"
        else cout<<S.top()<<"-?"
    
    return 0
    
    

    2.1.2 总结解题所用的知识点

    利用栈的先进后出特点,最顶端一定是和右符号最近的左符号,进行比对,判断是否匹配
    利用stack库,使得操作更快
    学会思考多种情况和特殊情况的处理,将/左符号只留一个/右符号留一个 -

    2.2 银行业务队列简单模拟

    2.2.1 解题思路及伪代码

    • 思路
      输入时,将a,b客户分别入队到对应的队列中
      开始循环输出,a,输出两个,b,输出一个
      最后输出剩余队列的元素
    • 伪代码
    queue<int>a, b;//a,b分别代表两个银行,将数据入队
    while a,b都不为空
       // 输出两个a,一个b
      if flag=1  cout<<a.front() flag=0//进行空格处理
      else cout<<" "<<a.front()
      a.pop()
      if a不为空,cout << " " << a.front() a.pop()
      cout << " " << b.front() b.pop()
    end while
    while a不为空
        if flag = 1  cout << a.front() flag = 0//没有b的元素进行空格处理
        else cout << " " << a.front()
        a.pop()
    end while
    while b不为空
       if flag = 1  cout << b.front() flag = 0//没有a的元素进行空格处理
       else cout << " " << b.front()
       b.pop()
    end while
    

    2.2.2 总结解题所用的知识点

    根据队列先进先出,可以将不同银行客户按顺序输出,
    直接使用C++中的queue库,更加快捷方便

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

    3.1 题目及解题代码

    LeetCode 餐盘栈

    class DinnerPlates {
    public:
        int cap;
        set<int> notFullStack;
        map<int, stack<int>> stackCont;
        DinnerPlates(int capacity) {
            cap = capacity;
        }   
        void push(int val) {
            // 正常情况下 stackCont 为空时 notFullStack 也为空
            if(stackCont.size() == 0 ){
                stackCont[0].push(val);
                if(stackCont[0].size() < cap) notFullStack.insert(0);
            }
            else if(stackCont.size() != 0 && notFullStack.size() == 0){
                int lastStackIndex = stackCont.rbegin()->first ;
                // 不需要 判断最后一个 stack 是否 满了
                stackCont[lastStackIndex + 1].push(val);
                if(stackCont[lastStackIndex + 1].size() < cap) notFullStack.insert(lastStackIndex + 1);
            } 
            else if( stackCont.size() != 0 && notFullStack.size() != 0 ){
                int firstNotFullFromLeft = *notFullStack.begin();
                stackCont[firstNotFullFromLeft].push(val);
                if(stackCont[firstNotFullFromLeft].size() >= cap) notFullStack.erase(firstNotFullFromLeft);
            }
        }  
        int pop() {
            if(stackCont.size() == 0) return -1;
            int lastStackIndex = stackCont.rbegin()->first ;
            int val = stackCont[lastStackIndex].top();        
            stackCont[lastStackIndex].pop();
            int lastStackSize = stackCont[lastStackIndex].size();
            // 没有满的 stack
            notFullStack.insert(lastStackIndex);
            if(lastStackSize == 0) {
                stackCont.erase(lastStackIndex);
                notFullStack.erase(lastStackIndex);
            } 
            return val;
        }    
        int popAtStack(int index) {
            if( stackCont.find(index) == stackCont.end() ) return -1;
            // 最大的栈 index
            int lastStackIndex = stackCont.rbegin()->first ;
            int val = stackCont[index].top();
            stackCont[index].pop();
            int thisStackSize = stackCont[index].size();
            notFullStack.insert(index);
            if(thisStackSize == 0) {
                stackCont.erase(index);
                if(lastStackIndex == index) notFullStack.erase(index);
            }
            return val;
        }
    };
    

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

    利用了C++中的STL库的set和map;
    set记录未满的栈的index序列,set可以使之有序
    map 记录栈index 以及对应的 stack

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

    • 优点:
      利用了C++中的STL库的set和map;
      了解了setmap的一些用法

    • 缺点:

    名称过于冗长,阅读有点麻烦。。。

  • 相关阅读:
    mac 终端命令
    安装和使用Carthage
    Mac下的常用终端命令与vim常用命令
    swift 获取推送deviceToken
    使mac版的MYSQL支持emoji表情
    iOS --- 通过CPU实现的简单滤镜效果
    IOS多选单选相册图片
    AVCaptureDevice iOS摄像头属性
    GPUImage 滤镜介绍
    苹果IOS开发者账号如何续费-Appstore
  • 原文地址:https://www.cnblogs.com/ww-yy/p/14608605.html
Copyright © 2020-2023  润新知