系統性學習數據結構-第三講-棧和隊列
- 1. 棧
- 1.1 棧和隊列
- 1.2 棧的實現
- 2. 隊列
- 2.1 概念與結構
- 2.2 隊列的實現
- 3. 棧和隊列算法題
- 3.1 [有效的括號](https://leetcode.cn/problems/valid-parentheses/description/)
- 3.2 [用隊列實現棧](https://leetcode.cn/problems/implement-stack-using-queues/description/)
- 3.3 [用棧實現隊列](https://leetcode.cn/problems/implement-queue-using-stacks/description/)
1. 棧
1.1 棧和隊列
棧:?種特殊的線性表,其只允許在固定的?端進行插入和刪除元素操作。進行數據插入和刪除操作的?端稱為棧頂,另?端稱為棧底。
棧中的數據元素遵守后進先出 LIFO(Last In First Out)的原則。
壓棧:棧的插入操作叫做進棧/壓棧/入棧,入數據在棧頂。
出棧:棧的刪除操作叫做出棧。出數據也在棧頂。
棧底層結構選型
棧的實現?般可以使用數組或者鏈表實現,相對而言數組的結構實現更優?些。因為數組在尾上插入數據的代價比較小。
1.2 棧的實現
stack. h
typedef int STDataType;
typedef struct Stack
{STDataType* a;int top;int capacity;
}ST;
// 初始化棧
void STInit(ST* ps);
// 銷毀棧
void STDestroy(ST* ps);
// ?棧
void STPush(ST* ps, STDataType x);
//出棧
void STPop(ST* ps);
//取棧頂元素
STDataType STTop(ST* ps);
//獲取棧中有效元素個數
int STSize(ST* ps);
//棧是否為空
bool STEmpty(ST* ps);
Stack.c
#include "Stack.h"void STInit(ST* ps)
{ps->arr = NULL;ps->capacity = ps->top = 0;
}void STDestroy(ST* ps)
{if(ps->arr)free(ps);ps->arr = NULL;ps->capacity = ps->top = 0;
}void StackPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top){int NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* newStack = (STDataType*)realloc(ps->arr, sizeof(STDataType) * NewCapacity);if (newStack == NULL){perror("malloc fail:");exit(1);}ps->arr = newStack;ps->capacity = NewCapacity;}ps->arr[ps->top++] = x;
}void StackPop(ST* ps)
{assert(ps);ps->top--;
}bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}STDataType StackTop(ST* ps)
{assert(ps);return ps->arr[ps->top - 1];
}int STSize(ST* ps)
{assert(ps);return ps->top;
}
2. 隊列
2.1 概念與結構
概念:只允許在?端進行插入數據操作,在另?端進行刪除數據操作的特殊線性表,隊列具有先進先出 FIFO (First In First Out)
?隊列:進行插入操作的?端稱為隊尾
出隊列:進行刪除操作的一端成為隊頭
隊列底層結構選型
隊列也可以數組和鏈表的結構實現,使用鏈表的結構實現更優?些,因為如果使用數組的結構,出隊列在數組頭上出數據,效率會比較低。
2.2 隊列的實現
Queue.h
typedef int QDataType;
//隊列結點結構
typedef struct QueueNode
{int val;struct QueueNode* next;
}QNode;
//隊列結構
typedef struct Queue
{QNode* phead;QNode* ptail;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);
//隊列判空
bool QueueEmpty(Queue* pq);
//隊列有效元素個數
int QueueSize(Queue* pq);
Queue.c
#include"Queue.h"void QueueInit(Queue* pq)
{pq->head = pq->list = NULL;pq->size = 0;
}void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* pcur = pq->head;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->head = pq->list = NULL;
}void QueuePush(Queue* pq, QDataTpe x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc fail:");exit(1);}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->list = newnode;pq->size++;}else{pq->list->next = newnode;pq->size++;pq->list = pq->list->next;}
}bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}void QueuePop(Queue* pq)
{assert(!(QueueEmpty(pq)));if (pq->list == pq->head){free(pq->head);pq->head = pq->list = NULL;}else{QueueNode* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}QDataTpe QueueFront(Queue* pq)
{assert(!(QueueEmpty(pq)));return pq->head->data;
}QDataTpe QueueBack(Queue* pq)
{assert(!(QueueEmpty(pq)));return pq->list->data;
}int QueueSize(Queue* pq)
{return pq->size;
}
3. 棧和隊列算法題
3.1 有效的括號
typedef char StackDateTpye;
typedef struct Stack
{StackDateTpye* arr;int top; //指向棧頂的位置int capacity; //容量
}Stack;
//棧的初始化
void StackInit(Stack* st)
{assert(st);st->arr = NULL;st->capacity = 0;st->top = 0;
}//入棧-棧頂
void StackPush(Stack* st,StackDateTpye data)
{assert(st);if (st->top == st->capacity){int NewCapacity = st->capacity == 0 ? 4 : 2 * st->capacity;StackDateTpye* New = (StackDateTpye*)realloc(st->arr, NewCapacity*sizeof(Stack));if (New == NULL){perror("realloc fail:");exit(1);}st->arr = New; //將數組換到新地址st->capacity = NewCapacity; //將容量更新}st->arr[st->top++] = data; //將棧頂位置更新
}
//判斷棧是否為空
bool StackEmpty(Stack* st)
{assert(st);return st->top == 0;
}//出棧
void StackPop(Stack* st)
{assert(!StackEmpty(st));st->top--;
}//取棧頂數據
StackDateTpye StackTopData(Stack* st)
{assert(!StackEmpty(st));return st->arr[st->top-1];
}void STDestroy(Stack* ps)
{if (ps->arr)free(ps->arr);ps->arr = NULL;ps->top = ps->capacity = 0;
}
//獲取棧中有效元素個數
int StackSize(Stack* st)
{assert(st);return st->top;
}
bool isValid(char* s) {Stack* st=(Stack*)malloc(sizeof(Stack));StackInit(st);while(*s!='\0'){if(*s=='('||*s=='['||*s=='{'){StackPush(st,*s);} else{ if(StackEmpty(st)){STDestroy(st);return false;}if((*s==')'&&StackTopData(st)!='(')||(*s==']'&&StackTopData(st)!='[')||(*s=='}'&&StackTopData(st)!='{')){STDestroy(st);return false;}elseStackPop(st);}s++;}bool ret=StackEmpty(st)?true:false;STDestroy(st);return ret;}
在解答這道題時,我們使用上我們剛剛實現的棧結構,遇見左括號就入棧,遇見右括號就取棧頂與之配對,如果是對應的括號,
那就進行出棧操作,最后對棧進行判空,若為空則為有效的括號。
3.2 用隊列實現棧
typedef int QDataTpe;
typedef struct QueueNode //隊列節點的結構
{QDataTpe data;struct QueueNode* next;
}QueueNode;typedef struct Queue //隊列的結構
{QueueNode* head; //隊頭QueueNode* list; //隊尾int size; //有效數據個數
}Queue;bool QueueEmpty(Queue* pq)
{assert(pq);return pq->size == 0;
}void QueueInit(Queue* pq)
{pq->head = pq->list = NULL;pq->size = 0;
}void QueuePush(Queue* pq, QDataTpe x)
{assert(pq);QueueNode* newnode = (QueueNode*)malloc(sizeof(QueueNode));if (newnode == NULL){perror("malloc fail:");exit(1);}newnode->data = x;newnode->next = NULL;if (pq->head == NULL){pq->head = pq->list = newnode;pq->size++;}else{pq->list->next = newnode;pq->size++;pq->list = pq->list->next;}
}int QueueSize(Queue* pq)
{return pq->size;
}QDataTpe QueueFront(Queue* pq)
{assert(!(QueueEmpty(pq)));return pq->head->data;
}void QueuePop(Queue* pq)
{assert(!(QueueEmpty(pq)));if (pq->list == pq->head){free(pq->head);pq->head = pq->list = NULL;}else{QueueNode* next = pq->head->next;free(pq->head);pq->head = next;}pq->size--;
}QDataTpe QueueBack(Queue* pq)
{assert(!(QueueEmpty(pq)));return pq->list->data;
}void QueueDestroy(Queue* pq)
{assert(pq);QueueNode* pcur = pq->head;while (pcur){QueueNode* next = pcur->next;free(pcur);pcur = next;}pq->head = pq->list = NULL;
}typedef struct {Queue PushQueue;Queue PopQueue;
} MyStack;MyStack* myStackCreate() {MyStack* mystack = (MyStack*)malloc(sizeof(MyStack));QueueInit(&mystack->PushQueue);QueueInit(&mystack->PopQueue);return mystack;
}void myStackPush(MyStack* obj, int x) {QueuePush(&obj->PushQueue, x);
}int myStackPop(MyStack* obj) {while(QueueSize(&obj->PushQueue) != 1){int data = QueueFront(&obj->PushQueue);QueuePop(&obj->PushQueue);QueuePush(&obj->PopQueue, data);}int data = QueueFront(&obj->PushQueue);QueuePop(&obj->PushQueue);while(QueueSize(&obj->PopQueue) != 0){int data = QueueFront(&obj->PopQueue);QueuePop(&obj->PopQueue);QueuePush(&obj->PushQueue, data);}return data;
}int myStackTop(MyStack* obj) {return QueueBack(&obj->PushQueue);
}bool myStackEmpty(MyStack* obj) {if(QueueEmpty(&obj->PushQueue) && QueueEmpty(&obj->PopQueue))return true;elsereturn false;
}void myStackFree(MyStack* obj) {QueueDestroy(&obj->PushQueue);QueueDestroy(&obj->PopQueue);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);
*/
在這道題中,我們創建兩個隊列,棧遵循先進后出的規律,所以僅僅一個隊列是無法完成要求的,定義一個棧為 PushQueue
,
對于入棧的數據我們直接入到這個隊列中,定義一個棧為 PopQueue
,對于出棧操作,我們就將 PushQueue
中除了隊頭的數據,
全部遷移到 PopQueue
中,然后對PushQueue
進行出隊操作, 最后再將 PopQueue
中的數據再遷移回來即可,若要取棧頂元素,
我們就重復上述步驟,但不進行出隊操作即可。
3.3 用棧實現隊列
typedef int STDataType;
typedef struct Stack
{STDataType* arr;int top; //指向棧頂的位置int capacity; //容量
}ST;void STInit(ST* ps)
{ps->arr = NULL;ps->capacity = ps->top = 0;
}void STDestroy(ST* ps)
{if(ps->arr)free(ps);ps->arr = NULL;ps->capacity = ps->top = 0;
}void StackPush(ST* ps, STDataType x)
{assert(ps);if (ps->capacity == ps->top){int NewCapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;STDataType* newStack = (STDataType*)realloc(ps->arr, sizeof(STDataType) * NewCapacity);if (newStack == NULL){perror("malloc fail:");exit(1);}ps->arr = newStack;ps->capacity = NewCapacity;}ps->arr[ps->top++] = x;
}void StackPop(ST* ps)
{assert(ps);ps->top--;
}bool StackEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}STDataType StackTop(ST* ps)
{assert(ps);return ps->arr[ps->top - 1];
}int STSize(ST* ps)
{assert(ps);return ps->top;
}typedef struct {ST PushStack;ST PopStack;
} MyQueue;MyQueue* myQueueCreate() {MyQueue* myQueue = (MyQueue*)malloc(sizeof(MyQueue));STInit(&myQueue->PushStack);STInit(&myQueue->PopStack);return myQueue;
}void myQueuePush(MyQueue* obj, int x) {StackPush(&obj->PushStack, x);
}int myQueuePop(MyQueue* obj) {while(STSize(&obj->PushStack) != 1){int top = StackTop(&obj->PushStack);StackPush(&obj->PopStack, top);StackPop(&obj->PushStack);}int final = StackTop(&obj->PushStack);StackPop(&obj->PushStack);while(STSize(&obj->PopStack) != 0){int top = StackTop(&obj->PopStack);StackPush(&obj->PushStack, top);StackPop(&obj->PopStack);}return final;
}int myQueuePeek(MyQueue* obj) {while(STSize(&obj->PushStack) != 1){int top = StackTop(&obj->PushStack);StackPush(&obj->PopStack, top);StackPop(&obj->PushStack);}int final = StackTop(&obj->PushStack);while(STSize(&obj->PopStack) != 0){int top = StackTop(&obj->PopStack);StackPush(&obj->PushStack, top);StackPop(&obj->PopStack);}return final;
}bool myQueueEmpty(MyQueue* obj) {if(StackEmpty(&obj->PopStack) && StackEmpty(&obj->PushStack))return true;elsereturn false;
}void myQueueFree(MyQueue* obj) {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);
*/
對于用棧實現隊列,我們采用的思路與用隊列實現棧并無太大差別,閱讀代碼即可,在這里不再贅述。