栈和队列相关题目

题目一:实现一个栈,要求实现Push(出栈)、Pop(入栈)、Min(返回最小值)的时间复杂度为O(1)
本题目的GitHub地址

  • 本题目的实现思路比较简单,使用两个栈,一个栈是用来存储数字,就是普通的数据,在代码中这个栈为Stack

  • 结构体的设计:数字+出现次数,另一个栈便用来存储结构体,在代码中这个栈为NumStack,这个栈的栈顶永远存的是Stack栈中的最小值和最小值个数构成的结构体

  • 所以我们将要设计的这个栈命名为DoubleStack,提供入栈,出栈,返回最小值得接口和其它基本接口

  • 入栈:首先我们先考虑入栈,入栈的时候呢,对于Stack肯定是必须要入栈的,对于NumStack的话就需要考虑了,如果NumStack是空栈,那么肯定是第一次进入元素,所以两个栈都要存东西,而且对于第一次存入的应该将最小值对应的结构体设置为1

  • 如果NumStack 栈不为空的话,那么在压栈之前就需要比较大小,如果比NumStack 栈栈顶元素还小的话就需要将这个较小值压栈,如果相等的话就对栈顶元素的结构体的num+1即可!

  • 出栈:首先还是先要获取栈顶元素,因为不是每一次入Stack 栈的元素都能存入到NumStack 中,所以要出栈的元素和NumStack 的栈顶相等的话就将对应的结构体的count属性-1,要是count原本就是1,那么直接将此元素在NumSatck 中出栈即可!

  • 上一步只是判断NumStack 中的元素是否需要出栈,但是将Stack 中的元素出栈是必要的,所以最后将Stack 中的元素弹栈!

GIF演示过程——入栈
这里写图片描述
GIF演示过程——出栈
这里写图片描述

void DoubleStackPush(DoubleStack* ds, IDataType x)
{
	SDataType s;
	SDataType ret;
	assert(ds);

	//如果结构体栈为空
	if(NStackEmpty(&ds->nst) == 0)
	{
		s.count = 1;
		s.num = x;
		StackPush(&ds->st,x);
		NStackPush(&ds->nst, s);
	}
	else
	{	
		StackPush(&ds->st, x);
		//如果入栈的元素小于最小值记录栈的栈顶
		if(x < NStackTop(&ds->nst).num)
		{
			s.num = x;
			s.count = 1;
			//将此元素的对应结构体入栈
			NStackPush(&ds->nst, s);
		}
		else if (x == NStackTop(&ds->nst).num) 
		{
			//相等的情况
			ret = NStackTop(&ds->nst);
			NStackPop(&ds->nst);
			ret.count += 1;
			NStackPush(&ds->nst, ret);
		}
	}
}
void DoubleStackPop(DoubleStack* ds)
{
	SDataType ret;
	assert(ds);
	//先获取结构体栈的栈顶元素
	ret = NStackTop(&ds->nst);

	//如果像个相等就做结构体计数-1或者出栈操作
	if(ret.num == StackTop(&ds->st))
	{
		if(ret.count == 1)
		{
			NStackPop(&ds->nst);
		}
		else 
		{
			ret.count--;
			NStackPop(&ds->nst);
			NStackPush(&ds->nst, ret);
		}
	}
	//将原本存数字出栈
	StackPop(&ds->st);
}

题目二:一个数组实现两个栈(共享栈)

本题需要使用一个数组来完成两个栈,于是最容易实现这两个栈的方法就是奇偶栈!
数组中的奇数位用来存储一个栈的数据,偶数位用来存储另一个栈的数据!
这里写图片描述

#include "ShareStack.h"

void ShareStackInit(ShareStack* pss)
{
	assert(pss);
	pss->_top1 = 0;
	pss->_top2 = 1;
}

//which 1/2
void ShareStackPush(ShareStack* pss, SSDataType x, int which)
{
	assert(pss && (which == 1 || which == 2));
	if (pss->_top1 < N && pss->_top2 < N)
	{
		if (which == 1)
		{
			pss->_a[pss->_top1] = x;
			pss->_top1 += 2;
		}
		else
		{
			pss->_a[pss->_top2] = x;
			pss->_top2 += 2;
		}
	}
	else
		printf("空间不足\n");
}
void ShareStackPop(ShareStack* pss, int which)
{
	assert(pss && (which == 1 || which == 2));

	if (which == 1 && (pss->_top1 - 2 >= 0))
		pss->_top1 -= 2;
	else if (which == 2 && (pss->_top2 - 2 >= 0))
		pss->_top2 -= 2;
}
int error_flag = 0;
SSDataType ShareStackTop(ShareStack* pss, int which)
{
	assert(pss && (which == 1 || which == 2));

	if (which == 1 && pss->_top1-2 >= 0)
		return pss->_a[pss->_top1 -2];
	else if (which == 2 && pss->_top2- 2 >= 0)
		return pss->_a[pss->_top2 -2];
	error_flag = -1;
	return error_flag;
}

void TestShareStack()
{
	ShareStack ss;
	ShareStackInit(&ss);
	ShareStackPush(&ss,11, 1);
	ShareStackPush(&ss, 22, 1);
	ShareStackPush(&ss, 33, 2);
	ShareStackPush(&ss, 44, 1);

	printf("%d\n", ShareStackTop(&ss, 1));
	ShareStackPop(&ss, 1);

	printf("%d\n", ShareStackTop(&ss, 1));
	ShareStackPop(&ss, 1);

	printf("%d\n",ShareStackTop(&ss, 2));
	ShareStackPop(&ss, 2);
}

题目三:元素出栈、入栈顺序的合法性。如入栈的序列(1,2,3,4,5),出栈序列为 (4,5,3,2,1) 。

这个问题需要将in 数组不停的入栈将每个入栈的元素与out 比较,相同的就出栈,否则继续入栈,然后直到in 数组已经没有元素可以入栈,接着就是逐个比较剩下的元素,每一个元素都要匹配才可以认定是匹配的!如下图:
这里写图片描述

#include "Stack.h"

int IsLegal(int *in, int *out, int insize, int outsize)
{
	int i = 0;
	int j = 0;
	Stack st;
	//如果指针无效或者长度不一样是无法判断的
	assert(in && out && insize == outsize);
	StackInit(&st);
	//将in数组中的元素压入栈中逐个比较,如果栈顶元素与out数组中的一致就弹出此元素
	while(i<insize)
	{
		StackPush(&st, in[i++]);
		if (StackTop(&st) == out[j]) {
			StackPop(&st);
			j++; //注意out数组中比较过的元素要跳过,所以下标要+1
		}
	}

	//此时栈中剩下的元素要与out数组中剩下的元素逐个比较,遇到不一样的就不匹配
	while (StackEmpty(&st) != 0)
	{
		if(StackTop(&st) != out[j++])
		{
			return 0;
		}
		StackPop(&st);
	}
	//此时为空栈,则说明匹配
	return 1;
}

int main(void)
{
	int in[5] = {1, 2, 3, 4, 5};
	int out[5] = {4, 5, 3, 2, 1 };
	int ret = IsLegal(in, out, 5, 5);
	if (ret == 1)
		printf("匹配\n");
	else
		printf("不匹配\n");

	system("pause");
	return 0;
}

测试用例:
入站数据:int in[5] = {1, 2, 3, 4, 5};
两组合法数据:
int out[5] = {4, 5, 3, 2, 1 };
int out[5] = {2, 3, 4, 5, 1 };
两组非法数据:
int out[5] = {4, 5, 3, 1, 2 };
int out[5] = {4, 3, 2, 5, 1 };

题目四:使用两个栈实现一个队列

  • 要实现Push接口其实不难,因为我们只需要向一个栈里面Push数据即可,我们暂且将这个栈定义为栈一,另一个栈设定为栈二
  • 要实现Pop接口的话,其实只要先判断栈二是否为空栈,如果栈二不为空那么直接Pop出一个元素即可,如果栈二不为空,那么需要先将栈一中的元素全部转移到栈二中,然后栈二就有元素了,直接Pop出一个即可!
#include "Topic.h"
void QueueByTwoStackInit(QueueByTwoStack* qts)
{
	assert(qts);
	StackInit(&(qts->s1));
	StackInit(&(qts->s2));
}

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

//永远向栈一Push元素
void QueueByTwoStackPush(QueueByTwoStack* qts, DataType x)
{
	assert(qts);
	StackPush(&(qts->s1),x);
}

void QueueByTwoStackPop(QueueByTwoStack* qts)
{
	assert(qts);
	//如果栈二为空需要先将栈一中的元素全部转移到栈二中
	if (StackEmpty(&(qts->s2)) == 0) 
	{
		while (StackEmpty(&(qts->s1)))
		{
			StackPush(&(qts->s2), StackTop(&(qts->s1)));
			StackPop(&(qts->s1));
		}
	}
	StackPop(&(qts->s2));
}

DataType QueueByTwoStackFront(QueueByTwoStack* qts)
{
	assert(qts);
	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)
{
	assert(qts);
	return StackSize(&(qts->s1)) + StackSize(&(qts->s2));
}

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

void TestQueueByTwoStack()
{
	QueueByTwoStack qs;
	QueueByTwoStackInit(&qs);
	QueueByTwoStackPush(&qs, 11);
	QueueByTwoStackPush(&qs, 22);
	QueueByTwoStackPush(&qs, 33);
	QueueByTwoStackPush(&qs, 44);
	QueueByTwoStackPop(&qs);
	QueueByTwoStackPop(&qs);
	QueueByTwoStackPush(&qs, 55);

	QueueByTwoStackDestory(&qs);
}

这里写图片描述

题目五:使用两个队列实现一个栈

接下来是两个队列实现一个栈,首先先大致说一下怎么实现?
这里写图片描述
如图所示,两个队列总有一个是空队列,一个是非空队列,要入栈的话,必须要入非空队列,出栈的话,必须让非空队列将元素转移到空队列里面,直到非空队列剩余一个元素,然后将剩余的这一个元素出队列,即可完成“出栈”

#include "motive.h"

//初始化
void StackByTwoQueueInit(StackByTwoQueue* stq)
{
	assert(stq);
	QueueInit(&(stq->q1));
	QueueInit(&(stq->q2));
}

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

//分配空队列与非空队列
static EmptyCmp(Queue** em, Queue** noem, StackByTwoQueue** pstq)
{
	assert(stq);
	QueueEmpty(&(*pstq)->q1) == 1 ? ((*noem = &(*pstq)->q1), *em = &((*pstq)->q2)) : ((*noem = &(*pstq)->q2), *em = &((*pstq)->q1));
}
//获取顶部数据
DataType StackByTwoQueueTop(StackByTwoQueue* stq)
{
	assert(stq);
	Queue *empty;
	Queue *noempty;
	DataType ret;
	//通过三元运算符确定空队列与非空队列
	EmptyCmp(&empty, &noempty, &stq);

	//将非空队列的元素转移到非空队列,保留一个
	while (QueueSize(noempty) > 1)
	{
		QueuePush(empty, QueueFront(noempty));
		QueuePop(noempty);
	}
	//获取保留结果数据
	ret = QueueFront(noempty);
	//将剩下的一个数据也转移
	QueuePop(noempty);
	QueuePush(empty, ret);
	return ret;
}

//判断模拟栈是否为空,为空返回0,不为空返回1
int StackByTwoQueueEmpty(const StackByTwoQueue* stq)
{
	assert(stq);
	//只要有一个队列不为空那么模拟栈就不为空
	return QueueEmpty(&(stq->q1)) | QueueEmpty(&(stq->q2));
}

//模拟栈中存入的元素个数
int StackByTwoQueueSize(const StackByTwoQueue* stq)
{
	assert(stq);
	return QueueSize(&(stq->q1)) + QueueSize(&(stq->q2));
}

//Push数据
void StackByTwoQueuePush(StackByTwoQueue* stq, DataType x)
{
	Queue *empty;
	Queue *noempty;
	assert(stq);
	EmptyCmp(&empty, &noempty, &stq);

	//永远向不为空的队列插入数据
	QueuePush(noempty,x);
}

//Pop数据
void StackByTwoQueuePop(StackByTwoQueue* stq)
{
	Queue *empty;
	Queue *noempty;
	assert(stq);
	EmptyCmp(&empty, &noempty, &stq);

	//与StackByTwoQueueTop()一样的过程,只是最后余下的元素直接出队列
	while (QueueSize(noempty) > 1)
	{
		QueuePush(empty, QueueFront(noempty));
		QueuePop(noempty);
	}
	printf("Pop:%d\n", noempty->_front->_data);
	QueuePop(noempty);
}

//测试函数
void TestStackByTwoQueue()
{
	StackByTwoQueue sq;
	StackByTwoQueueInit(&sq);
	StackByTwoQueuePush(&sq, 11);
	StackByTwoQueuePush(&sq, 22);
	StackByTwoQueuePush(&sq, 33);
	StackByTwoQueuePush(&sq, 44);
	StackByTwoQueuePop(&sq);
	StackByTwoQueuePop(&sq);
	StackByTwoQueuePush(&sq, 55);
	StackByTwoQueuePop(&sq);
	StackByTwoQueuePop(&sq);
	StackByTwoQueuePop(&sq);
	StackByTwoQueueDestory(&sq);
}

©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页