數據結構——lesson5棧和隊列詳解

hellohello~這里是土土數據結構學習筆記🥳🥳
在這里插入圖片描述

💥個人主頁:大耳朵土土垚的博客
💥 所屬專欄:數據結構學習筆記
💥對于順序表鏈表有疑問的都可以在上面數據結構的專欄進行學習哦~感謝大家的觀看與支持🌹🌹🌹
有問題可以寫在評論區或者私信我哦~

前言:

之前的博客我們學習了數據結構中的順序表和鏈表,現在我們一起回顧一下它們各自的優缺點。
首先是順序表
?優點:
1.支持下標的隨機訪問(因為是數組的形式);
2.尾插尾刪比較方便,效率不錯;
3.CPU高速緩存命中率較高;
? 缺點:
1.前面部分插入刪除數據需要挪動數據,時間復雜度為O(n);
2.空間不夠需要擴容——一方面擴容需要付出代價例如異地擴容, 另一方面擴容一般還伴隨著空間的浪費;
其次是鏈表
?優點:
1.任意位置插入刪除數據都比較方便高效,時間復雜度為O(1);
2.按需申請釋放空間
?缺點:
1.不支持下標的隨機訪問;
2.CPU高速緩存命中率較低;
我們發現順序表的優點和缺點恰好對應著鏈表的缺點和優點,順序表和鏈表各自都有它們獨特的作用與優勢,不存在優劣之分。大家在使用的時候要根據自己的需求去選擇哦~


一、棧


1.1棧的概念及結構

棧: 一種特殊的線性表,其只允許在固定的一端進行插入和刪除元素操作。進行數據插入和刪除操作的一端稱為棧頂,另一端稱為棧底。棧中的數據元素遵守后進先出LIFO(Last In First Out)的原則。

壓棧:棧的插入操作叫做進棧/壓棧/入棧,入數據在棧頂。
出棧:棧的刪除操作叫做出棧。出數據也在棧頂。

1.2棧的實現

棧的實現一般可以使用數組或者鏈表實現,相對而言數組的結構實現更優一些。因為數組在尾上插入數據的代價比較小。

在這里插入圖片描述

如圖所示,左邊是棧尾,右邊是棧頂(進行出棧也就是刪除操作);
以下是棧的實現:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
#include<stdbool.h>typedef int STDataType;// 支持動態增長的棧
typedef int STDataType;
typedef struct Stack//定義一個結構體表現棧
{STDataType* a;int top;       // 棧頂int capacity;  // 容量 
}Stack;
// 初始化棧 
void StackInit(Stack* ps);
// 入棧 
void StackPush(Stack* ps, STDataType data);
// 出棧 
void StackPop(Stack* ps);
// 獲取棧頂元素 
STDataType StackTop(Stack* ps);
// 獲取棧中有效元素個數 
int StackSize(Stack* ps);
// 檢測棧是否為空,如果為空返回true,如果不為空返回false
bool StackEmpty(Stack* ps);
// 銷毀棧 
void StackDestroy(Stack* ps);

棧實現包括初始化,入棧,出棧,獲取棧頂元素,獲取棧中有效元素個數,判斷棧是否為空以及銷毀棧這7個函數。

下面我們來具體實現棧:

(1)初始化棧

void StackInit(Stack* ps);

// 初始化棧 
void StackInit(Stack* ps)
{assert(ps);ps->a = NULL;ps->capacity = 0;ps->top = 0;//指向棧頂的下一個數據//ps->top = -1; //則指向棧頂數據
}

這里要注意ps->top = 0 代表的是棧頂元素的下一個;ps->top = -1才指向棧頂元素,因為后面的函數每增加一個元素,ps->top++,如果初始化top = 0,加一個元素后,top=1;表示的位置是下標為1(其本質是數組,下標為1的位置表示第二個元素),但確間接表明了棧中元素的個數剛好為1,所以為了后續方便,我們選擇初始化top=0;當然你也可以自由選擇。

(2)入棧

void StackPush(Stack* ps, STDataType data);

void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->top == ps->capacity)//判斷空間是否滿了{//空間capacity滿了就需要擴容STDataType newcapacity = ps->capacity == 0 ? 4 : ps->capacity * 2;//判斷是否擴容過,如果capacity為0就增加4//個單位空間,否則開辟capacity的2倍空間ps->capacity = newcapacity;//擴容后capacity要等于newcapacityps->a = (STDataType*)realloc(ps->a, newcapacity * sizeof(STDataType));if (ps->a == NULL){perror("realloc fail");return;}}ps->a[ps->top] = data;//入棧ps->top++;//棧頂+1}

這里入棧要注意判斷棧的容量是否滿了,滿了需要使用realloc函數擴容,對于realloc函數有疑問的小伙伴可以查看土土的博客——C語言動態內存函數介紹

(3)出棧

void StackPop(Stack* ps)

// 出棧 
void StackPop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));//判斷非空ps->top--;
}

出棧就比較簡單,只需將top–即可,但是同時也要注意判斷棧不為空哦~判空函數StackEmpty(ps)將在后面實現

(4)獲取棧頂元素

STDataType StackTop(Stack* ps)

// 獲取棧頂元素 
STDataType StackTop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));//判斷非空return ps->a[ps->top-1];
}

是時候考驗你們的專注力了,這里返回棧頂元素用的是top-1;有小伙伴知道為什么不直接用top嗎?答案我們放在下一個獲取棧中有效元素個數函數中揭曉。

(5)獲取棧中有效元素個數

int StackSize(Stack* ps)

// 獲取棧中有效元素個數 
int StackSize(Stack* ps)
{assert(ps);return ps->top;
}

上一個函數獲取棧頂元素我們使用的是top-1,是因為在初始化函數時我們就介紹過將top初始化為0,指向棧頂元素的下一個,所以要獲取棧頂元素我們要將top-1;依此類推棧中有效元素個數就恰好是top了。

(6)檢測棧是否為空

bool StackEmpty(Stack* ps)

// 檢測棧是否為空,如果為空返回true,如果不為空返回false
bool StackEmpty(Stack* ps)
{assert(ps);/*if (ps->top == 0)return true;elsereturn false;*/return ps->top == 0;
}

這里可以使用if語句來判斷,也可以如上面代碼所示直接使用return返回。

(7)銷毀棧

void StackDestroy(Stack* ps)

// 銷毀棧 
void StackDestroy(Stack* ps)
{assert(ps);free(ps->a);ps->capacity = 0;ps->a = NULL;ps->top = 0;
}

這里就不過多贅述,使用free銷毀即可;因為數組時地址連續的一段物理空間,所以只要數組首元素地址即可free整個數組與鏈表需要遍歷不同。

棧實現可視化如下圖所示:

在這里插入圖片描述
代碼如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include"stack.h"
void Sttest()
{Stack ST;StackInit(&ST);StackPush(&ST, 1);StackPush(&ST, 2);StackPush(&ST, 3);StackPush(&ST, 4);while (ST.top)//打印棧{printf("%d", StackTop(&ST));StackPop(&ST);//打印一個出一個}StackDestroy(&ST);}
int main()
{Sttest();return 0;
}

二、隊列

2.1隊列的概念及結構

隊列:只允許在一端進行插入數據操作,在另一端進行刪除數據操作的特殊線性表,隊列具有先進先出FIFO(First In First Out)
入隊列:進行插入操作的一端稱為隊尾
出隊列:進行刪除操作的一端稱為隊頭

發現進行刪除操作的都是隊頭,無論棧還是隊列;
隊列根據其名字,我們不難發現類似于我們生活中的排隊,先排隊的肯定會先出去;
在這里插入圖片描述

2.2隊列的實現

隊列也可以數組和鏈表的結構實現,使用鏈表的結構實現更優一些,因為如果使用數組的結構,出隊列在數組頭上出數據,效率會比較低。

// 鏈式結構:表示隊列 
typedef int QDataType;
typedef struct QListNode 
{ struct QListNode* pNext; QDataType data; 
}QNode; // 隊列的結構 
typedef struct Queue 
{ 
QNode* front; 
QNode* rear; 
}Queue; 
// 初始化隊列 
void QueueInit(Queue* q); 
// 隊尾入隊列 
void QueuePush(Queue* q, QDataType data); 
// 隊頭出隊列 
void QueuePop(Queue* q); 
// 獲取隊列頭部元素 
QDataType QueueFront(Queue* q); 
// 獲取隊列隊尾元素 
QDataType QueueBack(Queue* q); 
// 獲取隊列中有效元素個數 
int QueueSize(Queue* q); 
// 檢測隊列是否為空,如果為空返回非零結果,如果非空返回0 
int QueueEmpty(Queue* q); 
// 銷毀隊列 
void QueueDestroy(Queue* q);

隊列相較于棧定義了兩個結構體來表示,一個結構體QNode表示節點,另一個結構體Queue則用來表示隊列的頭尾指針,展示隊列的結構。
隊列也包含了初始化,隊尾入隊列,隊頭出隊列,獲取隊列頭部元素,獲取隊列尾部元素,以及有效元素個數,判空,銷毀這八個函數。

(1)初始化隊列

void QueueInit(Queue* q);

// 初始化隊列 
void QueueInit(Queue* q)
{assert(q);q->front = NULL;q->rear = NULL;
}

將Queue結構體初始化即可

(2)隊尾入隊列

void QueuePush(Queue* q, QDataType data);

// 隊尾入隊列 
void QueuePush(Queue* q, QDataType data)
{assert(q);QNode* newnode = (QNode*)malloc(sizeof(QNode));//創建新節點if (newnode == NULL){perror("malloc fail");return;}newnode->data = data;newnode->pNext = NULL;//隊列為空的情況入隊列if (QueueEmpty(q)){q->front = newnode;q->rear = newnode;return;}//隊列不為空的情況入隊列else{q->rear->pNext = newnode;q->rear = newnode;return;}
}

隊尾入隊列首先要記得malloc一個新節點,然后要記得判斷隊列是否為空,分為兩種情況。判空函數將在后面實現。

(3)隊頭出隊列

void QueuePop(Queue* q);

// 隊頭出隊列 
void QueuePop(Queue* q)
{assert(q);assert(!QueueEmpty(q));//判斷隊列非空QNode* tmp = q->front;//先保存隊頭指針q->front = tmp->pNext;free(tmp);
}

隊頭出隊列要記得free釋放出去節點的空間。

(4)獲取隊列頭部元素

QDataType QueueFront(Queue* q);

// 獲取隊列頭部元素 
QDataType QueueFront(Queue* q)
{assert(q);assert(!QueueEmpty(q));//判斷隊列非空return q->front->data;}

通過結構體Queue的front指針可以直接找到頭返回即可。

(5)獲取隊列隊尾元素

QDataType QueueBack(Queue* q);

// 獲取隊列隊尾元素 
QDataType QueueBack(Queue* q)
{assert(q);assert(!QueueEmpty(q));//判斷隊列非空return q->rear->data;
}

同樣通過結構體Queue的rear指針可以直接找到尾返回即可。

(6) 獲取隊列中有效元素個數

int QueueSize(Queue* q)

// 獲取隊列中有效元素個數 
int QueueSize(Queue* q)
{assert(q);assert(!QueueEmpty(q));//判斷隊列非空int count = 0;//記錄元素個數QNode* cur = q->front;while (cur){cur = cur->pNext;count++;}return count;
}

這里隊列用的是鏈表的結構,所以需要使用循環遍歷來獲取有效元素的個數。

(7)檢測隊列是否為空

bool QueueEmpty(Queue* q);

// 檢測隊列是否為空,如果為空返回true,非空返回false
bool QueueEmpty(Queue* q)
{assert(q);return q->front == NULL;}

隊列頭指針為空即沒有元素進入隊列。

(8)銷毀隊列

void QueueDestroy(Queue* q);

// 銷毀隊列 
void QueueDestroy(Queue* q)
{assert(q);while (q->front){QueuePop(q);}
}

QueuePop()函數將元素從隊頭刪除的同時也使用了free釋放空間,所以這里直接使用該函數即可。

隊列實現可視化如下圖所示:

在這里插入圖片描述
實現代碼如下:

#include"queue.h"void Qtest()
{Queue QT;QueueInit(&QT);QueuePush(&QT, 1);QueuePush(&QT, 2);QueuePush(&QT, 3);QueuePush(&QT, 4);while (QT.front){printf("%d", QueueFront(&QT));QueuePop(&QT);}QueueDestroy(&QT);
}
int main()
{Qtest();return 0;
}

三、練習題

1.一個棧的初始狀態為空。現將元素1、2、3、4、5、A、B、C、D、E依次入棧,然后再依次出棧,則元素出
棧的順序是(  )。
A 12345ABCDEB EDCBA54321C ABCDE12345D 54321EDCBA2.若進棧序列為 1,2,3,4 ,進棧過程中可以出棧,則下列不可能的一個出棧序列是()
A 1,4,3,2B 2,3,4,1C 3,1,4,2D 3,4,2,13.以下(  )不是隊列的基本運算?
A 從隊尾插入一個新元素
B 從隊列中刪除第i個元素
C 判斷一個隊列是否為空
D 讀取隊頭元素的值

答案:BCB

四、結語

棧和隊列有很多的相似之處,盡管棧是隊頭進入刪除數據(后進先出),隊列是隊尾入數據,隊頭刪數據(先進后出),但其本質是一樣的。熟悉了棧和隊列后,相信大家對于順序表和鏈表的理解也會更上一層樓。以上就是棧和隊列的學習啦~ 完結撒花~🥳🥳🎉

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

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

相關文章

ElasticSearch開篇

1.ElasticSearch簡介 1.1 ElasticSearch&#xff08;簡稱ES&#xff09; Elasticsearch是用Java開發并且是當前最流行的開源的企業級搜索引擎。能夠達到實時搜索&#xff0c;穩定&#xff0c;可靠&#xff0c;快速&#xff0c;安裝使用方便。 1.2 ElasticSearch與Lucene的關…

Angular項目升級的一般步驟?

升級Angular項目是一個重要的任務&#xff0c;可以帶來性能改進、新功能和安全性增強等好處。以下是升級Angular項目的一般步驟&#xff1a; 1、備份項目文件&#xff1a; 在進行升級之前&#xff0c;務必對整個項目進行備份&#xff0c;以防意外情況發生。 2、查看當前版本&…

如何快速遷移其他云服務器中的網站數據到騰訊云輕量應用服務器中?教你使用寶塔Linux面板遷移網站

要快速遷移其他云服務器中的網站數據到騰訊云輕量應用服務器中&#xff0c;可以遵循以下步驟&#xff1a; 準備遷移前的工作&#xff1a;首先&#xff0c;確保你已經有了從其他云服務器到騰訊云輕量應用服務器的數據備份。這一步是為了在遷移過程中避免數據丟失或損壞。 使用寶…

模擬器抓HTTP/S的包時如何繞過單向證書校驗(XP框架)

模擬器抓HTTP/S的包時如何繞過單向證書校驗&#xff08;XP框架&#xff09; 逍遙模擬器無法激活XP框架來繞過單向的證書校驗&#xff0c;如下圖&#xff1a; ?? 解決辦法&#xff1a; 安裝JustMePlush.apk安裝Just Trust Me.apk安裝RE管理器.apk安裝Xposedinstaller_逍遙64位…

智能邊緣小站 CloudPond(低延遲、高帶寬和更好的數據隱私保護)

智能邊緣小站 CloudPond(低延遲、高帶寬和更好的數據隱私保護) 邊緣小站的主要功能是管理用戶在線下部署的整機柜設施&#xff0c;一個邊緣小站關聯一個華為云指定的區域和一個用戶指定的場地&#xff0c;相關的資源運行狀況監控等。 邊緣計算 邁入5G和AI時代&#xff0c;新…

利用redis實現秒殺功能

6、秒殺優化 這個是 圖靈 的redis實戰里面的一個案例 6.1 秒殺優化-異步秒殺思路 我們來回顧一下下單流程 當用戶發起請求&#xff0c;此時會請求nginx&#xff0c;nginx會訪問到tomcat&#xff0c;而tomcat中的程序&#xff0c;會進行串行操作&#xff0c;分成如下幾個步驟…

基于單片機的紅外遙控解碼程序設計與實現

摘要:該文介紹基于士蘭半導體芯片(SC6122)的紅外發射遙控器,通過單片機解碼程序,實現紅外遙控信號的解碼和接收。紅外接收頭與單片機特定的引腳連接,通過設置單片機定時計數器,采樣來自紅外接收頭的高、低電平寬度解碼遙控信號。該解碼程序設計主要應用在LED數碼顯示控制…

電機的極數和槽數,機械角度和電角度,霍爾IC,內外轉子

什么是電機的極數和槽數&#xff1f; 【第7集】②?正弦波驅動的轉矩脈動、正弦電流的時序和相位變化、超前角控制&#xff08;超前角調整&#xff09;、正弦波驅動的各種波形 - 電源設計電子電路基礎電源技術信息網站_羅姆電源設計R課堂 (rohm.com.cn) 下面為您介紹表示電機…

supervisor進程管理器-supervisord管理hyperf項目

Supervisor安裝 # 安裝 epel 源&#xff0c;如果此前安裝過&#xff0c;此步驟跳過 yum install -y epel-release # 安裝supervisor yum install -y supervisor # 設置supervisor開機自啟動 systemctl enable supervisord # 啟動supervisord服務 systemctl start supervisord…

新概念英語第二冊(72)

【New words and expressions】生詞和短語&#xff08;7&#xff09; racing n. 競賽 per prep. 每 Utah n. 猶他&#xff08;美國州名&#xff09; horsepower n. 馬力…

Java虛擬機(JVM)從入門到實戰【上】

Java虛擬機&#xff08;JVM&#xff09;從入門到實戰【上】&#xff0c;涵蓋類加載&#xff0c;雙親委派機制&#xff0c;垃圾回收器及算法等知識點&#xff0c;全系列6萬字。 一、基礎篇 P1 Java虛擬機導學課程 P2 初識JVM 什么是JVM Java Virtual Machine 是Java虛擬機。…

3.2日-線性模型,基礎優化方法,線性回歸從零開始實現

3.2日-線性模型&#xff0c;基礎優化方法&#xff0c;線性回歸從零開始實現 1線性模型衡量預估質量訓練數據總結2基礎優化方法3 線性回歸從零開始實現 1線性模型 衡量預估質量 訓練數據 總結 2基礎優化方法 梯度下降是一種優化算法&#xff0c;常用于機器學習和深度學習中&…

autojs Intent跳轉申請忽略電池優化頁面 和判斷是否已加入忽略優化白名單

//打開電池優化申請 判斷是否加入白名單 importClass(android.os.PowerManager); // importClass(android.Settings) //安卓setting 中有設置界面的各種activity var pm context.getSystemService(context.POWER_SERVICE);if (!pm.isIgnoringBatteryOptimizations(currentPa…

進程的信號

目錄 信號(signal)入門 技術應用角度的信號 注意 用kill -l命令可以察看系統定義的信號列表 信號處理常見方式概覽 產生信號 1.通過終端(鍵盤)按鍵產生信號 signal函數 2. 調用系統函數向進程發信號 kill 函數 raise 函數 3.由軟件條件產生的信號 alarm 函數 4.硬…

pytorch基礎4-自動微分

專題鏈接&#xff1a;https://blog.csdn.net/qq_33345365/category_12591348.html 本教程翻譯自微軟教程&#xff1a;https://learn.microsoft.com/en-us/training/paths/pytorch-fundamentals/ 初次編輯&#xff1a;2024/3/2&#xff1b;最后編輯&#xff1a;2024/3/3 本教程…

【Java EE】JUC(java.util.concurrent) 的常見類

目錄 &#x1f334;Callable 接口&#x1f38d;ReentrantLock&#x1f340;原子類&#x1f333;線程池&#x1f332;信號量 Semaphore??CountDownLatch、?相關面試題 &#x1f334;Callable 接口 Callable 是?個 interface . 相當于把線程封裝了?個 “返回值”. ?便程序…

什么是灰色預測

灰色預測是一種基于灰色系統理論的預測方法&#xff0c;用于處理數據不完全、信息不充分或未知的情況下的預測問題。它適用于樣本數據較少、無法建立精確的數學模型的情況。 灰色預測的基本思想是利用已知數據的特點和規律來推斷未知數據的發展趨勢。它的核心是灰色關聯度的概念…

(學習日記)2024.03.01:UCOSIII第三節 + 函數指針 (持續更新文件結構)

寫在前面&#xff1a; 由于時間的不足與學習的碎片化&#xff0c;寫博客變得有些奢侈。 但是對于記錄學習&#xff08;忘了以后能快速復習&#xff09;的渴望一天天變得強烈。 既然如此 不如以天為單位&#xff0c;以時間為順序&#xff0c;僅僅將博客當做一個知識學習的目錄&a…

Kubernetes: 本地部署dashboard

本篇文章主要是介紹如何在本地部署kubernetes dashboard, 部署環境是mac m2 下載dashboard.yaml 官網release地址: kubernetes/dashboard/releases 本篇文章下載的是kubernetes-dashboard-v2.7.0的版本&#xff0c;通過wget命令下載到本地: wget https://raw.githubusercont…

【Python】進階學習:pandas--isin()用法詳解

【Python】進階學習&#xff1a;pandas–isin()用法詳解 &#x1f308; 個人主頁&#xff1a;高斯小哥 &#x1f525; 高質量專欄&#xff1a;Matplotlib之旅&#xff1a;零基礎精通數據可視化、Python基礎【高質量合集】、PyTorch零基礎入門教程&#x1f448; 希望得到您的訂閱…