力扣经典题————栈和队列结合会生成怎样的火花呢?

一.让我们复习一下什么是“栈”和“队列”

1.栈是什么?

栈作为一种基本的数据结构,它的主要特点是后进先出,类似于一口大缸一样:

数据从上至下加入,取数据时只能由表面取出。我们可以通过顺序表的方式进行实现,也可以通过链表进行实现,由于栈不需要从栈底获取元素,所以减少顺序表头插麻烦的劣势,所以我使用顺序表实现。

typedef int STdata;

typedef struct stack {
	STdata* a;
	int top;
	int capacity;
}ST;

void STInit(ST* pst);
void STPush(ST* pst, STdata x);
void STPop(ST* pst);
STdata STTop(ST* pst);
bool STEmpty(ST* pst);
int STSize(ST* pst);
void STDestroy(ST* pst);

void STInit(ST* pst)
{
	assert(pst);
	pst->a = NULL;
	pst->top=0;
	pst->capacity = 0;

}
void STPush(ST* pst, STdata x)
{
	assert(pst);
	if (pst->top == pst->capacity)
	{
		int newcapacity =pst->capacity==0 ? 4 : 2*pst->capacity;
		STdata* tmp = (STdata*)realloc(pst->a,sizeof(STdata)*newcapacity);
		if (tmp==NULL)
		{
			perror("realloc fail");
		}
		pst->a = tmp;
		pst->capacity = newcapacity;
	}
	pst->a[pst->top] = x;
	pst->top++;
}
void STPop(ST* pst)
{
	assert(pst);
	assert(pst->top > 0);

		pst->top--;
}
STdata STTop(ST* pst)
{
	assert(pst);
	// 不为空
	assert(pst->top > 0);

	return pst->a[pst->top - 1];
}
bool STEmpty(ST* pst)
{
	assert(pst);
	return pst->top==0;
}
int STSize(ST* pst)
{
	assert(pst);

	return pst->top;
}
void STDestroy(ST* pst)
{
	assert(pst);
	free(pst->a);
	pst->a = NULL;
	pst->capacity = 0;
	pst->top = 0;
}

我们来简单测试一下各项功能:

2.队列是什么?

正如其名一般,队列好像一个排着的对,先进先出:

使用者在队尾加入数据,从队头获得数据,中间数据不访问,恰好对应了单链表的优势,所以我们也来简单实现一下:

#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>

typedef int Qdata;

typedef struct queuenode {
	Qdata val;
	struct queuenode* next;
}QNode;

typedef struct queue {
	QNode* phead;
	QNode* ptail;
	int size;
}queue;

void QueueInit(queue* pq);
void QueuePush(queue* pq, Qdata x);
void QueuePop(queue* pq);
Qdata QueueFront(queue* pq);
Qdata QueueBack(queue* pq);
bool QueueEmpty(queue* pq);
int QueueSize(queue* pq);
void QueueDestroy(queue* pq);
void QueueInit(queue* pq)
{
	assert(pq);
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}
void QueuePush(queue* pq, Qdata x)
{
	assert(pq);
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("newnode creat fail");
	}
	newnode->next = NULL;
	newnode->val = x;
	if (pq->ptail == NULL)
	{
		pq->ptail = pq->phead = newnode;
	}
	else
	{
		pq->ptail->next = newnode;
		pq->ptail = newnode;
	}
	pq->size++;
}
void QueuePop(queue* pq)
{
	assert(pq);
	assert(pq->phead);
	QNode* del = pq->phead;
	pq->phead = pq->phead->next;
	free(del);
	if (pq->phead == NULL)
		pq->ptail = NULL;
	pq->size--;
}
Qdata QueueFront(queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return 	 pq->phead->val;

}
QueueBack(queue* pq)
{
	assert(pq);
	assert(pq->phead);
	return	 pq->ptail->val;
}
bool QueueEmpty(queue* pq)
{
	assert(pq);

	return pq->phead == NULL;
}
int QueueSize(queue* pq)
{
	assert(pq);
	return pq->size;
}
void QueueDestroy(queue* pq)
{
	assert(pq);
	QNode* del = pq->phead;
	while (del)
	{
		QNode* next = del->next;
		free(del);
		del = next;
	}
	pq->phead = pq->ptail = NULL;
	pq->size = 0;
}

我们使用phead和ptail指针来维护,队列的头和尾,还可以加入一个size来动态记录队列成员数量。

二.思想进阶,队列和栈怎么互相转换呢?

1.用两个队列实现一个栈

题目链接:题目1

在做题之前,由于我们用的纯c语言,没有标准库,所以先自我实现一下队列。

做题思路是永远保持两个队列,一个空队列,一个存数据的队列,当队列push时,则直接添加到有数据队列的队尾,当需要删除时,则需要将当前队列转移至空队列只剩队尾一个,然后删除那一个元素。

1.先创建Mystack栈的结构体并进行初始化(直接malloc至堆上,函数使用完后空间并不会销毁)

typedef struct {
   queue q1;
   queue q2;
    
} MyStack;


MyStack* myStackCreate() {
   MyStack*pst= (MyStack*)malloc(sizeof(MyStack));
   QueueInit(&pst->q1);
   QueueInit(&pst->q2);
    return pst;
}

2.判空函数

bool myStackEmpty(MyStack* obj) {
    if(QueueEmpty(&obj->q1)&&QueueEmpty(&obj->q2))
    {
        return true;
    }
    return false;
}

3.push

void myStackPush(MyStack* obj, int x) {
   if(!QueueEmpty(&obj->q1))
   {
    QueuePush(&obj->q1,x);
   }
   else
   {
     QueuePush(&obj->q2,x);
   }
}

如果,队列不为空,则继续推入,反之推入另一个。

4.pop

int myStackPop(MyStack* obj) {
    queue*Emptyq=&obj->q1;
    queue*nonEmptyq=&obj->q2;
    if(!QueueEmpty(&obj->q1))
    {
       Emptyq=&obj->q2;
      nonEmptyq=&obj->q1;
    }
    while(QueueSize(nonEmptyq)>1)
    {
      QueuePush(Emptyq,QueueFront(nonEmptyq));
      QueuePop(nonEmptyq);
    }
    int top=QueueFront(nonEmptyq);
    QueuePop(nonEmptyq);
    return top;
    
}

先假定q1为空进行创建指针,然后判断纠正。进行遍历,导入数据。

5.最后收尾即可

int myStackTop(MyStack* obj) {

    if(!QueueEmpty(&obj->q1))
   {
  return   QueueBack(&obj->q1);
   }
   else
   {
   return  QueueBack(&obj->q2);
   }
}

void myStackFree(MyStack* obj) {
    QueueDestroy(&obj->q1);
    QueueDestroy(&obj->q2);
    free(obj);
    
}

2.用两个栈实现一个队列

题目:题目2

用栈实现队列,关键在于设置两个不同作用的栈,pop栈,push栈,每当需要pop时先检查是否pop栈为空,若为空则将push栈取出,放入pop栈,从栈底删除,相当于删了队列头数据。

1.创建MyQueue

typedef struct {
    ST pushstack;
    ST popstack;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
    STInit(&obj->pushstack);
    STInit(&obj->popstack);
    return obj;
}

2.判空函数

bool myQueueEmpty(MyQueue* obj) {
  return   STEmpty(&obj->pushstack)&&STEmpty(&obj->popstack);
}

3.返回队头元素和删除函数

int myQueuePeek(MyQueue* obj) {
    if(!STEmpty(&obj->popstack))
    return STTop(&obj->popstack);
    else 
    {
        while(!STTop(&obj->pushstack))
        {
            STPush(&obj->popstack,STTop(&obj->pushstack));
            STPop(&obj->pushstack);
        }
        return STTop(&obj->popstack);
    }
}
int myQueuePop(MyQueue* obj) {
      int top=myQueuePeek(obj);
      STPop(&obj->popstack);
      return top;
}

4.push


void myQueuePush(MyQueue* obj, int x) {
    STPush(&obj->pushstack,x);
}

5.最后进行收尾

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->pushstack);
    STDestroy(&obj->popstack);
    free(obj);
}

这两个题看似很无聊,实则对理解这两种数据结构意义重大。

本期就到这里,希望各位一键三联。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

强sir的世界

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

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

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

打赏作者

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

抵扣说明:

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

余额充值