系統性學習數據結構-第三講-棧和隊列

系統性學習數據結構-第三講-棧和隊列

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

對于用棧實現隊列,我們采用的思路與用隊列實現棧并無太大差別,閱讀代碼即可,在這里不再贅述。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:
http://www.pswp.cn/news/921337.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/921337.shtml
英文地址,請注明出處:http://en.pswp.cn/news/921337.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

硬件(三) 通信方式、串口通信

一、通信類型(一)并行通信多個比特通過并行線同時傳輸,傳輸速率快,但會大量占用芯片資源,在對資源敏感的場景下不太適用。(二)串行通信把數據拆成單個比特,按順序在一根總線上發送。…

vsan default storage policy 具體是什么策略?

vSAN Default Storage Policy(vSAN 默認存儲策略)是 VMware vSAN 部署后自動創建的基礎存儲策略,其核心目標是在“通用性”和“可靠性”之間取得平衡,為大多數虛擬機提供默認的數據保護和存儲服務,無需管理員手動創建策…

雨后陽光為何更強烈?

1. 降雨后的輻射是否會增強一般來說,降雨時天空多云,云層對太陽輻射有強烈削弱作用,所以降雨時的短波輻射顯著下降。但雨后,空氣濕度大、顆粒物被沖刷、天空轉晴時,大氣透明度會提高,短波輻射相較于降雨前往…

美團發布 | LongCat-Flash最全解讀,硬剛GPT-4.1、Kimi!

一、導讀 本報告解析了美團LongCat團隊推出的LongCat-Flash模型,一個擁有5600億參數的混合專家模型(Mixture-of-Experts, MoE)。面對大規模語言模型在計算資源和效率上的挑戰,LongCat-Flash旨在實現計算效率與高級智能體&#xf…

Ubuntu 18.04 上升級 gcc 到 9.4

18.04 默認的源中可能沒有 GCC-9.3 或更新版本,在終端運行以下命令來添加 PPA: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt update2.安裝 GCC 和 G sudo apt install gcc-9 g-93.更新替代版本 如果系統中安裝了多個 GCC 版本&#x…

.NET GcPDF V8.2 新版本:人工智能 PDF 處理

一、GcPDF 產品簡介 GcPDF(GrapeCity Documents for PDF)是葡萄城(GrapeCity)推出的一款功能強大的 .NET PDF 開發組件,旨在為開發人員提供高效、靈活的 PDF 文檔處理解決方案。無論是創建全新 PDF 文檔、編輯現有 PD…

解鎖桐果云零代碼數據平臺能力矩陣——賦能零售行業數字化轉型新動能

在零售行業從“規模擴張”轉向“精細運營”的當下,數據已成為優化庫存、精準營銷、防控風險的核心抓手。但多數零售企業仍面臨“數據雜亂難治理、分析建模門檻高、場景適配性不足”等難題,導致大量訂單、商品、交易數據沉睡,難以轉化為經營決…

rabbitmq 入門知識點

RabbitMQ 是一個 消息隊列中間件(Message Broker),實現了 AMQP 協議,常用于服務之間解耦、異步處理、流量削峰等場景。 我幫你分成兩個部分來講:核心原理 常見用法。🧩 一、核心原理 RabbitMQ 的核心是 生…

點控云智能客服:以AI重塑服務體驗,登頂行業第一的革新之路

在數字化浪潮席卷全球的今天,客戶服務已成為企業核心競爭力之一。智能客服作為連接企業與客戶的重要橋梁,其效能與體驗直接關系到企業的品牌形象與市場口碑。近日,權威機構發布的《中國智能客服市場競爭力報告》顯示,點控云智能客…

9.5 IO-線程day5

信號量打印ABC#include <stdio.h> #include <string.h> #include <stdlib.h> #include <25061head.h> sem_t sem[1]; void *callback(void *arg) {while(1){sem_wait(&sem[0]);printf("A\n");sleep(1);sem_post(&sem[1]);}pthread_e…

老師如何高效收集學生學籍信息,完成收集工作?

開學的時光總是忙碌而充實&#xff0c;除了要熱情地迎接新生、用心地備課&#xff0c;還有一件讓人頭疼不已的事情——學生學籍信息的收集。上學期開學&#xff0c;我承擔起了收集班級新生信息的重任&#xff0c;滿心以為提前準備好的紙質表格&#xff0c;在新生報到那天發給家…

JAVA層的權限與SELinux的關系

Java 層權限是應用程序級別的“門禁卡”&#xff0c;而 SELinux 是系統級別的“防火墻規則和強制訪問控制”。即使你擁有進入大樓的“門禁卡”&#xff08;Java 權限&#xff09;&#xff0c;如果“防火墻規則”&#xff08;SELinux 策略&#xff09;不允許你的進程與目標服務或…

Screen 三步上手

好的&#xff0c;這是給同事的簡潔版說明&#xff1a;Screen 三步上手 開新窗口&#xff1a;干活前先開個帶名字的窗口&#xff0c;不怕斷連。 screen -S 任務名看所有窗口&#xff1a;隨時查看都有哪些任務在后臺跑。 screen -ls重回窗口&#xff1a;斷連后重新登錄&#xff0…

flink 偽代碼

import java.util.*; import java.util.concurrent.*;// 核心接口定義 interface StreamOperator {void open();void processElement(Object element);void close(); }interface SourceFunction extends StreamOperator {void run(SourceContext ctx); }interface SinkFunction…

一招快速識別你的電腦是機械硬盤還是固態硬盤

你是否經常覺得電腦開機慢、軟件打開卡頓&#xff1f;其中一個關鍵原因&#xff0c;可能就在于你使用的是機械硬盤&#xff08;HDD&#xff09;還是固態硬盤&#xff08;SSD&#xff09;。固態硬盤讀寫速度快&#xff0c;能顯著提升系統響應速度&#xff1b;而機械硬盤雖然容量…

52核心52線程,Intel下一代CPU憋了個大的

被逼急了的 Intel&#xff0c;可能正在憋大招&#xff01;如大伙兒所見&#xff0c;Intel 這兩年日子已經不能用「慘」來形容。其過去引以為傲的 PC 處理器&#xff0c;特別是高性能桌面處理器領域&#xff0c;如今算是徹底被 AMD 打懵了。無他&#xff0c;己方產品是連年擺爛&…

【LeetCode 熱題 100】1. 兩數之和——(解法二)哈希表

Problem: 1. 兩數之和 文章目錄整體思路完整代碼時空復雜度時間復雜度&#xff1a;O(N)空間復雜度&#xff1a;O(N)整體思路 這段代碼旨在高效地解決 “兩數之和” 問題。與 O(N^2) 的暴力枚舉法相比&#xff0c;此版本采用了一種經典的 “空間換時間” 策略&#xff0c;利用 …

MySQL主從同步--主從復制進階

MySQL支持一臺主庫同時向多臺從庫進行復制&#xff0c;從庫同時也可以作為其他從服務器的主庫&#xff0c;實現鏈狀復制。1、MySQL支持的binlog二進制日志復制類型- 基于語句&#xff08;statement&#xff09;的復制在主服務器上執行SQL語句&#xff0c;在從服務器上執行同樣的…

WPF外部打開html文件

注意&#xff1a;這是一份提供WPF外部瀏覽器打開html的方法&#xff0c;而不是WPF內部嵌入html 需要通過瀏覽器打開&#xff0c;否則無法使用地址欄拼接參數的形式操作html 下面是打開html的方法↓string localHtmlPath "C:\Users\pangb\Downloads\Help\幫助文檔 - 副本.…

Go初級之十:錯誤處理與程序健壯性

Go初級之十&#xff1a;錯誤處理與程序健壯性為什么選這個主題&#xff1f; 錯誤處理是 Go 語言中一個非常獨特且重要的設計哲學。它體現了 Go 的“顯式錯誤處理”思想&#xff0c;與其它語言&#xff08;如 Java/Python&#xff09;的異常機制不同。在實際開發中&#xff0c;幾…