
很显然,本篇文章的标题出卖了这道题,我们将使用栈来解决这道题。对于栈和队列,C 语言的库中并没有这两个数据结构,但在 C++ 的库中是可以直接使用这两种数据结构的。局限于目前我们只会使用 C 语言,所以在解这道题时,需要做一个前置工作,就是将我们写好的栈复制过来。这里我给出了上一篇关于栈和队列实现的代码。
- //可以动态开辟空间的栈
- typedef char StackData;//注意是字符元素
- typedef struct Stack
- {
- StackData* a;
- int top;//与顺序表的 size 一致
- int capacity;
- }Stack;
-
- void StackInit(Stack* ps);//栈初始化
- void StackPush(Stack* ps,StackData x);//入栈
- void StackPop(Stack* ps);//出栈
- StackData StackTop(Stack* ps);//获取栈顶元素
- bool StackEmpty(Stack* ps);//判断栈是否为空
- int StackSize(Stack* ps);//计算栈元素个数
- void StackDestroy(Stack* ps);//栈销毁
-
- //初始化栈
- void StackInit(Stack* ps)
- {
- assert(ps);
- //栈的初始容量置空
- ps->a = NULL;
- ps->top = ps->capacity = 0;
- }
- //入栈
- void StackPush(Stack* ps,StackData x)
- {
- assert(ps);
- //入栈只有一种方式,所以不需要将扩容独立封装
- if (ps->top == ps->capacity)
- {
- int NewCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
- StackData* tmp = (StackData*)realloc(ps->a, NewCapacity*sizeof(StackData));
- assert(tmp);
- ps->a = tmp;
- ps->capacity = NewCapacity;
- }
- ps->a[ps->top] = x;
- ps->top++;
- }
- //出栈
- void StackPop(Stack* ps)
- {
- assert(ps);
- assert(!StackEmpty(ps));
- ps->top--;
- }
- //获取栈顶元素
- StackData StackTop(Stack* ps)
- {
- assert(ps);
- return ps -> a[ps->top - 1];
- }
- //判断栈是否为空
- bool StackEmpty(Stack* ps)
- {
- assert(ps);
- return ps->top == 0;//等于 0 则返回true,即栈为空
- }
- //计算栈中元素个数
- int StackSize(Stack* ps)
- {
- assert(ps);
- return ps->top;
- }
- //栈销毁
- void StackDestroy(Stack* ps)
- {
- assert(ps);
- free(ps->a);
- ps->a = NULL;
- ps->top = ps->capacity = 0;
- }
做好了前置工作之后现在我们就要试着来解题。我们来分析一下思路:

我们将它们转换为代码:
- bool isValid(char * s){
- Stack st;
- StackInit(&st);
- while(*s)
- {
- if(*s == '(' || *s == '[' || *s == '{')
- {
- StackPush(&st,*s);
- }
- else
- {
- //如果没有一个左括号入栈
- if(StackEmpty(&st))
- {
- StackDestroy(&st);
- return false;
- }
- else
- {
- char top = StackTop(&st);
- StackPop(&st);
- //如果有任何不满足匹配的情况就返回 false
- if(*s == ')' && top == '(' ||
- *s == ']' && top == '[' ||
- *s == '}' && top == '{')
- {
- StackDestroy(&st);
- return false;
- }
- }
- }
- s++;
- }
- //如果括号匹配的话,那么栈中就应该没有任何元素
- //这个例子见于字符串中全是左括号,没有满足任何匹配条件,就不会出栈
- //不会出栈就会导致栈中有元素,即不为空
- bool flag = StackEmpty(&st);
- StackDestroy(&st);
- return flag;
- }
-

注意看题,题目的要求是让我们用两个队列来实现栈。那么现在就要搞清楚队列转化为栈的难点是什么。队列的特征是先进先出,如果我们入队的数据是 1、2、3、4、5 ,那么出队的顺序也是 1、2、3、4、5 。而栈的特征是先进后出,即我们入栈的数据是 1、2、3、4、5,那么出栈的顺序是 5、4、3、2、1 。由此可见入队和入栈的方式一样,差别在于出队和出栈的顺序不同。我们需要解决的便是出的问题,还有就是删除的问题。
我们知道,我们实现队列的数据结构是链表。题目的要求是让我们使用两个队列,两个队列如何实现获取队尾元素和尾删呢?

我们拿出我们使用链表实现队列的代码,并将它复制到我们的题目上面去。
- //链表的结点
- typedef int QueueData;
- typedef struct QueueNode
- {
- QueueData val;
- struct QueueNode* next;
- }QueueNode;
- //存储头、尾结点地址的指针
- typedef struct HeadTail
- {
- QueueNode* head;
- QueueNode* tail;
- int size;//记录队列有几个元素
- }HeadTail;
-
- void QueueInit(HeadTail* p);//初始化队列
- void QueuePush(HeadTail* p,QueueData x);//进入队列
- QueueData QueueHead(HeadTail* p);//获取队头元素
- QueueData QueueTail(HeadTail* p);//获取队尾元素
- void QueuePop(HeadTail* p);//删除操作,出队
- bool QueueEmpty(HeadTail* p);//检查队列是否为空
- int QueueSize(HeadTail* p);//获取队列元素个数
- void QueuePopTail(HeadTail* p);
- void QueueDestroy(HeadTail* p);//销毁队列
-
- //初始化
- void QueueInit(HeadTail* p)
- {
- assert(p);
- p->head = p->tail = NULL;
- p->size = 0;
- }
- //队列尾插
- void QueuePush(HeadTail* p, QueueData x)
- {
- assert(p);
- //创建一个新结点
- QueueNode* newnode = (QueueNode*)calloc(1, sizeof(QueueNode));
- assert(newnode);
- newnode->val = x;
- newnode->next = NULL;
- //如果链表内没有结点,头尾指针指向同一个结点
- if (p->head == NULL)
- {
- p->head = newnode;
- p->tail = newnode;
- }
- //否则尾指针需要变化
- else
- {
- p->tail->next = newnode;
- p->tail = newnode;
- }
- p->size++;
- }
- //获取队头元素
- QueueData QueueHead(HeadTail* p)
- {
- assert(p);
- assert(!QueueEmpty(p));
- return p->head->val;
- }
- //获取队尾元素
- QueueData QueueTail(HeadTail* p)
- {
- assert(p);
- assert(!QueueEmpty(p));
- return p->tail->val;
- }
- //删除、出队
- void QueuePop(HeadTail* p)
- {
- assert(p);
- assert(!QueueEmpty(p));
- //如果链表只有一个结点
- if (p->head == p->tail)
- {
- free(p->head);
- p->head = p->tail = NULL;
- }
- //否则进行头删
- else
- {
- QueueNode* cur = p->head;
- p->head = p->head->next;
- free(cur);
- cur = NULL;
- }
- p->size--;
- }
- //检测队列是否为空
- bool QueueEmpty(HeadTail* p)
- {
- assert(p);
- return p->head == NULL && p->tail == NULL;
- }
- //获取队列元素个数
- int QueueSize(HeadTail* p)
- {
- assert(p);
- return p->size;
- }
- //销毁队列
- void QueueDestroy(HeadTail* p)
- {
- assert(p);
- QueueNode* cur = p->head;
- while (cur)
- {
- QueueNode* del = cur;
- cur = cur->next;
- free(del);
- }
- }
-
- typedef struct {
- HeadTail q1;
- HeadTail q2;
- } MyStack;
-
-
- MyStack* myStackCreate() {
- MyStack* obj = (MyStack*)calloc(1,sizeof(MyStack));
- //取 q1、q2 的地址传入函数
- 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) {
- //如果q1为空,将q2的size-1个倒入q1
- //并将q2剩下的最后一个当成栈顶元素返回
- if(QueueEmpty(&obj->q1))
- {
- while(QueueSize(&obj->q2) > 1)
- {
- QueuePush(&obj->q1,QueueHead(&obj->q2));
- QueuePop(&obj->q2);
- }
- int ret = QueueTail(&obj->q2);
- QueuePop(&obj->q2);
- return ret;
- }
- //如果q2为空,将q1的size-1个倒入q2
- //并将q1剩下的最后一个当成栈顶元素返回
- else
- {
- while(QueueSize(&obj->q1) > 1)
- {
- QueuePush(&obj->q2,QueueHead(&obj->q1));
- QueuePop(&obj->q1);
- }
- int ret = QueueTail(&obj->q1);
- QueuePop(&obj->q1);
- return ret;
- }
-
- }
-
- int myStackTop(MyStack* obj) {
- //这个函数并没有要求要删除数据
- //所以直接返回非空队列的队尾元素
- if(!QueueEmpty(&obj->q1))
- {
- return QueueTail(&obj->q1);
- }
- else
- {
- return QueueTail(&obj->q2);
- }
- }
-
- bool myStackEmpty(MyStack* obj) {
- return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2);
- }
-
- void myStackFree(MyStack* obj) {
- //obj里面存放的只是q1、q2空间的地址
- //所以需要独立释放q1、q2空间
- QueueDestroy(&obj->q1);
- QueueDestroy(&obj->q2);
- free(obj);
- }

这里的题目要求是用两个栈实现队列,那么肯定是要涉及倒数据的。我们现在来具体分析如何倒数据。

我们将我们实现栈的数据结构的代码复制到题目中去:
- //可以动态开辟空间的栈
- typedef int StackData;
- typedef struct Stack
- {
- StackData* a;
- int top;//与顺序表的 size 一致
- int capacity;
- }Stack;
-
- void StackInit(Stack* ps);//栈初始化
- void StackPush(Stack* ps,StackData x);//入栈
- void StackPop(Stack* ps);//出栈
- StackData StackTop(Stack* ps);//获取栈顶元素
- bool StackEmpty(Stack* ps);//判断栈是否为空
- int StackSize(Stack* ps);//计算栈元素个数
- void StackDestroy(Stack* ps);//栈销毁
-
- //初始化栈
- void StackInit(Stack* ps)
- {
- assert(ps);
- //栈的初始容量置空
- ps->a = NULL;
- ps->top = ps->capacity = 0;
- }
- //入栈
- void StackPush(Stack* ps,StackData x)
- {
- assert(ps);
- //入栈只有一种方式,所以不需要将扩容独立封装
- if (ps->top == ps->capacity)
- {
- int NewCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
- StackData* tmp = (StackData*)realloc(ps->a, NewCapacity*sizeof(StackData));
- assert(tmp);
- ps->a = tmp;
- ps->capacity = NewCapacity;
- }
- ps->a[ps->top] = x;
- ps->top++;
- }
- //出栈
- void StackPop(Stack* ps)
- {
- assert(ps);
- assert(!StackEmpty(ps));
- ps->top--;
- }
- //获取栈顶元素
- StackData StackTop(Stack* ps)
- {
- assert(ps);
- return ps -> a[ps->top - 1];
- }
- //判断栈是否为空
- bool StackEmpty(Stack* ps)
- {
- assert(ps);
- return ps->top == 0;//等于 0 则返回true,即栈为空
- }
- //计算栈中元素个数
- int StackSize(Stack* ps)
- {
- assert(ps);
- return ps->top;
- }
- //栈销毁
- void StackDestroy(Stack* ps)
- {
- assert(ps);
- free(ps->a);
- ps->a = NULL;
- ps->top = ps->capacity = 0;
- }
- typedef struct {
- Stack push;
- Stack pop;
- } MyQueue;
-
-
- MyQueue* myQueueCreate() {
- MyQueue* obj = (MyQueue*)calloc(1,sizeof(MyQueue));
- StackInit(&obj->push);
- StackInit(&obj->pop);
- return obj;
- }
-
- void myQueuePush(MyQueue* obj, int x) {
- //只向push栈插入数据
- StackPush(&obj->push,x);
- }
-
- int myQueuePop(MyQueue* obj) {
- //要向pop栈中倒入数据
- if(StackEmpty(&obj->pop))
- {
- while(!StackEmpty(&obj->push))
- {
- StackPush(&obj->pop,StackTop(&obj->push));
- StackPop(&obj->push);
- }
- }
- int ret = StackTop(&obj->pop);
- StackPop(&obj->pop);
- return ret;
- }
-
- int myQueuePeek(MyQueue* obj) {
- //只有向pop栈倒入数据才能取到最先进去的那个元素
- if(StackEmpty(&obj->pop))
- {
- while(!StackEmpty(&obj->push))
- {
- StackPush(&obj->pop,StackTop(&obj->push));
- StackPop(&obj->push);
- }
- }
- return StackTop(&obj->pop);
- }
-
- bool myQueueEmpty(MyQueue* obj) {
- return StackEmpty(&obj->push) && StackEmpty(&obj->pop);
- }
-
- void myQueueFree(MyQueue* obj) {
- StackDestroy(&obj->push);
- StackDestroy(&obj->pop);
- free(obj);
- }

我们先不关注题目的要求,就单单循环队列而言,我们先选择合适的数据结构。
我们有两种数据结构可选,一是链表,而是顺序表。那么那种数据结构优势较大呢?首先我们来看看循环队列是什么。

那么其次,我们把这个逻辑结构套到两种数据结构上面去。

有了上面的分析基础,现在就可以尝试去解题了。
- typedef struct {
- int* a;
- int head;//头
- int tail;//尾
- int size;//长度
- } MyCircularQueue;
-
-
- MyCircularQueue* myCircularQueueCreate(int k) {
- MyCircularQueue* obj = (MyCircularQueue*)calloc(1,sizeof(MyCircularQueue));
- obj->a = (int*)calloc(1,sizeof(int)*(k+1));//顺序表的空间多开一个
- obj->head = obj->tail = 0;
- obj->size=k+1;
- return obj;
- }
-
- bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
- return obj->head == obj->tail;
- }
-
- bool myCircularQueueIsFull(MyCircularQueue* obj) {
- return (obj->tail+1)%obj->size == obj->head;
- }
-
- bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
- if(myCircularQueueIsFull(obj))
- return false;
- obj->a[obj->tail]=value;
- obj->tail++;
- obj->tail %= obj->size;//确保tail的值不会超过长度范围
- return true;
- }
-
- bool myCircularQueueDeQueue(MyCircularQueue* obj) {
- if(myCircularQueueIsEmpty(obj))
- return false;
- obj->head++;
- obj->head %= obj->size;//确保head的值不会超过长度范围
- return true;
- }
-
- int myCircularQueueFront(MyCircularQueue* obj) {
- if(myCircularQueueIsEmpty(obj))
- return -1;
- return obj->a[obj->head];
- }
-
- int myCircularQueueRear(MyCircularQueue* obj) {
- if(myCircularQueueIsEmpty(obj))
- return -1;
- //推导的公式,以防tail的值为 0
- return obj->a[(obj->tail-1+obj->size)%obj->size];
- }
-
-
-
- void myCircularQueueFree(MyCircularQueue* obj) {
- free(obj->a);
- free(obj);
- }