栈和队列的相互实现

用队列实现栈

要求:仅使用两个队列去实现一个栈,并支持栈中的Push、Pop、Top、Empty四种操作


前言:我们知道栈和队列都是一种特殊的线性表,不同点在于栈只允许在一段进行插入和删除,遵循先进后出的原则;而队列允许在一端进行插入,在另一端进行删除,遵循先进先出的原则。

那么用队列去实现栈,无非就是用两个队列去实现一个先进后出的数据结构。


那么如何去实现这样的结构呢?

两个队列它肯定是有关系的,自然很容易就想到一个队列里面的数据进入到另一个队列当中

如图,假设一组数据3,4,5进入栈中,出栈必定是5,4,3的顺序,第一个出栈的元素是5。那么借用两个队列实现这种效果,最后呈现的结果也一定是5,4,3。

初始情况下,两个队列都为空,先让这组数据先进入到其中一个队列q1中,再让它们依次导入到另一个队列q2中。

按照队列的原则,依次导入的顺序为3,4,5.当我们只剩下最后一个数据5时,可以发现,此时如果将5直接出队列,而不去入q2,那么刚好符合栈的特性,先进先出,第一个出栈的元素是5。

由此可知,有n个数据在队列中,依次将前n-1个数据导入到另一个空队列,剩下最后一个数据直接出队列。再将n-1个数据按照此方法出最后一个数据,即可实现栈


具体实现: 

已知是用队列的基本操作去实现栈的基本操作,所以在实现新栈之前,队列基本操作的相关代码要先写上(以下省略队列基本操作的代码,直接展示新栈的代码)

//入新栈
void mystackPush(Mystack* obj, int x)
{
	//往空队列中插入数据
	if (!QueueEmpty(&obj->q1))
	{
		QueuePush(&obj->q1, x);
	}
	else
	{
		QueuePush(&obj->q2, x);
	}
}

//出新栈
int mystackPop(Mystack* obj)
{
	//把已有数据的队列前size-1个元素,导入到空队列中
	//先找出空队列
	Queue* empQ = &obj->q1;//先假设q1是空队列
	Queue* noneQ = &obj->q2;
	if (!QueueEmpty(&obj->q1))//假设错误在调换
	{
		noneQ = &obj->q1;
		empQ = &obj->q2;
	}
	//开始导入
	while (QueueSize(noneQ) > 1)
	{
		int front = QueueFront(noneQ);
		QueuePush(empQ, front);
		QueuePop(noneQ);
	}
	//非空队列只剩下最后一个元素,即是要出栈的元素
	int pop = QueueFront(noneQ);
	QueuePop(noneQ);
	return pop;
}

注意!!用两个队列实现一个栈操作的核心点就是,至少要有一个队列为空(这样才能保证可以倒导数据) 

先创建两个变量empQ和noneQ,方便后面能够直接分清哪个队列为空哪个队列非空

//取新栈的栈顶元素
int mystackTop(Mystack* obj)
{
	if (!QueueEmpty(&obj->q1))
	{
		return QueueBack(&obj->q1);
	}
	else
	{
		return QueueBack(&obj->q2);
	}
}

 取新栈的栈顶元素这里是一个易错误区,看到前面出新栈的操作,不难认为出新栈的思路也可以用在此处,只是省略了出栈的这一步

但是!!就是因为必须省略出栈这一步所以该思路不可以采用

因为我们必须要保证至少有一个队列是空的,若采用该错误思路后,会发现,两个队列均非空,故不可行

//判空
bool mystackEmpty(Mystack* obj)
{
	return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
}

思路总结:

必须保证至少有一个队列为空

出新栈:找不为空的队列,将size-1个数据导入到另一个空队列当中

入新栈:往不为空的队列中插入数据

取新栈顶元素:找不为空的队列取队尾元素

用栈实现队列

要求:仅使用两个栈去实现一个队列,并支持队列中的Push、Pop、Top、Empty四种操作


前言:同理,用栈去实现队列,无非就是用两个栈去实现一个先进先出的数据结构。


那么如何去实现这样的结构呢?

同上面的方法一致,也是利用数据从一个栈到另一个栈中实现队列的效果。

如图,假设一组数据6,7,8,9的顺序入队,出队的顺序必定是6,7,8,9。第一个出队的元素是6,借用个栈实现这种效果,最后呈现的结果也一定是6,7,8,9。

定义一个栈push专门实现入新队,另一个栈pop专门实现出新队(与新栈不同的是,因为提前定义了谁入谁出,就不需要去找空和非空)

由图易知,将push栈中的数据导入pop栈中,再由pop栈出,即可实现队列的特性

当出新队时,判断pop是否为空,若为空,直接将push里面的数据导入;若非空,就先出pop里面的数据


具体实现:

已知是用栈的基本操作去实现队列的基本操作,所以在实现新队列之前,栈基本操作的相关代码要先写上(以下省略栈基本操作的代码,直接展示新队的代码)

//入新队
void myqueuePush(Myqueue* obj, int x)
{
	StackPush(&obj->pushST, x);
}
//出新队
int myqueuePop(Myqueue* obj)
{
	//看popST是否为空,非空就先pop;为空就先将pushST的数据导入popST,再pop
	if (StackEmpty(&obj->popST))
	{
		while (!StackEmpty(&obj->pushST))//导数据
		{
			StackPush(&obj->popST, StackTop(&obj->pushST));
			StackPop(&obj->pushST);
		}
	}
	//非空
	int top = StackTop(&obj->popST);
	StackPop(&obj->popST);
	return top;
}
//取新队的队头元素
int myqueueTop(Myqueue* obj)
{
	if (StackEmpty(&obj->popST))
	{
		while (!StackEmpty(&obj->pushST))
		{
			StackPush(&obj->popST, StackTop(&obj->pushST));
			StackPop(&obj->pushST);
		}
	}
	return StackTop(&obj->popST);
}
//判空
bool myqueueEmpty(Myqueue* obj)
{
	return StackEmpty(&obj->pushST) && (StackEmpty(&obj->popST));
}

思路总结:

入新队:往pushST中插入数据

出新队:判断popST是否为空,不为空直接pop;为空就将pushST中的数据导入popST中

取新队的队头元素:跟出队一样,但是只取,不出

. - 力扣(LeetCode)

. - 力扣(LeetCode)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值