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

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

1.1 栈

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

  • 顺序栈的结构、操作函数
struct struct{
    ElemType Data[MaxSize];  /* 存储元素的数组 */
    int top = -1;        /* 栈顶   */
}Stack,SqStack*;

入栈

bool Push(Sqstack &S,ElemType e)
{
if (top +1 == MaxSize)
  return ERROR;
S.Data[++S.top] = e;
  return OK;
}

出栈

ElemType Pop(Sqstack &S)
{
if (S.top ==-1)
  return ERROR;
return S.Data[S.top--] 
  • 链栈的结构、操作函数
typedef struct
{
	ElemType* Data;
	struct LinkStack *next;
}Stack,SqStack*;

入栈

bool Push(SqStack *head,ElemType e)
{
	 struct LinkStack *p;
	 p=(struct LinkStack*)malloc(sizeof(struct SqStack));
	 if(!p)
         {	   
          cout<<"分配内存失败";
          return ERROR;
         }
	 p->data=e;
	 p->next=head->next;
	 head->next=p;
	 return OK;
 }

出栈操作

Status Pop(LinkStack *head,ElemType *e){  //出栈操作
	 SqStack *p=head->next;
         if(!p)
         {
          cout<<"空栈!"
          return ERROR;
         }
	 head->next=p->next;
	 *e=p->data;
	 free(p);
	 return OK;
	 }

1.2 栈的应用

表达式

我们一般看到和使用的表达式是中缀表达式 比如 B*C 我们很容易知道是B乘以C
这种操作符在操作数中间的表示法就是 中缀表示法
为了消除混淆就引入了操作符 “优先级”的概念来消除混淆
高优先级的操作符先计算
相同优先级的操作符从左到右依次计算
移动操作符的位置
将操作符移到前面,比如 A+B 变成+AB
或者将操作符移动到最后,AB+
这其实就是表达式的另外两种表示方法:前缀和后缀表示法

1.3 队列

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

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

typedef struct {
    ElemType data[MAXQSIZE]; 
    int front; //头指针
    int rear; //尾指针
} Queue,SqQueue *;

入队

bool EnQueue(SqQueue &Q, ElemType e);
{
if (Q->rear - Q->front == MAXQSIZE)
        return false;
    Q->rear = (Q->rear + 1) % MAXQSIZE;
    Q->data[Q->rear] = e;
    return OK;
}

出队列

bool DeQueue(SqQueue& Q, ElemType& e)//出队列 
{
    if (Q->front==Q->rear)
        return ERROR;
    Q->front = Q->front + 1;
    e = Q->data[Q->front];
    return OK;
}

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

typedef struct {
    ElemType data[MAXQSIZE]; 
    int front; //头指针
    int rear; //尾指针
} Queue,SqQueue *;

入队

bool EnQueue(SqQueue& Q, ElemType e)//加入队列 
{
    if ((Q->rear + 1) % MAXQSIZE == Q->front)
        return false;
    Q->rear = (Q->rear + 1) % MAXQSIZE;
    Q->data[Q->rear] = e;
    return OK;
}

出队

bool DeQueue(SqQueue& Q, ElemType& e)//出队列 
{
    if (Q->front == Q->rear)
        return ERROR;
    Q->front = (Q->front + 1) % MAXQSIZE;
    e = Q->data[Q->front];
    return OK;
}

链队列的结构、操作函数

typedef struct{
	ElemType data;//数据域
	struct SqQueue next;//指针域,指向下一个结点
}Qnode;
typedef struct{
	Qnode* front;//队头指针 相当于Qnode *front 
	Qnode* rear;//队尾指针	
}LinkQueue;

创建链队列

bool initQueue(LinkQueue* Q)
{
	Q->front  = (Qnode*)malloc(sizeof(Qnode));
	Q->rear = Q->front;//储存分配失败 
        if(!Q->front)return NO;
	Q->front->next = NULL;
	return OK;
}

入队

bool insertQueue(LinkQueue* Q,ElemType e)
{
	LinkQueue p;	
	p = (Qnode*)malloc(sizeof(Qnode));

	if(!p)	return ERROR;//	分配失败
	p->data = e;
	p->next = NULL;
	Q->rear->next = p;
	Q->rear = p;		
	return OK;
}

出队

bool DeQueue(LinkQueue* Q,ElemType &e)
{
       if(Q->front == Q->rear)
           return ERROR;
       
       QNode *p;
       p = Q->front->next;
       Q->front->next = p->next;
       if (Q->rear == p)
          Q->rear = Q->front;
       e = p->data;
       free(p)
       return OK;
}

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

实际生活中,队列的应用随处可见,比如排队买 XXX、医院的挂号系统等,采用的都是队列的结构。
拿排队买票来说,所有的人排成一队,先到者排的就靠前,后到者只能从队尾排队等待,队中的每个
人都必须等到自己前面的所有人全部买票成功并从队头出队后,才轮到自己买票。这就是队列结构。

迷宫问题

#include<iostream>
bool mgpathl(int xi, int yi ,int xe ,int ye) //搜家路径为(xi,yi)->(xe,ye)
{
	Box e;
    int i,j, di, il, jl;
    QuType* qu;//定义顺序队指针qu

    InitQueue(qu);//初始化队列qu

    e.i = xi; e.j = yi; e.pre = -1;
    enQueue(qu, e);//(xi, yi)进队
    mg[xi][yi] = -1;//将其赋值一1,以避免回过来重复搜索

	while (!QueueEmpty(qu))//队不空循环
	{
		deQueue(qu, e);//出 队方块e,由于不是环形队列,该出队元素仍在队列中
		i = e.i; j = e.j;
		if (i == xe && j == ye)//找到了出口输出路径
		{
			print(qu, qu->front); //调用print函数输出路径
			DestroyQueue(qu);//销毁队列
			return true;
		}
			//找到一条路径时返回真
		for (di = 0; di < 4; di++)
		{
			switch (di)
			{
			case 0:
				il = i - 1; jl = j : break:

			case 1:
				i1 = i; jl -= j + 1; break:

			case 2:
				i1 = i + 1; j1 = j;  break;

			case 3:
				il = i; j1 = j - 1: break :
			}

			if (mg[i1][j1]==0)
			{
				e.i = il:e.j = jl;
				e.pre = qu->front;//指向路径中上一个方块的下标

				enQueue(qu, e);//(i1.j1)方块进队

				mg[i1][j1] = --1;//将其赋值一1.以避免回过来重复热索

		
		}
			DestroyQueue(qu);

			//销毁队列

			return false;

			//未找到任何路径时返回假
	}
}

2.PTA实验作业(4分)

2.1 符号配对

符号配对链接

2.1.1 解题思路及伪代码

逐行获取字符串,然后遍历,得到需要的符号左符号跟右符号存入另一个数组
遍历存有符号的数组,然后开始判断,如果是左符号则压入栈,如果是右符号则判断是否与栈顶元素匹配
如果不相匹配则输出错误信息,结束循环。
在遍历完数组后,判断该栈是否还有元素,如果有则是未匹配完成,输出错误信息。

  • 伪代码
定义两个足够长的字符数组
定义一个用来保存错误信息的字符c

cin>>str
while(str&&str[0]!='.')没有读到尾时
  for 0 to str末尾
    if 为符号条件的符号
      存入数组
    else if 为/* */
      存入数组
    END IF
  cin>>str
END While
For 0 to s末尾
  if s[i]为左符号
    入栈
  else if 为右符号
    if 栈不空且栈顶的左符号跟该右符号相配对
      出栈
    else
      保存错误信息,结束循环
    END IF
END For
if 栈为空且无错误信息
  输出YES
else
  输出NO后对错误信息c相匹配,然后输出错误信息的正确的格式
END IF

2.1.2 总结解题所用的知识点

解题所用的是对栈的操作,利用入栈来存左符号,出栈来配对相近的右符号

2.2 银行业务队列简单模拟

银行业务队列简单模拟链接

2.2.1 解题思路及伪代码

利用排在窗口的两个队列,队列A跟队列B
当A,B都有人时,先出队A队列的两人,然后出队B队列的一人,知道其中一个队列完成出队
后续增加判断A队列为空,或者B队列为空的循环,出队余下一个还有人的队列的其他人

  • 伪代码
创建队列q1,q2
For 0 to n
  输入排队的人的序号
  if 为奇数
    入队队列q1
  else
    入队q2
  END IF
END For
int h1 = q1.size();
int h2 = q2.size();//两队的长度
while h1&&h2
  if 为第一次输出
    输出两个q1队列的人,并出队
  else 为第二次输出
    同上的if操作,不过为了控制格式,输出方式略有不同
  END if
  输出q2的一个人,并出队
  h1-=2,h2--
END While
while h1或h2为真//其中一个队列还有人
  输出剩下的人的序号
END While

2.2.2 总结解题所用的知识点

解题所用的是对队列的构建及其入队跟出队操作的运用。

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

3.1 题目及解题代码

#define N 5003

typedef struct {
    int stk1[N], stk2[N];
    int top1, top2;
} SortedStack;


SortedStack* sortedStackCreate() {
    return (SortedStack*)calloc(1, sizeof(SortedStack));
}

void sortedStackPush(SortedStack* obj, int val) {
    // 1.stk1 中 <val 的元素加入 stk2 暂存
    while (0 != obj->top1 && obj->stk1[obj->top1 - 1] < val) {
        obj->stk2[obj->top2++] = obj->stk1[--obj->top1];
    }
    obj->stk1[obj->top1++] = val;  // 入 val 元素
    // 2. 将 stk2 元素倾倒回 stk1
    while (0 != obj->top2) {
        obj->stk1[obj->top1++] = obj->stk2[--obj->top2];
    }
}

bool sortedStackIsEmpty(SortedStack* obj) {
    return obj->top1 == 0;
}

void sortedStackPop(SortedStack* obj) {
    if (!sortedStackIsEmpty(obj)) --obj->top1;  // 存在才删除
}

int sortedStackPeek(SortedStack* obj) {
    if (!sortedStackIsEmpty(obj)) return obj->stk1[obj->top1 - 1];
    return -1;
}

void sortedStackFree(SortedStack* obj) {
    free(obj); obj = NULL;
}

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

思路

利用两个栈,其中一个栈存放排序好的,另一个栈用来进行暂存的排序操作。
压入栈时,当栈顶小于要压入的元素时,将栈顶元素出栈到另一个栈,直至压入,然后再把另一个栈的元素倒回排序栈

复杂度分析:

时间复杂度:入栈为 O(n^2),因为平均入栈需要搬动 stk1 中元素共 2 * len(stk1) 次,出栈为 O(1)。
空间复杂度: O(n),使用两个栈模拟。

伪代码

While top1不为0时且插入元素大于栈顶元素时
  把栈顶元素出栈到另一个暂存栈
END While
While top2不为0时
  把栈顶元素压回排序栈
END while

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

该题目解题在压栈时就按顺序排列好,这样比较原地排序,时间复杂度上会低,且思路结构较为简单有效。
难点在于不利用传统的数组来解决问题,比较以前仅学过的冒泡法跟选择法,都不怎么适用。

 posted on 2021-04-05 22:35    阅读(55)  评论(1编辑  收藏  举报