目录
- 前言
- 有效的括号
- 思路分析
- 代码实现
- 用队列实现栈
- 思路分析
- 代码实现
- 用栈实现队列
- 思路分析
- 代码实现
- 设计循环队列
- 思路分析
- 代码实现
前言
本篇文章将对部分栈和队列综合运用题进行讲解,以对栈和队列有一个更深层次的理解。
有效的括号
先来看题
思路分析
这里我们采取的方法是将左括号入栈,右括号与栈顶的括号进行比较,如果不匹配,则返回false,当所有括号匹配完则返回true。
但是,这里最后几个测试用例会设置各种各样的坑。
1. 我们在每次取栈顶元素时首先要判空,如果为空则返回false。
2. 在将所有的左括号匹配完后,还需对栈判空,如果不为空,说明还有右括号没有匹配,则返回false。
3. 在取出栈顶元素后别忘了将其删除(pop)。
代码实现
由于代码是c语言版本,必须要自己创建一个栈,所以代码可能会有些冗长。
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int Capacity;
}ST;
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->Capacity = 0;
pst->top = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->Capacity = 0;
pst->top = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
if (pst->Capacity == pst->top)
{
int newCapacity = pst->Capacity == 0 ? 4 : pst->Capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
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(!STEmpty(pst));
pst->top--;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
bool isValid(char * s){
ST pst;
STInit(&pst);
int len=strlen(s);
if(len%2==1)
return false;
for(int i=0;i<len;i++)
{
if(s[i]=='('||s[i]=='['||s[i]=='{')
{
STPush(&pst,s[i]);
}
else
{
if(s[i]==')')
{
if(!STEmpty(&pst))
{
char ch = STTop(&pst);
STPop(&pst);
if(ch!='(')
return false;
}
else
return false;
}
if(s[i]==']')
{
if(!STEmpty(&pst))
{
char ch = STTop(&pst);
STPop(&pst);
if(ch!='[')
return false;
}
else
return false;
}
if(s[i]=='}')
{
if(!STEmpty(&pst))
{
char ch = STTop(&pst);
STPop(&pst);
if(ch!='{')
return false;
}
else
return false;
}
}
}
if(!STEmpty(&pst))
{
return false;
}
return true;
}
用队列实现栈
先来看题
思路分析
这道题的主体思路就是用两个队列queue1、queue2,先将元素存入queue2,要出栈时将queue2中的元素出队列存入queue1中,剩下一个queue2得队尾元素用于出栈即可。
若不是第一次出栈,则将queue1中的元素出队列存入queue2中,剩下一个queue1得队尾元素用于出栈即可。
代码实现
typedef int QDataType;
typedef struct QueueNode
{
struct QueueNode* next;
QDataType data;
}QNode;
typedef struct Queue
{
QNode* phead;
QNode* ptail;
int size;
}Queue;
bool QueueEmpty(Queue* pq)
{
assert(pq);
return pq->size == 0;
}
void QueueInit(Queue* pq)
{
assert(pq);
pq->phead = pq->ptail = NULL;
pq->size = 0;
}
void QueueDestroy(Queue* pq)
{
assert(pq);
//先删节点
QNode* cur = pq->phead;
while (cur)
{
QNode* next = cur->next;
free(cur);
cur = next;
}
//再删头尾指针
pq->phead = NULL;
pq->ptail = NULL;
pq->size = 0;
}
void QueuePush(Queue* pq, QDataType x)
{
assert(pq);
QNode* newnode = (QNode*)malloc(sizeof(QNode));
if (newnode == NULL)
{
perror("malloc fail");
return;
}
newnode->data = x;
newnode->next = NULL;
if (pq->ptail == NULL)
{
assert(pq->phead == NULL);
pq->phead = pq->ptail = newnode;
}
else
{
pq->ptail->next = newnode;
pq->ptail = newnode;
}
pq->size++;
}
void QueuePop(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
if (pq->phead->next == NULL)
{
free(pq->phead);
pq->phead = pq->ptail = NULL;
}
else
{
QNode* next = pq->phead->next;
free(pq->phead);
pq->phead = next;
}
pq->size--;
}
QDataType QueueFront(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->phead->data;
}
QDataType QueueBack(Queue* pq)
{
assert(pq);
assert(!QueueEmpty(pq));
return pq->ptail->data;
}
int QueueSize(Queue* pq)
{
assert(pq);
return pq->size;
}
typedef struct {
Queue q1;
Queue q2;
} MyStack;
MyStack* myStackCreate() {
MyStack* obj=(MyStack*)malloc(sizeof(MyStack));
if(obj==NULL)
{
perror("malloc fail\n");
}
QueueInit(&obj->q1);
QueueInit(&obj->q2);
return obj;
}
void myStackPush(MyStack* obj, int x) {
if(!QueueEmpty(&obj->q1))
QueuePush(&obj->q1,x);
else
QueuePush(&obj->q2,x);
}
int myStackPop(MyStack* obj) {
Queue* EmptyQueue=&obj->q1;
Queue* NonEmptyQueue=&obj->q2;
if(!QueueEmpty(&obj->q1))
{
EmptyQueue=&obj->q2;
NonEmptyQueue=&obj->q1;
}
while(QueueSize(NonEmptyQueue)>1)
{
QueuePush(EmptyQueue,QueueFront(NonEmptyQueue));
QueuePop(NonEmptyQueue);
}
int top=QueueFront(NonEmptyQueue);
QueuePop(NonEmptyQueue);
return top;
}
int myStackTop(MyStack* obj) {
if(QueueEmpty(&obj->q1))
return QueueBack(&obj->q2);
else
return QueueBack(&obj->q1);
}
bool myStackEmpty(MyStack* obj) {
return QueueEmpty(&obj->q1)
&& QueueEmpty(&obj->q2);
}
void myStackFree(MyStack* obj) {
QueueDestroy(&obj->q1);
QueueDestroy(&obj->q2);
free(obj);
}
用栈实现队列
先看题
思路分析
主体思路就是将其中一个栈用于放入,另一个栈用于取出,每次出栈元素顺序都会翻转,出栈一次正好和队列顺序相匹配。
注意: 在返回队列开头元素时,应先判断用于取出的栈是否为空,若不为空,则直接将栈顶元素取出即可,若为空,则将用于放入的栈元素全部放入用于取出的栈,再返回栈顶元素。
代码实现
typedef int STDataType;
typedef struct Stack
{
STDataType* a;
int top;
int Capacity;
}ST;
bool STEmpty(ST* pst)
{
assert(pst);
return pst->top == 0;
}
void STInit(ST* pst)
{
assert(pst);
pst->a = NULL;
pst->Capacity = 0;
pst->top = 0;
}
void STDestroy(ST* pst)
{
assert(pst);
free(pst->a);
pst->a = NULL;
pst->Capacity = 0;
pst->top = 0;
}
void STPush(ST* pst, STDataType x)
{
assert(pst);
if (pst->Capacity == pst->top)
{
int newCapacity = pst->Capacity == 0 ? 4 : pst->Capacity * 2;
STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType));
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(!STEmpty(pst));
pst->top--;
}
STDataType STTop(ST* pst)
{
assert(pst);
assert(!STEmpty(pst));
return pst->a[pst->top - 1];
}
int STSize(ST* pst)
{
assert(pst);
return pst->top;
}
typedef struct {
ST pushst;//放
ST popst;//取
} MyQueue;
MyQueue* myQueueCreate() {
MyQueue* obj=(MyQueue*)malloc(sizeof(MyQueue));
if(obj==NULL)
{
perror("malloc fail\n");
return NULL;
}
STInit(&obj->pushst);
STInit(&obj->popst);
return obj;
}
void myQueuePush(MyQueue* obj, int x) {
STPush(&obj->pushst,x);
}
int myQueuePop(MyQueue* obj) {
int front=myQueuePeek(obj);
STPop(&obj->popst);
return front;
}
int myQueuePeek(MyQueue* obj) {
if(STEmpty(&obj->popst))
{
while(!STEmpty(&obj->pushst))
{
STPush(&obj->popst,STTop(&obj->pushst));
STPop(&obj->pushst);
}
}
return STTop(&obj->popst);
}
bool myQueueEmpty(MyQueue* obj) {
return STEmpty(&obj->pushst)&&STEmpty(&obj->popst);
}
void myQueueFree(MyQueue* obj) {
STDestroy(&obj->pushst);
STDestroy(&obj->popst);
free(obj);
}
设计循环队列
先看题
思路分析
我们首先要考虑一个问题,如何区分满和空?
当队列满或空时,rear和front的下标相同。
为了解决这个问题,我们考虑增加一个空间,不存储任何数据,如果rear+1等于front则满。
在解决这个问题以后,我们再来看其他操作,
假设循环队列存储5个数据,则我们先开辟六个空间。
此时rear==front为空。
那么此时我们该如何判满呢?
比如当front为0,rear为5,此时队列满了,又或者是当rear是2,front是3,此时又满了,似乎只要满足rear+1=front即可,但我们仔细想这样一个问题,数组又没法像链表那样,可以直接从尾部找到头部,所以数组下标如果超出了存储空间,我们取模即可让下标又从头开始往后走,
如何插入数据呢?
这个很简单,只需将值放入下标为rear的位置,再将rear++即可,注意如果超出范围,则需取模,由于小于最大范围取模还是等于它本身,我们干脆每次都取模。
如何删除数据?
我们只需将front++即可,同样要取模。
如何获取队首元素?
很简单,直接返回下标为front的元素即可。
如何获取队尾元素?
队尾元素即为rear前一个下标对应的元素,但存在特殊情况,假设此时rear指向了5,我们应该返回4,如果指向0,应该返回5,但5-1=4,0-1很显然不等于5,所以我们还是考虑用取模的方法,这里直接给出公式了
(rear+k)%(k+1).
代码实现
typedef struct {
int front;
int rear;
int k;
int* a;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int*)malloc(sizeof(int)*(k+1));
obj->front=obj->rear=0;
obj->k=k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front==obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->k+1)==obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->rear]=value;
obj->rear++;
obj->rear%=(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front%=(obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
以上就是本篇文章全部内容,如有出入,欢迎指正。