当前位置 : 主页 > 编程语言 > c语言 >

利用栈完成队列

来源:互联网 收集:自由互联 发布时间:2023-09-03
栈和队列的特点 首先我们要知道一个队列的特点是先进先出,也就意味着如果我们往队列出输入1234那么输出的值也是1234,而栈的特点是后进先出,同样是在栈中输入1234,输出的是43


栈和队列的特点

首先我们要知道一个队列的特点是先进先出,也就意味着如果我们往队列出输入1234那么输出的值也是1234,而栈的特点是后进先出,同样是在栈中输入1234,输出的是4321。

那么我们怎么运用两个栈去完成一个队列呢?

下面是题目

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

解题思路

运用画图去理解:

利用栈完成队列_数据

利用栈完成队列_数据结构_02

现在我们往输入栈中输入1234。然后要我们输出1,我们就可以将输入栈里面的数据全部导入到输出栈里面

利用栈完成队列_Stack_03

现在我们就可以将1从输出栈里面删除了。如果还要你继续删除2那么也只用将2从输出栈里面删除就可以了。如果我们想要继续输入呢,那么我们只用往输入栈里面输入就可以了,等到输出栈里面的数据都已经输出完成之后,再将输入栈里面的数据输入到输出栈里面,再通过输出栈输出即可。

利用栈完成队列_数据结构_04

下面我们就来解题:

解题开始

因为在c中并没有栈所以我们这里必须先自己实现一个栈。至于栈的完成请参考我的上一篇博客这里我就将栈写在下面。

栈代码:

// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{
	STDataType* _a;
	int _top; // 栈顶
	int _capacity; // 容量
}Stack;
// 初始化栈
void StackInit(Stack* ps);
// 入栈
void StackPush(Stack* ps, STDataType data);
// 出栈
void StackPop(Stack* ps);
// 获取栈顶元素
STDataType StackTop(Stack* ps);
// 获取栈中有效元素个数
int StackSize(Stack* ps);
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
bool StackEmpty(Stack* ps);
// 销毁栈
void StackDestroy(Stack* ps);
//栈的特点是后进先出
// 这里是运用的动态数组实现的栈
// 初始化栈
void StackInit(Stack* ps)
{
	assert(ps);//断言防止传入空指针,因为ps是一个结构体指针那么外部在使用的时候一定会存在一个结构体
	//所以这里可以断言
	ps->_a = NULL;//在初始化的这里你可以选择一开始就开辟一些初始空间给这个数组但这里我就直接初始化为NULL了
	ps->_capacity = 0;//容量自然也是0
	ps->_top = 0;//这里有两种选择一种选择是0一种选择为-1,要解决为什么要使用0或-1我们就要理解top这里代表的含义
	//如果你想要top指向的就是栈顶的话你就要使用-1,如果你偏要使用0来代表栈顶,那么一开始的时候栈中没有元素,但是你的栈顶却指向了0,这明显不对
	//所以当栈中没有元素的时候我们就要使用-1来作为初始的栈顶元素指向
	//那么如果这里的top表示的是栈顶的下一个元素呢?那么这里的top初始值就可以写为0,因为如果一开始栈顶为无元素的下一个栈顶自然是0元素
}
// 入栈
void StackPush(Stack* ps, STDataType data)
{
	assert(ps);
	//首先我们要判断容量是否足够
	if (ps->_capacity == ps->_top)//我这里top的含义是栈顶的下一个元素,所以当top等于容量等于top时就要扩容了,
		//如果这里你的top代表的时栈顶元素那么如果栈顶元素+1等于容量一样要扩容
	{
		int newcapacity = ps->_capacity == 0 ? 4 : 2 * ps->_capacity;
		STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);//realloc函数当我们要扩容的指针指向的是NULL时,这时的realloc的功能相当于malloc
		if (tmp == NULL)//判断空间创建是否成功
		{
			perror("realloc fail");
			return;
		}
		ps->_a = tmp;//为空间赋值
		ps->_capacity = newcapacity;//更新容量
	}//因为在栈的操作里面只有这里一个地方需要判断容量,所以这里并没有将判断容量写成一个新函数
	//下面我们就要让元素进栈
	ps->_a[ps->_top] = data;//我们就以一开始为例子当栈中没有元素的时候我们放入的元素自然是栈顶的元素将其直接放入即可
	ps->_top++;//再让top++指向新栈顶的下一个元素
}
// 出栈
void StackPop(Stack* ps)
{
	assert(ps);
	//下面我们要判断是否是空栈
	assert(!StackEmpty(ps));
	//下面我们就要让栈顶的元素移除
	ps->_top--;//即可
}
// 获取栈顶元素
STDataType StackTop(Stack* ps)
{
	assert(ps);
	assert(!StackEmpty(ps));//如果这里的栈为空我们仍然访问栈顶元素就会出现越界访问的情况
	//所以这里直接assert断死
	return ps->_a[ps->_top - 1];
}
// 获取栈中有效元素个数
int StackSize(Stack* ps)
{
	assert(ps);
	//这里有效元素的个数也就是top了
	return ps->_top;
}
// 检测栈是否为空,如果为空返回true,如果不为空返回false 
bool StackEmpty(Stack* ps)
{
	assert(ps);
	return ps->_top == 0;
}
// 销毁栈
void StackDestroy(Stack* ps)
{
	assert(ps);
	free(ps->_a);
	ps->_capacity = 0;
	ps->_top = 0;
}
typedef struct {
    Stack inputdata;//这个是输入数据的栈
    Stack outdata;//这个是栈输出数据的栈

} MyQueue;//这里我们经过分析运用两个栈就可以实现一个队列,所以这里我们在结构体里面建立了两个栈
//这里的结构题定义使用的是匿名结构体的定义

MyQueue* myQueueCreate() 
{
      //这里也就是要求我们创建一个MyQueue* 的变量,并且这个变量必须使用malloc建立
      //因为不使用malloc建立的变量只是临时变量在出了这个作用域之后就会被销毁
      MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue));
      if(obj == NULL)
      {
          perror("malloc fail");
          return 0;
      }
      //创建好obj之后我们还要将stack a和b初始化
      StackInit(&obj->inputdata);//因为我们实现这个函数的时候使用的是stack* 所以这里要取一个地址
      StackInit(&obj->outdata);//原理同上
      return obj;//最后返回obj
}

void myQueuePush(MyQueue* obj, int x) {
     //这里也就是要往栈里面入数据
     //直接往inputdata里面输入数据就可以了
     StackPush(&obj->inputdata,x);
}

int myQueuePop(MyQueue* obj) {
    //这里要求我们输出数据那么按照思路我们就直接让outdata栈出数据就可以了
    //如果outdata栈里面没有数据就从inputdata里面导数据
    if(StackEmpty(&obj->outdata))
    {
        while(!StackEmpty(&obj->inputdata))//这里如果input里面空了那么返回的就是true
        //经过!后变成false循环停止
        {
            StackPush(&obj->outdata,StackTop(&obj->inputdata));//这里先获取到inputdata了里面的数据
            //然后导入outdata里面再删除inputdata里面的这个数据
            StackPop(&obj->inputdata);
        }
    }
    int front = StackTop(&obj->outdata);
    StackPop(&obj->outdata);
    return front;//因为题目要求我们将删除的数据
}

int myQueuePeek(MyQueue* obj) 
{
	if(StackEmpty(&obj->outdata))
    {
        while(!StackEmpty(&obj->inputdata))//这里如果input里面空了那么返回的就是true
        //经过!后变成false循环停止
        {
            StackPush(&obj->outdata,StackTop(&obj->inputdata));//这里先获取到inputdata了里面的数据
            //然后导入outdata里面再删除inputdata里面的这个数据
            StackPop(&obj->inputdata);
        }
    }
    return StackTop(&obj->outdata);
}

bool myQueueEmpty(MyQueue* obj) 
{
   //当两个栈里面的数据都没有了时我们创建的队列即为空
   return StackEmpty(&obj->outdata)&&StackEmpty(&obj->inputdata);

}

void myQueueFree(MyQueue* obj) 
{
    StackInit(&obj->inputdata);//先将栈销毁
    StackDestroy(&obj->outdata);
    free(obj);
}

做题链接https://leetcode.cn/problems/implement-queue-using-stacks/description/

希望能对你有所帮助

上一篇:力扣题目两两交换链表中的节点
下一篇:没有了
网友评论