栈和队列经典OJ

栈和队列相关代码在前面已经实现过了,接下来就手撕几道有关栈和队列的几道高频经典OJ,让大家更加深刻的理解栈和队列这两种数据结构。



80c4176d48b84bafbc67a4e3d0129aa8.jpeg


第一题:用栈实现队列 

OJ链接:

232. 用栈实现队列 - 力扣(LeetCode)


9a8f5cf76ae7483caf3aa37ada77ba6d.png

 题目要求用两个栈实现一个队列,要求具备队列基本接口:入列,出列,返回队列头元素,判断队列是否为空。接下来我们按照 ” 一定能写出来四步流程 “,来完成这个题目。

86e603783de04de399cbe4e75cdcb9b5.png

一.思路分析:

我们知道,队列有先进先出(FIFO)的原则,所以要想用两个栈实现队列,就必须用这两个栈使得数据先进先出。因为栈是先进后出的原则,会使得出数据顺序相反,所以用两个栈就刚好可以把顺序摆正。例如 1 2 3 4进入第一个栈---->4 3 2 1进入第二个栈---->1 2 3 4

ab9f6b20470b44b198dedc4ef452e711.png

 二.细节分析

我们把两个栈分别取名为pushstack、popstack。即一个栈专门用来入队列,一个栈专门用来出队列。

1.当有元素要入队列:只需要把这个元素入栈到pushstack。

2.当有元素要出队列:如果popstack栈中有元素,直接出栈即可。如果popstack栈中没有元素,需要将pushstack栈中的元素捯入popstack栈。再出popstack栈。

3.返回队首元素:如果popstack栈中有元素,直接返回栈顶元素即可。如果popstack栈中没有元素,需要将pushstack栈中的元素捯入popstack栈。再返回popstack栈顶元素。

4.判断队列是否为空:若两个栈都为空,则队列为空。

三.代码实现

//栈的实现
typedef int DateType;
typedef struct Stack//栈的总架构(这里是动态栈)
{
	DateType* arr;
	int top;//栈顶下标
	int capcity;//栈的容量
}Stack;
//下面对栈的操作都是改变结构体内部的属性,参数列表传结构体一级指针
void IntiStack(Stack* stack);//初始化栈
void PushStack(Stack* stack, DateType n);//进栈,尾插
void PopStack(Stack* stack);//出栈,尾删
bool StackEmpty(Stack* stack);//检测栈是否为空
int StackSize(Stack* stack);//获取栈中有效数据个数
DateType TopStack(Stack* stack);//获取栈顶数据
void DestoryStack(Stack* stack);//销毁栈

void IntiStack(Stack* stack)
{
	DateType* tmp = (DateType*)malloc(4*sizeof(DateType));
	assert(tmp);
	stack->arr = tmp;
	stack->top = 0;
	stack->capcity = 4;
}
void PushStack(Stack* stack, DateType n)
{
	assert(stack);
	if (stack->top == stack->capcity)
	{
		//扩容
		DateType* tmp = realloc(stack->arr,2 * stack->capcity * sizeof(DateType));
		assert(tmp);
		stack->arr = tmp;
		stack->capcity *= 2;
	}
	stack->arr[stack->top] = n;
	stack->top++;
}
void PopStack(Stack* stack)
{
	assert(stack);
	assert(!StackEmpty(stack));
	stack->top--;
}
bool StackEmpty(Stack* stack)
{
	assert(stack);
	return stack->top == 0;
}
int StackSize(Stack* stack)
{
	assert(stack);
	return stack->top;
}
DateType TopStack(Stack* stack)
{
	assert(stack);
	assert(!StackEmpty(stack));
	return stack->arr[stack->top - 1];
}
void DestoryStack(Stack* stack)
{
	assert(stack);
	free(stack->arr);
	stack->arr = NULL;
	stack->capcity = 0;
	stack->top = 0;
}

//开始解题
typedef struct//定义队列
{
    Stack pushstack;//定义两个栈
    Stack popstack;
} MyQueue;
MyQueue* myQueueCreate()//初始化队列
{
    MyQueue* queue=(MyQueue*)malloc(sizeof(MyQueue));//为队列分配空间,顺便为两个栈分配空间
    IntiStack(&queue->pushstack);//初始化两个栈
    IntiStack(&queue->popstack);
    return queue;
}
void myQueuePush(MyQueue* obj, int x)//入列
{
    PushStack(&obj->pushstack,x);//把这个元素入栈到pushstack
}

int myQueuePop(MyQueue* obj)//出列
{
    int tmp=myQueuePeek(obj);//获取队列头元素(popstack栈顶元素)
    PopStack(&obj->popstack);//删除popstack栈顶元素
    return tmp;//返回队列头元素
}
int myQueuePeek(MyQueue* obj)//获取队首元素
{
    if(StackEmpty(&obj->popstack))//如果popstack栈为空
    {
        //导pushstack栈的数据->popstack栈
        while(!StackEmpty(&obj->pushstack))//循环条件:pushstack栈不为空
        {
            //将pushstack栈顶元素入栈到popstack栈
            PushStack(&obj->popstack,TopStack(&obj->pushstack));
            //删除pushstack栈顶元素
            PopStack(&obj->pushstack);
        }
    }
    return TopStack(&obj->popstack);//返回popstack栈顶元素
}
bool myQueueEmpty(MyQueue* obj)//判断队列是否为空
{
    //两个栈都为空,队列为空,返回true
    return StackEmpty(&obj->pushstack)&&StackEmpty(&obj->popstack);
}
void myQueueFree(MyQueue* obj)//销毁队列
{
    DestoryStack(&obj->pushstack);//先销毁里面两个栈中的顺序表空间
    DestoryStack(&obj->popstack);
    free(obj);//再释放队列空间(可以释放两个栈的空间,但是无法是释放栈里面的顺序表空间!)
}

四.总结

用栈实现队列本质需要了解栈与队列的区别,知道二者数据处理的差异,并灵活应用。

猜你喜欢

转载自blog.csdn.net/2301_76144863/article/details/131117637