目录
前言
相对于前面学习的链表,栈与队列更加简单,本质上它们都属于线性表。栈的主要特点是后入先出,只能从栈的一端(栈顶)插入和删除元素;队列的主要特点是先入先出,只能从队尾插入元素、队头删除元素。
一、栈
Stack.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <assert.h> typedef int STDataType; typedef struct Stack { STDataType* a; //数组实现栈 int top; int capacity; //动态内存管理 }ST; //初始化 void STInit(ST* pst); //销毁 void STDestroy(ST* pst); //入栈 void STPush(ST* pst, STDataType x); //出栈 void STPop(ST* pst); //取栈顶元素 STDataType STTop(ST* pst); //判断栈空 bool STEmpty(ST* pst); //计算栈的元素个数 int STSize(ST* pst);
Stack.c
#include "Stack.h" void STInit(ST* pst) { assert(pst); pst->a = NULL; //pst->top = -1; // top 指向栈顶数据 pst->top = 0; // top 指向栈顶数据的下一个位置 pst->capacity = 0; } void STDestroy(ST* pst) { assert(pst); free(pst->a); pst->a = NULL; pst->top = pst->capacity = 0; } void STPush(ST* pst, STDataType x) { if (pst->top == pst->capacity) { int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType)); if (tmp == NULL) { perror("realloc fail"); return; } 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]; } bool STEmpty(ST* pst) { assert(pst); /*if (pst->top == 0) { return true; } else { return false; }*/ return pst->top == 0; } int STSize(ST* pst) { assert(pst); return pst->top; }
Test.c
#include "Stack.h" void Test() { ST st; STInit(&st); STPush(&st, 1); STPush(&st, 2); printf("%d ", STTop(&st)); STPop(&st); STPush(&st, 3); STPush(&st, 4); while (!STEmpty(&st)) { printf("%d ", STTop(&st)); STPop(&st); } STDestroy(&st); } int main() { Test(); return 0; }
二、队列
Queue.h
#pragma once #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <stdbool.h> typedef int QDataType; typedef struct QueueNode { struct QueueNode* next; //单链表实现队列 QDataType data; }QNode; typedef struct Queue { QNode* head; QNode* tail; int size; }Queue; //初始化 void QueueInit(Queue* pq); //销毁 void QueueDestroy(Queue* pq); //入队 void QueuePush(Queue* pq, QDataType x); //出队 void QueuePop(Queue* pq); //取队头元素 QDataType QueueFront(Queue* pq); //取队尾元素 QDataType QueueBack(Queue* pq); //计算队列的元素个数 int QueueSize(Queue* pq); bool QueueEmpty(Queue* pq);
Queue.c
#include "Queue.h" void QueueInit(Queue* pq) { assert(pq); pq->head = NULL; pq->tail = NULL; pq->size = 0; } void QueueDestroy(Queue* pq) { assert(pq); QNode* cur = pq->head; while (cur) { QNode* next = cur->next; free(cur); cur = next; } pq->head = pq->tail = NULL; pq->size = 0; } void QueuePush(Queue* pq, QDataType x) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); if (newnode == NULL) { perror("malloc fail\n"); return; } newnode->data = x; newnode->next = NULL; if (pq->tail == NULL) { assert(pq->head == NULL); pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } pq->size++; } void QueuePop(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); if (pq->head->next == NULL) { free(pq->head); pq->head = pq->tail = NULL; } else { Queue* next = pq->head->next; free(pq->head); pq->head = next; } pq->size--; } QDataType QueueFront(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->head->data; } QDataType QueueBack(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->tail->data; } int QueueSize(Queue* pq) { assert(pq); return pq->size; } bool QueueEmpty(Queue* pq) { assert(pq); return pq->size == 0; }
Test.c
#include "Queue.h" void Test() { Queue q; QueueInit(&q); QueuePush(&q, 1); QueuePush(&q, 2); QueuePush(&q, 3); QueuePush(&q, 4); QueuePop(&q); QDataType qnum = QueueFront(&q); printf("%d ", qnum); qnum = QueueBack(&q); printf("%d ", qnum); QueuePop(&q); printf("%d ", QueueFront(&q)); QueuePop(&q); printf("%d ", QueueFront(&q)); QueueDestroy(&q); } int main() { Test(); return 0; }
三、OJ练习
1.用两个栈实现一个队列
用栈实现队列https://leetcode.cn/problems/implement-queue-using-stacks/
typedef int STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST; void STInit(ST* pst); void STDestroy(ST* pst); void STPush(ST* pst, STDataType x); void STPop(ST* pst); STDataType STTop(ST* pst); bool STEmpty(ST* pst); int STSize(ST* pst); void STInit(ST* pst) { assert(pst); pst->a = NULL; //pst->top = -1; // top 指向栈顶数据 pst->top = 0; // top 指向栈顶数据的下一个位置 pst->capacity = 0; } void STDestroy(ST* pst) { assert(pst); free(pst->a); pst->a = NULL; pst->top = pst->capacity = 0; } void STPush(ST* pst, STDataType x) { if (pst->top == pst->capacity) { int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType)); if (tmp == NULL) { perror("realloc fail"); return; } 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]; } bool STEmpty(ST* pst) { assert(pst); /*if (pst->top == 0) { return true; } else { return false; }*/ return pst->top == 0; } int STSize(ST* pst) { assert(pst); return pst->top; } //copy from Stack typedef struct { ST pushst; ST popst; } MyQueue; MyQueue* myQueueCreate() { MyQueue* obj = (MyQueue*)malloc(sizeof(MyQueue)); if(obj == NULL) { perror("malloc fail"); 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); }
2.用两个队列实现一个栈
用队列实现栈https://leetcode.cn/problems/implement-stack-using-queues/
typedef int QDataType; typedef struct QueueNode { struct QueueNode* next; //单链表实现队列 QDataType data; }QNode; typedef struct Queue { QNode* head; QNode* tail; int size; }Queue; //初始化 void QueueInit(Queue* pq); //销毁 void QueueDestroy(Queue* pq); //入队 void QueuePush(Queue* pq, QDataType x); //出队 void QueuePop(Queue* pq); //取队头元素 QDataType QueueFront(Queue* pq); //取队尾元素 QDataType QueueBack(Queue* pq); //计算队列的元素个数 int QueueSize(Queue* pq); bool QueueEmpty(Queue* pq); void QueueInit(Queue* pq) { assert(pq); pq->head = NULL; pq->tail = NULL; pq->size = 0; } void QueueDestroy(Queue* pq) { assert(pq); QNode* cur = pq->head; while (cur) { QNode* next = cur->next; free(cur); cur = next; } pq->head = pq->tail = NULL; pq->size = 0; } void QueuePush(Queue* pq, QDataType x) { assert(pq); QNode* newnode = (QNode*)malloc(sizeof(QNode)); if (newnode == NULL) { perror("malloc fail\n"); return; } newnode->data = x; newnode->next = NULL; if (pq->tail == NULL) { assert(pq->head == NULL); pq->head = pq->tail = newnode; } else { pq->tail->next = newnode; pq->tail = newnode; } pq->size++; } void QueuePop(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); if (pq->head->next == NULL) { free(pq->head); pq->head = pq->tail = NULL; } else { Queue* next = pq->head->next; free(pq->head); pq->head = next; } pq->size--; } QDataType QueueFront(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->head->data; } QDataType QueueBack(Queue* pq) { assert(pq); assert(!QueueEmpty(pq)); return pq->tail->data; } int QueueSize(Queue* pq) { assert(pq); return pq->size; } bool QueueEmpty(Queue* pq) { assert(pq); return pq->size == 0; } //copy from Queue typedef struct { Queue q1; Queue q2; } MyStack; MyStack* myStackCreate() { MyStack* obj = (MyStack*)malloc(sizeof(MyStack)); if(obj == NULL) { perror("malloc fail"); return NULL; } 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* pQEmpty = &obj->q1; Queue* pQNonEmpty = &obj->q2; if(!QueueEmpty(&obj->q1)) { pQEmpty = &obj->q2; pQNonEmpty = &obj->q1; } while(QueueSize(pQNonEmpty) > 1) { QueuePush(pQEmpty, QueueFront(pQNonEmpty)); QueuePop(pQNonEmpty); } int top = QueueFront(pQNonEmpty); QueuePop(pQNonEmpty); return top; } int myStackTop(MyStack* obj) { if(!QueueEmpty(&obj->q1)) { return QueueBack(&obj->q1); } else { return QueueBack(&obj->q2); } } bool myStackEmpty(MyStack* obj) { return QueueEmpty(&obj->q1) && QueueEmpty(&obj->q2); } void myStackFree(MyStack* obj) { QueueDestroy(&obj->q1); QueueDestroy(&obj->q2); free(obj); }
3.括号匹配
有效的括号https://leetcode.cn/problems/valid-parentheses/
typedef char STDataType; typedef struct Stack { STDataType* a; int top; int capacity; }ST; void STInit(ST* pst); void STDestroy(ST* pst); void STPush(ST* pst, STDataType x); void STPop(ST* pst); STDataType STTop(ST* pst); bool STEmpty(ST* pst); int STSize(ST* pst); void STInit(ST* pst) { assert(pst); pst->a = NULL; //pst->top = -1; // top 指向栈顶数据 pst->top = 0; // top 指向栈顶数据的下一个位置 pst->capacity = 0; } void STDestroy(ST* pst) { assert(pst); free(pst->a); pst->a = NULL; pst->top = pst->capacity = 0; } void STPush(ST* pst, STDataType x) { if (pst->top == pst->capacity) { int newCapacity = pst->capacity == 0 ? 4 : pst->capacity * 2; STDataType* tmp = (STDataType*)realloc(pst->a, newCapacity * sizeof(STDataType)); if (tmp == NULL) { perror("realloc fail"); return; } 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]; } bool STEmpty(ST* pst) { assert(pst); return pst->top == 0; } int STSize(ST* pst) { assert(pst); return pst->top; } //end of cv bool isValid(char * s){ ST st; STInit(&st); while(*s) { if(*s == '(' || *s == '[' || *s == '{') { STPush(&st, *s); } else { if(STEmpty(&st)) { STDestroy(&st); return false; } char top = STTop(&st); STPop(&st); if((*s == ')' && top != '(') || (*s == ']' && top != '[') || (*s == '}' && top != '{')) { STDestroy(&st); return false; } } s++; } bool ret = STEmpty(&st); STDestroy(&st); return ret; } 主要思想:遇到左括号入栈,遇到右括号出栈顶元素与之配对 本题需要我们考虑到一些特殊的情况: 1.只存在左括号 2.只存在右括号 3.左右括号数目匹配,但是样式不匹配 4.括号匹配结束后,栈不为空(有的左括号没有被匹配)
4.设计循环队列
设计循环队列https://leetcode.cn/problems/design-circular-queue/
循环队列 可以采用数组实现,也可以采用链表实现 注意判断循环队列满和空的条件 typedef struct { int front; int rear; int k; int* a; } MyCircularQueue; MyCircularQueue* myCircularQueueCreate(int k) { MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue)); if(obj == NULL) { perror("malloc(obj) fail"); return NULL; } obj->a = (int*)malloc(sizeof(int)*(k+1)); if(obj->a == NULL) { perror("malloc(a) fail"); return NULL; } 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); }