力扣232 - 用栈实现队列【C语言实现】

一、题目描述

在这里插入图片描述

示例 1:

输入:
[“MyQueue”, “push”, “push”, “peek”, “pop”, “empty”]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false

提示

  • 1 <= x <= 9
  • 最多调用 100 次 push、pop、peek 和 empty
  • 假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)

二、思路分析

可以先看看这一篇:用队列实现栈

好,看完题目的描述,我们来分析一下去求解这道题目

  • 我们知道,栈与队列的原理刚好相反,对于栈是【FILO】,对于队列是【FIFO】。这就需要我们灵活地去使用这两种数据结构进行解题。对于本题,我的思路是这样的: 因为需要使用栈来实现队列,那还需要像我们上一题那样将两个队列倒来倒去实现一个出栈的操作吗?
  • 答案是:不需要,对于这一题而言,我们需要有一个明确的思路,也是去定义两个栈,一个栈专门入数据,一个栈专门出数据,具体的实现在下面👇

三、代码详解

1、结构声明与展开剖析

  • 可以看到,【StIn】是专门用来入数据的,【StOut】是专门用来出数据的;接着看到初始化创建这一块,一样对这两个栈进行一个初始化,首先由【qu】访问到这个两个栈,接着传入相应的地址进行初始化操作
typedef struct {
    ST stIn;
    ST stOut;
} MyQueue;
MyQueue* myQueueCreate() {
    MyQueue* qu = (MyQueue *)malloc(sizeof(MyQueue));
    InitStack(&qu->stIn);
    InitStack(&qu->stOut);

    return qu;
}
  • 以下是这个结构的整体形式

在这里插入图片描述


  • 然后的话来讲几个重要的接口算法实现

2、入队【入栈思想】

  • 首先的话就是这个入队了,因为我们使用栈来模拟,而且有专门只入数据的栈,因此直接将要放入队列的数据放到这个【StIn】中即可
PushStack(&obj->stIn, x);       //入栈操作均放入stIn

3、获取队头【出栈思想】

  • 接下去在首先讲出队操作之前我先讲讲如果获取队头这个接口,也就是peek()
  • 首先你会想到的一定是直接去调用我们栈中的Top()这个接口,去【StOut】中取数据,确实是可以取出来,但是当这个【StOut】为空的时候怎么办呢?因为需要去做一个处理
return StackTop(&obj->stOut);
  • 但这个【StOut】为空的时候,我们就可以将【StIn】中的数据放入【StOut】中,直至【StIn】为空为止。因为我们规定过【StIn】只入数据,【StOut】只出数据,所以要将这个【StIn】中的数据都倒到【StOut】中才可(这句话看清楚了,不要被我绕晕😵,或者你直接看代码吧)
if(StackEmpty(&obj->stOut))     //如果stOut为空,则进行一个倒栈操作
{
    while(!StackEmpty(&obj->stIn))
    {
        PushStack(&obj->stOut, StackTop(&obj->stIn));
        PopStack(&obj->stIn);
    }
}

4、出队【复用思想】

  • 有了【peek()】这个接口,我们在实现出队接口的时候就不需要再去写一个了,只需要去进行一个复用即可。接着Pop()出【StOut】中的一个数据
int peek = myQueuePeek(obj);
PopStack(&obj->stOut);

return peek;

5、逐步算法图解

  • 接下去我们通过算法图解来步步分析一下,首先看到【StOut】为空,因为需要将【StIn】中的数据尽数放入其中

在这里插入图片描述

  • 接着的话当全部数据一一过来后可以看到所有数据刚好实现了一个逆置的效果,接着出栈栈顶元素即可,就可以实现队列的一个FIFO的性质🎋

在这里插入图片描述

  • 继续入两个数据

在这里插入图片描述

  • 当连续执行完3次出队后,可以看到出队的顺序就是先进先出,接下去要继续出数据,因为【StOut】空了,所以继续将刚入的9和7放进来

在这里插入图片描述

在这里插入图片描述

  • 最后出队完成后就是利用两个栈实现的模拟队列入队出队后的序列

在这里插入图片描述

四、整体代码展示

💻C语言代码实现

  • 题目代码使用的是C语言实现
typedef int STDataType;
typedef struct Stack {
	STDataType* a;
	int top;		//栈顶指针
	int capacity;	//容量
}ST;

/*初始化栈*/
void InitStack(ST* st);

/*销毁栈*/
void DestroyStack(ST* st);

/*入栈*/
void PushStack(ST* st, STDataType x);

/*出栈*/
void PopStack(ST* st);

/*返回栈顶元素*/
STDataType StackTop(ST* st);

/*判空*/
bool StackEmpty(ST* st);

/*栈的元素个数*/
int StackSize(ST* st);

//--------------------------------
typedef struct {
    ST stIn;
    ST stOut;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* qu = (MyQueue *)malloc(sizeof(MyQueue));
    InitStack(&qu->stIn);
    InitStack(&qu->stOut);

    return qu;
}

void myQueuePush(MyQueue* obj, int x) {
    PushStack(&obj->stIn, x);       //入栈操作均放入stIn
}

bool myQueueEmpty(MyQueue* obj) {
    return StackEmpty(&obj->stIn) && StackEmpty(&obj->stOut);
}

int myQueuePop(MyQueue* obj) {
    int peek = myQueuePeek(obj);
    PopStack(&obj->stOut);

    return peek;
}

int myQueuePeek(MyQueue* obj) {
    if(StackEmpty(&obj->stOut))     //如果stOut为空,则进行一个倒栈操作
    {
        while(!StackEmpty(&obj->stIn))
        {
            PushStack(&obj->stOut, StackTop(&obj->stIn));
            PopStack(&obj->stIn);
        }
    }
    return StackTop(&obj->stOut);
}

void myQueueFree(MyQueue* obj) {
    DestroyStack(&obj->stIn);
    DestroyStack(&obj->stOut);

    free(obj);
}

//--------------------------------
/*初始化栈*/
void InitStack(ST* st)
{
	assert(st);		//警惕随意操作,传入空指针
	st->a = (STDataType*)malloc(sizeof(STDataType) * 4);
	if (st->a == NULL)
	{
		perror("fail mallic");
		exit(-1);
	}
	st->top = 0;		//初始化为0表示指向当前栈顶元素的后一元素
	st->capacity = 4;
}

/*销毁栈*/
void DestroyStack(ST* st)
{
	assert(st);
	free(st->a);
	st->a = NULL;
	st->top = st->capacity = 0;
}

/*入栈*/
void PushStack(ST* st, STDataType x)
{
	//栈满扩容逻辑
	if (st->top == st->capacity)
	{
		//初始化时已经malloc开辟过空间了,因此无需考虑容量为空的情况
		STDataType* tmp = (STDataType*)realloc(st->a, st->capacity * 2 * sizeof(STDataType));
		if (tmp == NULL)
		{
			perror("fail realloc");
			exit(-1);
		}
		st->a = tmp;
		st->capacity *= 2;
	}
	st->a[st->top] = x;		//top指向栈顶元素的后一元素,因此直接入栈即可
	st->top++;		//然后栈顶指针后移,为下一次入栈做准备
}

/*出栈*/
void PopStack(ST* st)
{
	assert(st);
	//assert(st->top > 0);
	assert(!StackEmpty(st));

	st->top--;
}

/*返回栈顶元素*/
STDataType StackTop(ST* st)
{
	return st->a[st->top - 1];
}

/*判空*/
bool StackEmpty(ST* st)
{
	return (st->top == 0);
}

/*栈的元素个数*/
int StackSize(ST* st)
{
	return st->top;
}

/**
 * Your MyQueue struct will be instantiated and called as such:
 * MyQueue* obj = myQueueCreate();
 * myQueuePush(obj, x);
 
 * int param_2 = myQueuePop(obj);
 
 * int param_3 = myQueuePeek(obj);
 
 * bool param_4 = myQueueEmpty(obj);
 
 * myQueueFree(obj);
*/

五、总结与提炼

  • 最后我们来总结一下本文所介绍的内容,本文讲解的是一道力扣中有关栈与队列相关的题目,使用的栈来实现队列,对于本题,和上题使用队列来实现栈不同的是我们不需要去判断哪个是否为空,对于本题来说,我们只需要往【StIn】中入数据,往【StOut】中出数据即可,就可以实现模拟队列的操作

以上就是本文所要描述的所有内容,感谢您对本文的观看,如有疑问请于评论区留言或者私信我都可以🍀

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
请问您需要的是两个数组的交集元素还是交集元素的数量? 如果是交集元素,可以采用双指针的方式,先将两个数组排序,然后设定两个指针 i 和 j,分别指向两个数组的开头,比较两个指针所指向的元素的大小,如果相等,则说明找到了一个交集元素,将其存到结果数组中;如果不相等,则将指向小的元素的指针向后移动一位,直到其中一个指针越界为止。 代码实现如下: ```c int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ int i = 0, j = 0, k = 0; int* res = (int*)malloc(sizeof(int) * (nums1Size > nums2Size ? nums2Size : nums1Size)); // 排序 qsort(nums1, nums1Size, sizeof(int), cmp); qsort(nums2, nums2Size, sizeof(int), cmp); while (i < nums1Size && j < nums2Size) { if (nums1[i] == nums2[j]) { res[k++] = nums1[i]; i++; j++; } else if (nums1[i] < nums2[j]) { i++; } else { j++; } } *returnSize = k; return res; } int cmp(const void* a, const void* b) { return *(int*)a - *(int*)b; } ``` 如果是交集元素的数量,可以采用哈希表的方式,用一个哈希表来记录第一个数组中的元素出现的次数,然后遍历第二个数组,在哈希表中查找是否存在相同的元素,如果存在,则说明找到了一个交集元素,将其计数并从哈希表中删除该元素,最后返回计数结果即可。 代码实现如下: ```c int* intersect(int* nums1, int nums1Size, int* nums2, int nums2Size, int* returnSize){ int i = 0, j = 0, k = 0; int* res = (int*)malloc(sizeof(int) * (nums1Size > nums2Size ? nums2Size : nums1Size)); int* hash = (int*)malloc(sizeof(int) * 1001); // 由于题目条件限制在 [0, 1000] 范围内,所以哈希表可以开得比较小 memset(hash, 0, sizeof(hash)); for (i = 0; i < nums1Size; i++) { hash[nums1[i]]++; } for (j = 0; j < nums2Size; j++) { if (hash[nums2[j]] > 0) { res[k++] = nums2[j]; hash[nums2[j]]--; } } *returnSize = k; return res; } ``` 希望这些代码能够帮到您,如有疑问请随时问我~

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烽起黎明

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值