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

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

0.PTA得分截图

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

1.1 栈

顺序栈的结构、操作函数

结构:

操作函数:

定义:

typedef struct 
{  ElemType data[MaxSize]; //栈中数据元素
   int top;		//top为栈顶指针
} Stack;
typedef Stack *SqStack;

初始化:

void InitStack(SqStack s)
{
    s = new SqStack;//分配一个顺序栈的空间,首地址存放s处
    s->top = -1;    //栈顶指针置为-1
}

入栈出栈:

bool Push(SqStack &s,ElemType e)
{
    if(s->top == MAXSIZE - 1)    //判断是否栈满
    {
        return false;
    }
    s->data[s->top++] = e;    //入栈
    return true;
}
bool Pop(SqStack &s,ElemType e)
{
    if(StackEmpty(s))    //判断是否为空栈
    {
        return false;
    }
    e = s->data[s->top--];    //退栈
    return true;
}

销毁栈:

void DestroyStack(SqStack s)
{
   delete s;
}

链栈的结构、操作函数

结构:

操作函数:
定义:

typedef struct StackNode
{
    ElemType data;
    struct StackNode *next;
}Node,*Stack;

初始化:

bool InitStack(Stack &s)
{
    s = NULL;
    return true;
}

入栈出栈:

void Push(Stack& s, ElemType e)
{
	Stack p;
	p = new Node;
	p->data = e;		//新建节点p
	p->next = s->next;	//插入*p节点作为开始节点
	s->next = p;
}
bool Pop(Stack& s, ElemType& e)
{
	Stack p;
	if (StackEmpty(s))		//栈空的情况
		return false;
	p = s->next;			//p指向开始节点,从栈顶开始出栈
	e = p->data;
	s->next = p->next;		//删除*p节点
	delete p;				//释放*p节点
	return true;
}

1.2 栈的应用

括号匹配检验

假设表达式中包含三种括号:圆括号、方括号和花括号,并且它们可以任意嵌套。例如{()[{}]}或[{()}([])]等为正确格式,而{[}()]或[({)]为不正确的格式。
算法需要一个栈,在读入字符的过程中,如果是左括号,则直接入栈,等待相匹配的同类右括号;如果是右括号,且与当前栈顶左括号匹配,则将栈顶左括号出栈,如果不匹配则属于不合法的情况。另外,如果碰到一个右括号,而堆栈为空,说明没有左括号与之匹配,则非法。那么,当字符读完的时候,如果是表达式合法,栈应该是空的,如果栈非空,那么则说明存在左括号没有相应的右括号与之匹配,也是非法的情况。

#include<iostream>
#include<stack>
#include<string>
#include<vector>
using namespace std;
bool MatchBrackets(string braket_st);
int main()
{
	string bracket_str;
	cin >> bracket_str;
	bool temp;
	temp = MatchBrackets(bracket_str);
	return 0;
}
bool MatchBrackets(string braket_st)
{
	stack<char> st;//初始化栈
	int i;
	for (i = 0; i < braket_st.size(); i++)
	{
		if (braket_st[i] == '(')
			st.push(braket_st[i]);//入栈

		else if (braket_st[i] == ')')
		{
			if (st.empty())//栈为空
			{
				cout << "no";
				return false;
			}

			if (st.top() != '(')
			{

				cout << st.top() << endl;//取栈顶元素
				cout << "no";

			}
			else//成功
			{
				st.pop();//输出

			}
		}

		if (braket_st[i] == '[')
			st.push(braket_st[i]);//输入
		else if (braket_st[i] == ']')
		{
			if (st.empty())//栈为空
			{
				cout << "no";
				return false;
			}


			if (st.top() != '[')
			{

				cout << st.top() << endl;//取栈顶元素
				cout << "no";

			}
			else//成功
			{
				st.pop();

			}
		}

		if (braket_st[i] == '{')
			st.push(braket_st[i]);//输入
		else if (braket_st[i] == '}')
		{
			if (st.empty())//栈空
			{
				cout << "no";
				return false;
			}


			if (st.top() != '{')
			{

				cout << st.top() << endl;//取栈顶元素
				cout << "no";

			}
			else
			{
				st.pop();
			}
		}

	}

	if (st.empty() && braket_st[i] == '\0')//找到配对并且扫描完成后栈为空
	{
		cout << "yes";
		return true;
	}
	else if (!st.empty())//非空条件下.不配对
	{
		cout << st.top() << endl << "no";
		return false;
	}

}

1.3 队列


注:包括顺序队列和环形队列

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

定义:

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

初始化:

void InitQueue(SqQueue &q)
{	q=new Queue;
	q->front=q->rear=-1;
}

入队出队:

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;
}
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;
}

销毁

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

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

定义:

typedef struct 
{	
  ElemType data[MaxSize];
  int front,rear;	
} Queue;
typedef Queue *SqQueue;

初始化:

void InitQueue(SqQueue &q)
{   q=new Queue;
    q->front=q->rear=0;
}

出队入队:

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;
}
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;
}

注:循环队列长度=Q.rear-Q.front+MAXQSIZE)%MAXQSIZE

链队列的结构、操作函数

定义:

typedef struct QNode{
   QElemType   data;
   struct Qnode  *next;
}Qnode, *QueuePtr;//定义节点类型
typedef struct {
   QueuePtr  front;            //队头指针   
   QueuePtr  rear;             //队尾指针
}LinkQueue;  //定义队列类型

初始化:

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

入队出队:

Status EnQueue(LinkQueue& Q, QElemType e)
{
	p = (QueuePtr)malloc(sizeof(QNode));
	if (!p) exit(OVERFLOW);
	p->data = e; p->next = NULL;
	Q.rear->next = 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;
	if (Q.rear == p) Q.rear = Q.front;
	delete p;
	return OK;
}

队列应用,要有具体代码操作。
破解迷宫:
使用队列来求解,假设当前点位为(x, y),在队列中的索引为front,遍历该位置的四个方位,如果方位可走则入队,并记录这个方位元素的前驱为front。如下图所示,当前点位上方的点位不可走,不入队;右方可走,入队;下方可走入队;左方可走入队;然后将front++,这时候当前点位变成(x, y+1),继续遍历它的四个方位,淘汰掉不可走的,可走的方位都会入队…。这样一层一层向外扩展可走的点,所有可走的点位各个方向都会尝试,而且机会相等,直到找到出口为止,这个方法称为“广度优先搜索方法”。然后我们从出口反向找其上一个方块的下标,直到下标为0,这个反向过程就能找到最短路径。

public static QueueByArray<MazeElem> getMazePathByArrayQueue(int[][] maze, int startX,
                                                                 int startY, int endX, int endY){
        int x, y, di;

        QueueByArray<MazeElem> queue = new QueueByArray();
        //入口元素进队
        MazeElem elem = new MazeElem(startX, startY, 0,-1);
        queue.enQueue(elem);
        maze[startX][startY] = -1;  //将入口元素置为-1,避免回过来重复搜索

        int front = 0;  //记录当前操作的可走方块在队列中的索引
        //队列不为空且未找到路径时循环
        while(front<=queue.getRear()){
            x = queue.getElement(front).x;
            y = queue.getElement(front).y;
            if(x == endX && y == endY){  //找到了出口
                int k = front, j;
                //反向找到最短路径,将该路径上的方块的pre设置为-1
                do{
                    j = k;
                    k = queue.getElement(k).pre;   //上一个可走方块索引
                    queue.getElement(j).pre = -1;  //将路径上的元素的pre值为-1
                }while(k!=0);
                //返回队列,队列中pre为-1的元素,构成最短路径
                return queue;
            }
            for(di = 0; di<4; di++){   //循环扫描每个方位,把每个可走的方块插入队列中
                switch (di){
                    case 0:     //上
                        x = queue.getElement(front).x-1;
                        y = queue.getElement(front).y;
                        break;
                    case 1:     //右
                        x = queue.getElement(front).x;
                        y = queue.getElement(front).y+1;
                        break;
                    case 2:     //下
                        x = queue.getElement(front).x+1;
                        y = queue.getElement(front).y;
                        break;
                    case 3:     //左
                        x = queue.getElement(front).x;
                        y = queue.getElement(front).y-1;
                        break;
                }
                if(x>=0 && y>=0 && x<maze.length && y<maze[0].length){
                    if(maze[x][y] == 0){
                        //将该相邻方块插入队列
                        queue.enQueue(new MazeElem(x, y, 0, front));
                        maze[x][y] = -1;   //赋值为-1,避免回过来重复搜索
                    }
                }
            }
            front ++;
        }
        return null;
    }

2.PTA实验作业(4分)

此处请放置下面2题代码所在码云地址(markdown插入代码所在的链接)。如何上传VS代码到码云

2.1 符号配对

7-2 jmu-ds-符号配对

2.1.1 解题思路及伪代码

遍历输入数据,取符号置于全新的数组中,然后依次入栈并加以判断

2.1.2 总结解题所用的知识点

1.数组的应用
2.栈的应用

2.2 银行业务队列简单模拟

7-6 银行业务队列简单模拟 (25 分)

2.2.1 解题思路及伪代码

用A,B两个队列分别存储顾客编号。A存储顾客编号为奇数的,则B存储顾客号为偶数。当A窗口没有解决完2个顾客的时且A队列不空,则A出队;当A解决完2人且B队列不空,则B出队

2.2.2 总结解题所用的知识点

1.采用queue库函数更加便捷,获取队首元素
2.需要借用flag来判断空格的输入输出
3.当A或B两个有一个队列为空就退出循环,然后单独输出不为空的队列

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

从键盘上输入一个逆波兰表达式,用伪码写出其求值程序。规定:逆波兰表达式的长度不超过一行,以$符作为输入结束,操作数之间用空格分隔,操作符只可能有+、-、、/四种运算。例如:234 34+2$
答:[题目分析]逆波兰表达式(即后缀表达式)求值规则如下:设立运算数栈OPND,对表达式从左到右扫描(读入),当表达式中扫描到数时,压入OPND栈。当扫描到运算符时,从OPND退出两个数,进行相应运算,结果再压入OPND栈。这个过程一直进行到读出表达式结束符$,这时OPND栈中只有一个数,就是结果。

     float expr( )
     //从键盘输入逆波兰表达式,以‘$’表示输入结束,本算法求逆波兰式表达式的值。
     {float OPND[30]; // OPND是操作数栈。
      init(OPND); //两栈初始化。
     float num=0.0; //数字初始化。
     scanf (“%c”,&x);//x是字符型变量。
     while(x!=’$’)
     {switch
          {case‘0’<=x<=’9’:while((x>=’0’&&x<=’9’)||x==’.’) //拼数
               if(x!=’.’) //处理整数
     {num=num*10+(ord(x)-ord(‘0’)); scanf(“%c”,&x);}
               else //处理小数部分。
               {scale=10.0; scanf(“%c”,&x);
               while(x>=’0’&&x<=’9’)
               {num=num+(ord(x)-ord(‘0’)/scale;
               scale=scale*10; scanf(“%c”,&x); }
               }//else
               push(OPND,num); num=0.0;//数压入栈,下个数初始化
     case x=‘ ’:break; //遇空格,继续读下一个字符。
     case x=‘+’:push(OPND,pop(OPND)+pop(OPND));break;
     case x=‘-’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2-x1);break;
     case x=‘*’:push(OPND,pop(OPND)*pop(OPND));break;
     case x=‘/’:x1=pop(OPND);x2=pop(OPND);push(OPND,x2/x1);break;
     default: //其它符号不作处理。
     }//结束switch
     scanf(“%c”,&x);//读入表达式中下一个字符。
     }//结束while(x!=‘$’)
     printf(“后缀表达式的值为%f”,pop(OPND));
     }//算法结束。
posted @ 2021-04-05 22:45  年少不知头发贵  阅读(135)  评论(1编辑  收藏  举报