栈和队列

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

0.PTA得分截图

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

1.1 栈

栈的定义以及特点

  • 栈是一种只能在一端进行插入和删除操作的线性表,表中允许进行插入和删除的一端为栈顶,另一端为栈底。
  • 当栈中没有数据元素时称为空栈。
  • 栈的插入操作称为入栈或者进栈,栈的删除操作称为出栈或者退栈。
  • 栈的主要特点为后进先出,每次出栈的元素都为当前栈的栈顶元素。

顺序栈的结构

  • 栈的代码定义
typedef struct {
	ElemType data[MaxSize];//存放元素
	int top=-1;//栈顶指针,下标
}SqStack;//顺序栈的类型

栈的存储和删除通过top的移动进行元素的进入和删除,对栈的元素进行删除实际上元素仍然在栈里面,仅是移动指针的位置。

顺序栈操作函数

  • 栈空栈满的判断条件(进行插入删除时需要注意的条件)
    若初始时s->top定义为-1,则栈空的条件为s->top=-1,栈满的条件为s->top=MaxSize-1(MaxSize为数组最大下标)。
  • 初始化栈
void InitStack(S)
{
   s=new Stack;//动态申请内存
   s->top=-1;
}
  • 进栈
bool Push(SqStack &S,ElemType e)
{
    if(s->top==MaxSize-1)//顺序栈进栈时要注意栈是否已满
    {
        return false;
    }
    s->top++;//栈顶指针加1
    s->data[s->top]=e; 
    return true;
}

进行是否栈满的判断,栈顶指针加一,放入元素

  • 出栈
bool Pop(SqStack &s,ElemType &e)
{
    if(s->top==-1)//顺序栈出栈时要注意栈是否为空
    {
       return flase
    }
    e=s->data[s->top];
    s->top--;//栈顶指针减一
    return ture;
}

进行是否栈空的判断,栈顶指针减一,移除元素

  • 取栈顶元素
bool GetTop(SqStack *s,ElemType &e)
{
   if(s->top==-1)//判断是否为空
   return false;
   e=s->data[s->top];
   return true;
}

进行是否栈空的判断,取栈顶指针位置,输出元素

链栈的结构

  • 栈的代码定义
typedef struct linknode
{
   ElemType data;//数据域
   struct linknode *next;//指针域
}LinkStNode;//类型

通过对指针的结点移动进行数据的插入和输出。

链栈的操作函数

  • 栈空栈满的判断条件(区别于顺序栈)
    栈空的判断条件为s->next=NULL,一般不用判断栈满,只有内存溢出时才栈满。
  • 初始化栈
void InitStack(LiStack &s)
{
   s=new LiNode;//动态申请内存
   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->enxt=p->next;//改变结点指向
   delete p;//删除
   return true;
}

出栈时需要对栈空进行判断,后利用链表删除某一结点的数据方法,新建临时结点保存需要删除的结点,后改变前继结点的指向,物理删除需要删除的结点。

c++模板类:stack

  • stack <元素类型> s:初始化栈
  • s.push(t):将元素t入栈
  • s.pop():出栈顶元素
  • s.top():返回栈顶元素
  • s.empty():当栈为空时返回true
  • s.size():访问栈的元素个数

1.2 栈的应用

表达式

  • 中缀表达式:运算符号位于两个运算数之间。后缀表达式:运算符号位于两个运算数之后。
  • 中缀表达式转为后缀表达式:
    建立一个栈用于存放运算符,每个运算符号进栈时都要比较一下其和栈顶的的符号优先级大小,若优先级较低,则栈里面的运算符需要出来,其进栈,当操作结束后,需要观察栈里面是否还有运算符,若有则需要将其出栈,若遇到括号,由于括号的优先级最高,当符号配对成功时,需要出栈的元素。
    例:

(1)将中缀表达式a+b * c+(d * e+f) * g转为后缀表达式,当读入f时栈里面的内容为+(+
解析:+进栈, * 进栈,+优先级较低,故出* 和 +,+进栈,(进栈, * 进栈,+优先级较低,故*出栈,+进栈,此时栈里面剩余+(+。

(2)将表达式a * (b+c)-d转为后缀表达式abc+ * d-。
解析: * 进栈,(进栈,+进栈,)进栈,配对成功,+出栈, * 出栈,-进栈,完成操作后,-还在栈里,-出栈。

1.3 队列

队列的定义以及特点

  • 队列是一种操作受限的线性表,仅允许在表的一端进行插入操作,在表的另一端进行删除操作。
  • 把进行删除的一端称为队头或队首,进行插入的一端称为队尾。
  • 插入新元素,新元素进队后为新的队尾元素,元素出队后,其后继的元素称为队头元素。
  • 队的特点为先进先出

顺序队列的结构

  • 队列的代码定义
typedef struct
{
   ElemType data[MaxSize];
   int front,rear;//队首,队尾指针
}Queue;

通过队首队尾指针的移动进行元素的插入和删除,front指向队头元素,rear指向队尾元素。

顺序队列的操作函数

  • 队列空满的判断条件(进行插入删除时需要注意的条件)
    初始定义front和rear为-1,对空的条件为front=rear,队满的条件为rear=MaxSize。
  • 初始化队列
void InitQueue(Queue &q)
{
   q=new Queue;//动态申请内存
   q->front=q->rear=-1;
}
  • 进队列
bool enQueue(SqQueue &q,ElemType e)
{
    if(q->rear+1==MaxSize)//判断是否栈满
    return flase;
    q->rear=q->rear+1;//移动指针
    q->data[q->rear]=e;
    return ture;
}

跟顺序栈的进栈一样,顺序队列的进队需要判断rear的下一位是否已满,若未满即可移动指针插入元素。

  • 出队列
bool deQueue(SqQueue &q,Elemtype &e)
{
   if(q->front==q->rear)//判断队是否为空
   return flase;
   e=q->data[q->front];
   q->front=q->front+1;//移动指针
   return ture;
}

顺序队列得到进队需要判断队列是否为空,后移动front到下一位,进行出队操作。

环形队列的结构
由于顺序队列的队满条件为rear=MaxSize-1,当满足这一条件时,即跳出操作,但此时可能仍有若干空位置,这种情况为假溢出。
为更好利用存储空间,可构建一个环形队列。

  • 队列的代码定义
   typedef struct
{
   ElemType data[MaxSize];
   int front,rear;//队首,队尾指针
}Queue;

环形队列的操作函数

  • 队头指针front循环增1:front=(front+1)%MaxSize,队尾指针rear循环增1:rear=(rear+1)%MaxSize
  • 队满的判定条件:(q->rear+1)%MaxSize=q->front,队空的判定条件:q->front=q->rear。
  • 初始化队列
void InitQueue(SqQueue &q)
{
   q=new Queue;//动态申请内存
   q->front=q->rear=0;
}

通过分别移动front和rear进行进队列和出队列操作。

  • 进环形队列
bool enQueue(SqQueue &q,Elemtype e)
{
   if((q->rear+1)%MaxSize==q->front)//判断是否队满
   return false;
   q->rear=(q->rear+1)%MaxSize;//移动rear
   q->data[q->rear]=e;
   return true;
}

进队列需要判断是否队满,判断(q->rear+1)%MaxSize是否等于q->front,后移动rear指针,q->rear=(q->rear+1)%MaxSize。

  • 出环形队列
bool deQueue(SqQueue &q,Elemtype e)
{
   if(q->front==q->rear)//判断是否队空
   return false
   e=q->data[q->front];
   q->front=(q->front+1)%MaxSize;//移动front
   return true;
}
出队需要判断是否对空,判断q->front==q->rea,后移动front指针q->front=(q->front+1)%MaxSize。

链队列的结构

  • 队列的代码定义
typedef struct
{
   QNode *front;
   QNode *rear;
}LinkQueue;

通过移动front和rear实现进栈和出栈

链队列的操作函数

  • 队空的判断条件为front=rear=NULL,一般不用考虑队满
  • 初始化链队列
void InitQueue(LinkQuNode &q)
{
   q=new LinkQuNode;
   q->front=q->rear=NULL;
}
  • 进队列
bool enQueue(LinkQuNode &q,ElemType e)
{
   p=new QNode;
   p->data=e;//新建结点
   p->next=NULL;//避免后面无结束
   q->rear->next=p;
   q->rear=p;//尾指针移动
}

进队列不需要判断队满,利用尾插法插入,并且改变rear的指向。

  • 出队列
bool deQueue(LinkQuNode &q,ElemType e)
{
    Node t;
    if(q->rear==NULL)
    return false;
    t=q->front;
    if(q->front==q->rear)//此时只有一个数据
    {
       q->front=q->rear=NULL;
    }
    else
    {
       q->front=q->front->next;//移动front
    }
    e=t->data;
    delete t;//删除
}

出队列判断是否为空,并考虑是否只有一个数据,移动front。

队列应用
例题:

#include <iostream>
#include <queue>
using namespace std;
int main()
{
	int m;//人数
	int n;//数字
	queue <int>person;
	cin >> m >> n;
	if (n > m)//特殊情况
	{
		printf("error!");
	}
	else
	{
		int i ;
		for (i = 1; i <= m; i++)//进入队列
		{
			person.push(i);
		}
		int flag = 1;//控制空格
		int num;
		 i = 0;
		while (!person.empty())
		{
			i++;
			if (i%n == 0)
			{
				num = person.front();
				if (flag == 1)
				{
					flag = 0;
					cout << num;
				}
				else
				{
					cout << ' ' << num;
				}
				person.pop();//出队列
				i = 0;//重新计数
			}
			else
			{
				num = person.front();
				person.push(num);//进队列
				person.pop();//出队列
			}
		}
	}
	return 0;
}

对于此类的报数问题还有搜索迷宫路径问题,可用队列解决,题中不满足报数条件的单位需要进行出队再入队的操作,具体的要求根据题意改变。

c++模板类:queue

  • q.push():入队
  • q.pop():出队
  • q.front():取队头元素
  • q.back():取队尾元素
  • q.empty():队是否为空

2.PTA实验作业(4分)

7-2 符号配对地址
7-6 银行业务队列简单模拟地址

7-2 符号配对

解题思路及伪代码

解题思路:定义flag进行判断操作,输入左符号时入栈,输入右符号时并且判断栈里面是否有元素,若无则为一种情况,若有则进行配对,判断是否是该右符号对应的左符号,用flag标记对应的情况。
伪代码:

int flag=0;
for (遍历条件)
{
	if (为左符号)
	{
		入栈;
	}
	else if (栈为空且有右符号)
	{
		flag = 1;
		break;
	}
	else if (各自左符号与右符号配对情况)
	{
		出栈;
	}
}
if (flag == 1)
{
	右符号剩余;
}
else if (栈为空)
{
	匹配;
}
else
{
	正常情况的不匹配;
}

总结解题所用的知识点

stack相关函数的应用、flag标记情况、情况不同的判断考虑,本题需要考虑到左符号剩余,右符号剩余,配对情况,不配对情况,需要多重if 来进行约束判断,最后根据flag的值输出对应的结果。

7-6银行业务队列简单模拟

解题思路及伪代码

解题思路:
先判断编号的奇偶,若为奇数进A队列,若为偶数进B队列,再分别计算A队列和B队列的元素个数,后判断A无元素和只有1个元素的特殊情况,两种情况下再判断B的个数,之后普通情况,另A的元素个数除以2,因为2人为一组,1组输出2个编号后B输出1个编号,但要考虑到A的元素个数为奇数个,故要添加判断,若其为奇数最后一组输出1个。
伪代码:

for (遍历条件)
{
	if (编号为奇数)
	{
		进A;
	}
	else
	{
		进B;
	}	
}
统计A和B的个数
if (A个数为0)
{
	全部输出B元素;
}
else if (A元素个数为1)
{
	输出A;
	全部输出B;
}
else
{
	int i = A个数 / 2;
	for (n = 1; n <= i; n++)
	{
		if (n < i)
		{
			输出A2个元素;
		}
		else if (n == i && A个数为奇数)
		{
			输出A1个元元素;
		}
		else if (n == i && A个数为偶数)
		{
			输出A2个元素;
		}
		if (B还有元素)
		{
			输出B1个元素;
		}
	}
}

总结解题所用的知识点

queue相关函数的使用、队列优先输出的顺序、本题需要考虑A对列的特殊情况,考虑其个数以及奇偶性。

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

3.1 题目及解题代码

代码:

 bool validateStackSequences(vector<int>& pushed, vector<int>& popped) 
{
        stack<int> story;
        int j=0;//popped的index
        for(int i=0;i<pushed.size();++i)
        {
            story.push(pushed[i]);
            while(!story.empty()&&story.top()==popped[j])//出与入相同时执行pop
            {
                story.pop();
                j++;
            }
        }
        
        while(!story.empty()&&j<popped.size())
        {
            if(story.top()==popped[j])//为pop首元素时执行pop
            {
                story.pop();
                j++;
            }
            else
            {
                return false;
            }
        }
        return true;
        
    }

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

伪代码:

for(遍历条件)
{
    push入新栈;
    while(栈顶与pop的top一样时)
    {
       执行pop;
    }
}
while(新栈不为空)
{
    if(栈顶与pop的top一样)
    {
       执行pop;
    }
    else
    {
       错误;
    }
}

相当于对新栈要遍历一遍故时间复杂度为O(n),空间复杂度为O(n)

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

优势:执行思路清晰,明确找到需要判断的点,构建新栈与pop进行一 一比较。
难点:需要想到构建新栈导入push,利用栈的特性,一 一与pop进行逆序匹对。

posted @ 2021-04-05 21:30  稶郗  阅读(201)  评论(0编辑  收藏  举报