【數據結構(C語言)】淺談棧和隊列

目錄

文章目錄

前言

一、棧

1.1 棧的概念及結構

1.2 棧的實現

1.2.1. 支持動態增長的棧的結構

1.2.2 初始化棧

1.2.3 入棧

1.2.4 出棧

1.2.5 獲取棧頂元素

1.2.6?獲取棧中有效元素個數

1.2.7 檢查棧是否為空

1.2.8 銷毀棧

二、隊列

2.1 隊列的概念及結構

2.2 隊列的實現

2.2.1 隊列的結構

2.2.2 初始化隊列

2.2.3 入隊

2.2.4 出隊

2.2.5 獲取隊頭元素

2.2.6 獲取隊尾元素

2.2.7 獲取隊列中有效元素個數

2.2.8 檢查隊列是否為空

2.2.9 銷毀隊列

總結


一、棧

1.1 棧的概念及結構

棧(Stack)是一種線性數據結構,它可以看作是一種特殊的列表。棧只能在一端進行插入和刪除操作,這一端被稱為棧頂(Top)。棧按照后進先出(LIFO, Last In First Out)的原則進行操作,即最后一個進棧的元素最先被彈出。棧可以用數組或鏈表實現。棧的主要操作包括壓棧(進棧/入棧)(Push)和彈棧(出棧)(Pop),還有取棧頂元素(Top)和判斷棧是否為空(Empty)等。棧在編程中常用于函數調用、表達式求值、括號匹配等場景。

1.2 棧的實現

棧的實現一般可以使用數組或者鏈表實現,相對而言數組的結構實現更優一些。因為數組在尾上插入數據的代價比較小。所以我們這里使用數組實現棧。用數組實現也分為靜態的和動態的,靜態的實際中一般不實用,所以我們實現動態的

1.2.1. 支持動態增長的棧的結構

這里我們聲明一個結構體,一個成員為指針a,用來存放開辟空間的首地址(即動態數組),一個成員top用來存放棧頂位置,還有一個成員capacity用來存放開辟的空間大小,方便數組擴容。

代碼如下:

typedef int StDataType;typedef struct Stack
{StDataType* a;int top;		// 標識棧頂位置的int capacity;
}St;

1.2.2 初始化棧

將結構體中的指針a賦值為NULL,將capacity賦值為0,將top賦值為0,表示top指向棧頂元素的下一個位置(也可以賦值為-1,表示top指向棧頂元素,這里我們使用第一種)。

代碼如下:

void StInit(St* pst)
{assert(pst);pst->a = NULL;pst->capacity = 0;//表示top指向棧頂元素的下一個位置pst->top = 0;//表示top指向棧頂元素,如果為-1,后面的代碼也要改//pst->top = -1;
}

1.2.3 入棧

入棧之前要先判斷開辟的空間滿了沒,如果滿了,可以使用realloc()函數重新分配數組大小,然后再將元素插入top所指向的位置,最后將top+1。

代碼如下:

void StPush(St* pst, StDataType x)
{assert(pst);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");exit(-1);}pst->a = tmp;pst->capacity = newCapacity;}pst->a[pst->top] = x;pst->top++;
}

1.2.4 出棧

先要確保棧中有元素,可以使用斷言,如果有,則只需要top-1就行。

代碼如下:

void StPop(St* pst)
{assert(pst);assert(pst->top > 0);pst->top--;
}

1.2.5 獲取棧頂元素

先確保棧中有元素,然后直接返回top-1所指向位置的元素即可。

代碼如下:

StDataType StTop(St* pst)
{assert(pst);assert(pst->top > 0);return pst->a[pst->top - 1];
}

1.2.6?獲取棧中有效元素個數

因為top指向棧頂元素的下一個位置,其大小剛好為元素的個數,所以直接返回top即可。

代碼如下:

int StSize(St* pst)
{assert(pst);return pst->top;
}

1.2.7 檢查棧是否為空

判斷top是否為0,為0即為空。

代碼如下:

bool StEmpty(St* pst)
{assert(pst);return pst->top == 0;
}

1.2.8 銷毀棧

先將動態分配的內存釋放了,再將結構體中的成員賦值為初始化棧時所賦值的值就行。

代碼如下:

void StDestroy(St* pst)
{assert(pst);free(pst->a);pst->a = NULL;pst->top = 0;pst->capacity = 0;
}

二、隊列

2.1 隊列的概念及結構

隊列(Queue)是一種遵循先進先出(First In First Out,FIFO)原則的數據結構,即最先插入隊列的元素最先被取出。隊列具有兩個端點,一個是隊頭(Head),一個是隊尾(Tail),入隊操作(enqueue)在隊尾進行,出隊操作(dequeue)在隊頭進行。隊列的應用領域很廣,例如實現任務調度、消息傳遞、緩沖區等。常見隊列的實現包括:單向隊列、雙向隊列和循環隊列等。我們這里主要討論單向隊列。

2.2 隊列的實現

我們這里實現的是最基礎的單向隊列,雙向隊列和循環隊列各位讀者可另行了解。隊列也可以數組和鏈表的結構實現,使用鏈表的結構實現更優一些,因為如果使用數組的結構,出隊列在數組頭上出數據,效率會比較低(因為要整體把元素往前移,時間復雜度為O(n),雖然在算法中用數組模擬實現隊列可以使用頭尾雙指針使時間復雜度變成O(1),但這樣做出隊的同時也把空間浪費了)。

2.2.1 隊列的結構

因為使用鏈表實現隊列,所以先聲明一個隊列的結點的結構體,其成員跟鏈表的聲明一致,有兩個成員,一個為數據val,另一個為next指針。然后為了后面實現的方便,再聲明一個隊列結構體,其成員包括隊頭指針phead和隊尾指針ptail以及一個記錄隊列大小的整形size。

代碼如下:

typedef int QDataType;typedef struct QueueNode
{QDataType val;struct QueueNode* next;
}QNode;typedef struct Queue
{QNode* phead;QNode* ptail;int size;
}Queue;

2.2.2 初始化隊列

將隊頭指針phead和隊尾指針ptail賦值為NULL,將size賦值為0。

代碼如下:

void QueueInit(Queue* pq)
{assert(pq);pq->phead = pq->ptail = NULL;pq->size = 0;
}

2.2.3 入隊

先動態申請一個新結點,將要入隊的元素賦給新結點的val,再將新結點的next指針指向NULL。然后判斷這個隊列是否為空,如果為空,則將隊頭指針phead和隊尾指針ptail都指向新結點;如果不為空,則只要改變隊尾指針ptail就行,即先將隊尾指針ptail指向的結點的next指針指向新結點,再將隊尾指針ptail指向新結點。最后將size+1就行了。

代碼如下:

void QueuePush(Queue* pq, QDataType x)
{assert(pq);QNode* newNode = (QNode*)malloc(sizeof(QNode));if (newNode == NULL){perror("malloc fail");exit(-1);}newNode->val = x;newNode->next = NULL;if (pq->phead == NULL){pq->phead = pq->ptail = newNode;}else{pq->ptail->next = newNode;pq->ptail = newNode;}pq->size++;
}

2.2.4 出隊

先要確保隊列中有結點,可以使用斷言。然后再判斷隊列中是否只有一個結點,如果是,則釋放這個結點后,要將隊頭指針phead和隊尾指針ptail都指向NULL;如果不是,則只需要將隊頭指針phead指向它所指向的結點的下一個結點,并將它原來所指向的結點釋放就行。最后將size-1。

代碼如下:

void QueuePop(Queue* pq)
{assert(pq);assert(pq->phead);if (pq->phead == pq->ptail){free(pq->phead);pq->phead = pq->ptail = NULL;}else{QNode* tmp = pq->phead;pq->phead = pq->phead->next;free(tmp);}pq->size--;
}

2.2.5 獲取隊頭元素

先確保隊列有結點,再返回隊頭指針phead所指向的結點的值val。

代碼如下:

QDataType QueueFront(Queue* pq)
{assert(pq);assert(pq->phead);return pq->phead->val;
}

2.2.6 獲取隊尾元素

先確保隊列有結點,再返回隊尾指針ptail所指向的結點的值val。

代碼如下:

QDataType QueueBack(Queue* pq)
{assert(pq);assert(pq->ptail);return pq->ptail->val;
}

2.2.7 獲取隊列中有效元素個數

直接返回size。

代碼如下:

int QueueSize(Queue* pq)
{assert(pq);return pq->size;
}

2.2.8 檢查隊列是否為空

判斷隊頭指針phead是否為NULL。

代碼如下:

bool QueueEmpty(Queue* pq)
{assert(pq);return pq->phead == NULL;
}

2.2.9 銷毀隊列

先遍歷釋放隊列中的每一個結點,再將隊列結構體中的成員賦值為初始化隊列時所賦值的值就行。

代碼如下:

void QueueDestroy(Queue* pq)
{assert(pq);QNode* cur = pq->phead;while (cur){QNode* next = cur->next;free(cur);cur = next;}pq->phead = pq->ptail = NULL;pq->size = 0;
}


總結

以上就是關于棧和隊列的基本概念和操作。通過這篇文章,希望大家能夠更好地理解關于棧和隊列的原理和實現,并在實際編程中靈活運用它們。

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

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

相關文章

Javaweb之前后臺分離開發介紹的詳細解析

2.1 前后臺分離開發介紹 在之前的課程中,我們介紹過,前端開發有2種方式:前后臺混合開發和前后臺分離開發。 前后臺混合開發,顧名思義就是前臺后臺代碼混在一起開發,如下圖所示: 這種開發模式有如下缺點&a…

守護進程的理解

什么是守護進程 daemon False # 是否以守護進程方式運行,True守護,False 非守護 在這段代碼中,daemon 變量的值決定了進程是否以守護進程方式運行。如果 daemon 的值為 True,則表示進程將以守護進程方式運行,否則為…

使用vcpkg安裝庫失敗的解決方法

1、前言 vcpk是是一款開源的c/c庫管理工具,尤其是在windows平臺,可以幫助我們很好的管理各種依賴包。 在windows環境做c/c開發的人應該都深有體會,有時候編譯需要下載一堆依賴庫,導致搭建編譯環境特別麻煩。但是,通過v…

前端 vue 面試題(二)

文章目錄 如何讓vue頁面重新渲染組件間通信vue為什么要mutation、 action操作插槽、具名插槽、作用域插槽vue編譯使用的是什么庫?vue怎么實現treeshakingwebpack實現treeshaking為什么只有es module 能支持 tree shaking mixin 的作用mixin的底層原理nexTick原理vue…

預處理機制

跟著肯哥(不是我)學預處理機制 預處理類別 宏定義:#define 將文本替換為表達式或語句 條件編譯:#ifdef、#ifndef和#if、#elif、#endif 根據標識符是否被定義選擇編譯代碼 頭文件包含:#include 將其他文件&#x…

Jmeter怎么實現接口關聯?

用于接口測試時,后一個接口經常需要用到前一次接口返回的結果,應該如何獲取前一次請求的結果值,應用于后一個接口呢,拿一個登錄的例子來說明如何獲取。 1、打開jmeter,新建一個測試計劃,在測試計劃里新建一…

將所有圖片居中對齊

Ctrl h 調出替換框 ^g表示所有圖片 格式里面選擇段落 全部替換

winlogbeat采集windows日志

下載鏈接 https://www.elastic.co/cn/downloads/past-releases/winlogbeat-7-16-2 配置文件 # ---------------------------- Elasticsearch Output ---------------------------- output.elasticsearch:# Array of hosts to connect to.hosts: ["192.168.227.160:9200&…

Vue3中如何響應式解構 props

目錄 1,前言2,解決2.1,利用插件,實現編譯時轉換2.2,toRef 和 toRefs 1,前言 Vue3 中為了保持響應性,始終需要以 props.x 的方式訪問這些 prop。這意味著不能夠解構 defineProps 的返回值&#…

Navicat 技術指引 | 適用于 GaussDB 的數據遷移工具

Navicat Premium(16.2.8 Windows版或以上) 已支持對 GaussDB 主備版的管理和開發功能。它不僅具備輕松、便捷的可視化數據查看和編輯功能,還提供強大的高階功能(如模型、結構同步、協同合作、數據遷移等),這…

Cesium 展示——地球以及渲染數據導出(下載)為圖片或 pdf

文章目錄 需求分析新加需求分析第一種方式第二種方式需求 將 Cesium 球體以及渲染數據導出為 jpg/png/pdf 分析 獲取場景 scene 信息,轉為image 的 octet-stream 流 進行下載為圖片 /*** @todo canvas 導出圖片* @param {string} dataurl - 地址* @return {Blob}*/ functio…

Failed to resolve import “@/..“ from “src/...“ @找不到路徑

安裝path npm install --save-dev types/node再修改 vite.config.ts 中的配置即可 import { defineConfig } from "vite" import react from "vitejs/plugin-react"import path from "path" // 需安裝此模塊// https://vitejs.dev/config/ expo…

設備健康管理平臺助力鋰電企業實現可持續發展

隨著鋰電池產業的快速發展,設備的穩定運行和精準維護對于鋰電企業來說至關重要。傳統的設備維護方式在效率和全面性方面存在局限,無法滿足鋰電行業對設備管理的需求。然而,通過設備健康管理平臺的引入,鋰電企業現在可以充分發揮其…

XSLVGL2.0 User Manual 頁面管理器(v2.0)

XSLVGL2.0 開發手冊 XSLVGL2.0 User Manual 頁面管理器 1、概述2、特性3、APIs3.1、xs_page_init3.2、xs_page_wait_inited3.3、xs_page_exit3.4、xs_page_acquire3.5、xs_page_release3.6、xs_page_set_bootlogo3.7、xs_page_setup_clear_finish3.8、xs_page_setup_is_finish…

【LeetCode:1410. HTML 實體解析器 | 模擬+哈希表+字符串+庫函數】

🚀 算法題 🚀 🌲 算法刷題專欄 | 面試必備算法 | 面試高頻算法 🍀 🌲 越難的東西,越要努力堅持,因為它具有很高的價值,算法就是這樣? 🌲 作者簡介:碩風和煒,…

【C語言】中,輸入一個數組,實現將輸入的n個數字按照從大到小的順序輸出。【通俗簡單易懂】

本篇文章中,我們將講述在C語言中,輸入一個數組,如何用for循環實現將輸入的n個數字按照從大到小輸出。 一.定義數組并初始化 首先,我們定義一個整形的數組并將其初始化。輸入n,來決定數組中整數的個數。 然后用for循…

通過HTML網頁對mysql數據庫進行增刪改查(CRUD實例)

首先我們得了解一下大致的架構 ,如下: 我們采用自底向上的方式進行開發, 一、先寫mysql數據庫 二、再寫java后端(Spring MVC架構)(這個是什么東西不懂不要緊,跟著步驟做就行了) 三、最后寫前端頁面(HTML) 一、 Mysql數據庫部分 我們要通過網頁對數據庫進行開發,…

解決:Gitee + PicGo配置圖床失敗

解決:Gitee PicGo配置圖床失敗 PicGo安裝插件的時候選擇:gitee-uploader,不要選擇gitee! 在Gitee新建的圖床倉庫中設置一個images文件夾,用來保存上傳的圖片,但是要注意在PicGo中的path中要寫上路徑/img…

數據庫基礎入門 — SQL運算符

我是南城余!阿里云開發者平臺專家博士證書獲得者! 歡迎關注我的博客!一同成長! 一名從事運維開發的worker,記錄分享學習。 專注于AI,運維開發,windows Linux 系統領域的分享! 本…

linux的基礎命令

文章目錄 linux的基礎命令一、linux的目錄結構(一)Linux路徑的描述方式 二、Linux命令入門(一)Linux命令基礎格式 三、ls命令(一)HOME目錄和工作目錄(二)ls命令的參數1.ls命令的-a選…