栈和队列——精选题目

「C++ 40 周年」主题征文大赛(有机会与C++之父现场交流!) 10w+人浏览 470人参与

目录

1.有效的括号

思路:用栈来解决

2.用队列实现栈

思路:用空队列接收非空队列得前top-1个元素,再让最后一个元素出队列即可。

3.用栈实现队列

思路:两个栈:pushST用来入队,popST用来出队

4.设计循环队列

思路:

1.有效的括号

题目链接:
20. 有效的括号 - 力扣(LeetCode)https://leetcode.cn/problems/valid-parentheses/description/题目描述:

给定一个只包括 '('')''{''}''['']' 的字符串 s ,判断字符串是否有效。

有效字符串需满足:

  1. 左括号必须用相同类型的右括号闭合。

  2. 左括号必须以正确的顺序闭合。

  3. 每个右括号都有一个对应的相同类型的左括号。

思路:用栈来解决

//定义栈的结构
typedef char STDataType;
typedef struct stack {
	STDataType* arr;
	int top;
	int capacity;
}stack;
//初始化
void STInit(stack* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//销毁栈
void STDestroy(stack* ps)
{
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//入栈
void STPush(stack* ps, STDataType x)
{
	assert(ps);
	//判断空间是否足够
	if (ps->capacity == ps->top)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* temp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (temp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}
//判断栈是否为空
bool STEmpty(stack* ps)
{
	assert(ps);
	return ps->top == 0;
}
//出栈
void STPop(stack* ps)
{
	assert(!STEmpty(ps));
	ps->top--;
}
//取栈顶数据
STDataType STTop(stack* ps)
{
	assert(!STEmpty(ps));
	return ps->arr[ps->top - 1];
}
//获取栈中有效元素个数
int STSize(stack* ps)
{
	assert(ps);
	return ps->top;
}


bool isValid(char* s) {
    //借助栈来实现
    stack st;
    STInit(&st);
    char* pi=s;
    while(*pi!='\0')
    {
        if(*pi=='('||*pi=='['||*pi=='{')
        {
            STPush(&st,*pi);
        }
        else{
            if(STSize(&st)==0)
            {
                return false;
            }
            char top=STTop(&st);
            if( (top=='('&&*pi==')') || (top=='['&&*pi==']') || (top=='{'&&*pi=='}') )
            {
                STPop(&st);
            }
            else{
                STDestroy(&st);
                return false;
            }
        }
        pi++;
    }
    bool ret=STEmpty(&st)?true:false;
    STDestroy(&st);
    return ret;
}

2.用队列实现栈

题目链接:
225. 用队列实现栈 - 力扣(LeetCode)https://leetcode.cn/problems/implement-stack-using-queues/description/题目描述:

请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(pushtoppop 和 empty)。

实现 MyStack 类:

  • void push(int x) 将元素 x 压入栈顶。

  • int pop() 移除并返回栈顶元素。

  • int top() 返回栈顶元素。

  • boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。

思路:用空队列接收非空队列得前top-1个元素,再让最后一个元素出队列即可。

//定义队列结构
typedef struct QueueNode {
    int data;
    struct QueueNode* next;
} QueueNode;
typedef struct Queue {
    QueueNode* phead;
    QueueNode* ptail;
} Queue;
//队列有效元素个数
int QueueSize(Queue* pq)
{
	assert(pq);
	int size = 0;
	QueueNode* pcur = pq->phead;
	while (pcur!=NULL)
	{
		size++;
		pcur = pcur->next;
	}
	return size;
}


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


MyStack* myStackCreate() {
    MyStack* pst=(MyStack*)malloc(sizeof(MyStack));
    //初始化栈
    pst->q1.phead=pst->q1.ptail=NULL;
    pst->q2.phead=pst->q2.ptail=NULL;
    return pst;
}

void myStackPush(MyStack* obj, int x) {
    QueueNode* newnode=(QueueNode*)malloc(sizeof(QueueNode));
    newnode->data=x;
    newnode->next=NULL;
    //往不为空的队列里插入数据
    if(obj->q1.phead!=NULL)
    {
        obj->q1.ptail->next=newnode;
        obj->q1.ptail=obj->q1.ptail->next;
    }
    else if(obj->q2.phead!=NULL)
    {
	    obj->q2.ptail->next=newnode;
        obj->q2.ptail=obj->q2.ptail->next;
    }
    else {
        obj->q1.phead = obj->q1.ptail = newnode;
    }
}

int myStackPop(MyStack* obj) {
    //找不为空队列
    Queue* emp=&obj->q1;
    Queue* noneEmp=&obj->q2;
    if(obj->q2.phead==NULL)
    {
        emp=&obj->q2;
        noneEmp=&obj->q1;
    }
    //不为空的队列前size-1个数据插入空队列中
    while(QueueSize(noneEmp)>1)
    {
        QueueNode* newnode=(QueueNode*)malloc(sizeof(QueueNode));
        newnode->data=noneEmp->phead->data;
        newnode->next=NULL;
        if (emp->phead == NULL)
        {
	        emp->phead = emp->ptail = newnode;
        }
        else {
	        emp->ptail->next=newnode;
            emp->ptail=emp->ptail->next;
        }
        //出队头
        if (noneEmp->phead == noneEmp->ptail)
        {
	        free(noneEmp->phead);
	        noneEmp->phead = noneEmp->ptail = NULL;
        }
        else {
	        QueueNode* next = noneEmp->phead->next;
	        free(noneEmp->phead);
	        noneEmp->phead = next;
        }
    }
    int top=noneEmp->phead->data;
	free(noneEmp->phead);
	noneEmp->phead = noneEmp->ptail = NULL;
    return top;
}

int myStackTop(MyStack* obj) {
    //找不为空队列
    Queue* emp=&obj->q1;
    Queue* noneEmp=&obj->q2;
    if(obj->q2.phead==NULL)
    {
        emp=&obj->q2;
        noneEmp=&obj->q1;
    }
    //返回不为空队列的队尾
    return noneEmp->ptail->data;
}

bool myStackEmpty(MyStack* obj) {
    return obj->q1.phead==NULL&&obj->q2.phead==NULL;
}

void myStackFree(MyStack* obj) {
    QueueNode* pcur1 = obj->q1.phead;
    while (pcur1)
    {
	    QueueNode* next = pcur1->next;
	    free(pcur1);
	    pcur1 = next;
    }
    obj->q1.phead = obj->q1.ptail = NULL;
    QueueNode* pcur2 = obj->q2.phead;
    while (pcur2)
    {
	    QueueNode* next = pcur2->next;
	    free(pcur2);
	    pcur2 = next;
    }
    obj->q2.phead = obj->q2.ptail = NULL;
    free(obj);
    obj=NULL;
}

/**
 * Your MyStack struct will be instantiated and called as such:
 * MyStack* obj = myStackCreate();
 * myStackPush(obj, x);
 
 * int param_2 = myStackPop(obj);
 
 * int param_3 = myStackTop(obj);
 
 * bool param_4 = myStackEmpty(obj);
 
 * myStackFree(obj);
*/

这里写的有些麻烦,也可以直接套用之前写的队列的代码,必要的地步直接用之前的队列代码里定义的函数即可。

3.用栈实现队列

题目链接:
232. 用栈实现队列 - 力扣(LeetCode)https://leetcode.cn/problems/implement-queue-using-stacks/description/题目描述:

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

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾

  • int pop() 从队列的开头移除并返回元素

  • int peek() 返回队列开头的元素

  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

思路:两个栈:pushST用来入队,popST用来出队

//定义栈的结构
typedef int STDataType;
typedef struct stack {
	STDataType* arr;
	int top;
	int capacity;
}stack;
//初始化
void STInit(stack* ps)
{
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//销毁栈
void STDestroy(stack* ps)
{
	if (ps->arr != NULL)
	{
		free(ps->arr);
	}
	ps->arr = NULL;
	ps->top = ps->capacity = 0;
}
//入栈
void STPush(stack* ps, STDataType x)
{
	assert(ps);
	//判断空间是否足够
	if (ps->capacity == ps->top)
	{
		int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
		STDataType* temp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));
		if (temp == NULL)
		{
			perror("realloc");
			exit(1);
		}
		ps->arr = temp;
		ps->capacity = newCapacity;
	}
	//空间足够
	ps->arr[ps->top++] = x;
}
//判断栈是否为空
bool STEmpty(stack* ps)
{
	assert(ps);
	return ps->top == 0;
}
//出栈
void STPop(stack* ps)
{
	assert(!STEmpty(ps));
	ps->top--;
}
//取栈顶数据
STDataType STTop(stack* ps)
{
	assert(!STEmpty(ps));
	return ps->arr[ps->top - 1];
}
//获取栈中有效元素个数
int STSize(stack* ps)
{
	assert(ps);
	return ps->top;
}


typedef struct {
    stack pushST;
    stack popST;
} MyQueue;


MyQueue* myQueueCreate() {
    MyQueue* pq=(MyQueue*)malloc(sizeof(MyQueue));
    STInit(&pq->pushST);
    STInit(&pq->popST);
    return pq;
}

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

int myQueuePop(MyQueue* obj) {
    //从popST里面出数据
    if(STEmpty(&obj->popST))
    {
        while(!STEmpty(&obj->pushST))
        {
            STPush(&obj->popST,STTop(&obj->pushST));
            STPop(&obj->pushST);
        }
    }
    int top=STTop(&obj->popST);
    STPop(&obj->popST);
    return top;
}

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

bool myQueueEmpty(MyQueue* obj) {
    return STEmpty(&obj->pushST)&&STEmpty(&obj->popST);
}

void myQueueFree(MyQueue* obj) {
    STDestroy(&obj->pushST);
    STDestroy(&obj->popST);
    free(obj);
    obj=NULL;
}

/**
 * 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);
*/

4.设计循环队列

这里先介绍一下循环队列:

实际中还有⼀种特殊的队列叫循环队列,环形队列首尾相连成环,环形队列可以使用数组实现,也可以使用循环链表实现。但是考虑到使用的空间大小,还是推荐使用数组来实现循环队列

用数组来实现,所以队列满了的情况就是 (rear+1) % (k + 1)  = front

                                 队列为空的情况就是 rear = front 。

题目链接:

622. 设计循环队列 - 力扣(LeetCode)https://leetcode.cn/problems/design-circular-queue/description/题目描述:

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

  • MyCircularQueue(k): 构造器,设置队列长度为 k 。

  • Front: 从队首获取元素。如果队列为空,返回 -1 。

  • Rear: 获取队尾元素。如果队列为空,返回 -1 。

  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

  • isEmpty(): 检查循环队列是否为空。

  • isFull(): 检查循环队列是否已满。

思路:

typedef struct {
    int* arr;
    int front;
    int rear;
    int capacity;
} MyCircularQueue;

//初始化
MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* pq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    //给arr申请k+1个空间
    pq->arr=(int*)malloc(sizeof(int)*(k+1));
    pq->front=pq->rear=0;
    pq->capacity=k;
    return pq;
}
//向循环队列插入一个元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //队列满了
    if((obj->rear+1)%(obj->capacity+1)==obj->front)
    {
        return false;
    }
    obj->arr[obj->rear++]=value;
    obj->rear=(obj->rear)%(obj->capacity+1);
    return true;
}
//从循环队列中删除一个元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //先检查队列是否为空
    if(obj->front==obj->rear)
    {
        return false;
    }
    obj->front++;
    obj->front=(obj->front)%(obj->capacity+1);
    return true;
}
// /从队首获取元素
int myCircularQueueFront(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return -1;
    }
    return obj->arr[obj->front];
}
//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {
    if(obj->front==obj->rear)
    {
        return -1;
    }
    int prev=obj->rear-1;
    if(obj->rear==0)
    {
        prev=obj->capacity;
    }
    return obj->arr[prev];
}
//检查循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->front==obj->rear;
}
//检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
    return (obj->rear+1)%(obj->capacity+1)==obj->front;
}

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr);
    free(obj);
    obj=NULL;
}

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值