栈和队列习题

目录

、两个栈实现一个队列

、两个队列实现一个栈


一、两个栈实现一个队列

       分析:栈是后进先出的,队列是先进先出的。如果要用两个栈实现一个队列,主要的两个接口就是实现入队和出队,所以我们使两个栈始终保持一个为入队栈,一个为出队栈,具体在下面分析。

       1、定义

typedef struct QueueByTwoStack
{
    Stack s1;  //入队栈
    Stack s2;  //出队栈
}QueueByTwoStack;

       2、入队 /出队

       分析

               (1)入队:定义为 s1 为入队栈,则入队时,不用管两个栈是不是为空,直接入栈到s1。

               (2)出队:出队就需要借助第二个栈了,从一开始,我们入栈的所有数据都在 s1 中,如果要实现队列的出队,就必须把 s1 中的数据倒到 s2 中,当所有数据倒过去的时候,我们会发现,s2的栈底是 s1 的栈顶,s2的栈顶是 s1 的栈底,所以实现出队,就是把 s2 的栈顶出栈,所以方法是:如果s2非空,直接出s2栈顶元素就好;如果s2为空,我们可以控制 s1 中元素的个数来达到出队,出队后,s2中剩余数据等待下一次出队即可。

void QueueByTwoStackPush(QueueByTwoStack* qts, DataType d)
{
	assert(qts);

	StackPush(&(qts->s1), d);
}

void QueueByTwoStackPop(QueueByTwoStack* qts)
{
	assert(qts);

	//1、如果s2有数据,则直接出
	//2、如果s2没有数据,则将s1的数据倒过来,再出
	if (StackEmpty(&(qts->s2)) == 0)
	{
		while (StackEmpty(&(qts->s1)))
		{
			StackPush(&(qts->s2), StackTop(&(qts->s1)));
			StackPop(&(qts->s1));
		}
	}
	StackPop(&(qts->s2));
}

       3、其余接口 

void QueueByTwoStackInit(QueueByTwoStack* qts)
{
	StackInit(&(qts->s1));
	StackInit(&(qts->s2));
}

void QueueByTwoStackDestory(QueueByTwoStack* qts)
{
	StackDestory(&(qts->s1));
	StackDestory(&(qts->s2));
}

DataType QueueByTwoStackFront(QueueByTwoStack* qts)
{
        //S2是出队栈,s1为入队栈
        //1、如果s2不为空,队头就相当于s2的栈顶
        //2、如果s2为空,说明出队栈没有数据,此时队头在s1的栈底,为了得到栈底元素
        //只需将s1倒到s2中,此时队头就是s2的栈顶
	if (StackEmpty(&(qts->s2)) == 0)
	{
		while (StackEmpty(&(qts->s1)))
		{
			StackPush(&(qts->s2), StackTop(&(qts->s1)));
			StackPop(&(qts->s1));
		}
	}
	return StackTop(&(qts->s2));
}

int QueueByTwoStackSize(QueueByTwoStack* qts)
{
	return StackSize(&(qts->s1)) + StackSize(&(qts->s2));
}

int QueueByTwoStackEmpty(QueueByTwoStack* qts)
{
	return StackEmpty(&(qts->s1)) | StackEmpty(&(qts->s2));
}

void TestQueueByTwoStack()
{
	QueueByTwoStack qts;
	QueueByTwoStackInit(&qts);

	QueueByTwoStackPush(&qts, 1);
	QueueByTwoStackPush(&qts, 2);
	QueueByTwoStackPush(&qts, 3);
	QueueByTwoStackPush(&qts, 4);
	QueueByTwoStackPush(&qts, 5);

	while (QueueByTwoStackEmpty(&qts))
	{
		printf("%d ", QueueByTwoStackFront(&qts));
		QueueByTwoStackPop(&qts);
	}
	printf("\n");

	QueueByTwoStackDestory(&qts);
}

2、两个队列实现一个栈

        分析:通过第一题,第二题就容易思考了,两个队列,我们需要做的就是始终保持其中一个为空。

1、定义

typedef struct StackByTwoQueue
{
    Queue q1;
    Queue q2;
}StackByTwoQueue;

2、入栈/出栈 

     分析

             (1)、入栈:入栈是每次向非空的队列中入数据。原因在于这是一个队列,我们只需要让数据入出的顺序保持一致就好,始终保持一个空队列是为了出栈做准备。

             (2)、出栈:上面已经说了空队列是为了出栈做准备。原因在于,这是两个队列,无论我们怎么像第一题一样那样倒来倒去,我们所得到的结果都是一样的,队中存放的东西没有改变,只是换了一个队列存放罢了。但是,在倒的过程中,我们发现,非空队列中剩余一个数据的时候,这个数据就是我们想要出栈的数据,因此可以控制非空队列中的数据个数来找到我们想要出栈的数据。因此在出栈中定义两个队列,一个记录空队列,一个记录非空队列

void StackByTwoQueuePush(StackByTwoQueue* stq, DataType d)
{
	assert(stq);

        //1、如果q1非空,就向q1入数据
        //2、如果q1为空,则向q2入数据
	if (QueueEmpty(&(stq->q1)) != 0)
	{
		QueuePush(&(stq->q1), d);
	}
	else
	{
		QueuePush(&(stq->q2), d); 
	}
}

void StackByTwoQueuePop(StackByTwoQueue* stq)
{
	Queue* empty = NULL;  
	Queue* nonempty = NULL; 

	assert(stq);

	empty = &(stq->q1);     //指向空队列
	nonempty = &(stq->q2);      //指向非空队列
        //1、如果q1不是空队列,说明记录错误,需要交换一下指向队列
	if (QueueEmpty(&(stq->q1)) != 0)
	{
		empty = &(stq->q2);
		nonempty = &(stq->q1);
	}
        //2、向空队列倒数据,直到非空队列中元素只有一个
        //   即找到要出的数据
	while (QueueSize(nonempty) > 1)
	{
		QueuePush(empty, QueueFront(nonempty));
		QueuePop(nonempty);
	}
        //3、出数据
	QueuePop(nonempty);
}

3、其他接口 

void StackByTwoQueueInit(StackByTwoQueue* stq)
{
	QueueInit(&(stq->q1));
	QueueInit(&(stq->q2));
}

void StackByTwoQueueDestory(StackByTwoQueue* stq)
{
	QueueDestory(&(stq->q1));
	QueueDestory(&(stq->q2));
}

DataType StackByTwoQueueTop(StackByTwoQueue* stq)
{
        //栈顶元素即队尾元素,只需找到非空队列
        //返回非空队列的队尾元素
	if (QueueEmpty(&(stq->q1)))
	{
		return QueueBack(&(stq->q1));
	}
	else
	{
		return QueueBack(&(stq->q2));
	}
}

int StackByTwoQueueSize(StackByTwoQueue* stq)
{
	return QueueSize(&(stq->q1)) + QueueSize(&(stq->q2));
}

int StackByTwoQueueEmpty(StackByTwoQueue* stq)
{
	return QueueEmpty(&(stq->q1)) | QueueEmpty(&(stq->q2));
}

void TestStackByTwoQueue()
{
	StackByTwoQueue stq;
	StackByTwoQueueInit(&stq);

	StackByTwoQueuePush(&stq, 1);
	StackByTwoQueuePush(&stq, 2);
	StackByTwoQueuePush(&stq, 3);
	StackByTwoQueuePush(&stq, 4);
	StackByTwoQueuePush(&stq, 5);

	while (StackByTwoQueueEmpty(&stq))
	{
		printf("%d ", StackByTwoQueueTop(&stq));
		StackByTwoQueuePop(&stq);
	}
	printf("\n");

	StackByTwoQueueDestory(&stq);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值