數據結構(C語言篇):(八)棧

目錄

前言

一、概念與結構

二、棧的實現

2.1? 頭文件的準備

2.2? 函數的實現

2.2.1? STInit( )函數(初始化)

2.2.2? STDestroy( )函數(銷毀)

2.2.3? STPush( )函數(入棧)

2.2.4? STPop( )函數(出棧)

2.2.5? STTop( )函數(取棧頂元素)

2.2.6? STSize( )函數(獲取棧中元素個數)

總結


前言

????????棧作為一種基礎且強大的線性數據結構,在計算機科學領域扮演著至關重要的角色。其"后進先出"(LIFO)的核心特性,使其成為處理函數調用、表達式求值、括號匹配等場景的理想選擇。從程序執行時系統棧的管理,到日常開發中撤銷操作、瀏覽歷史等功能的實現,棧的應用無處不在。本文將深入探討棧的工作原理、實現方式以及典型應用場景,幫助讀者全面理解這一數據結構的精髓及其在實際工程中的價值。下面就讓我們正式開始吧!


一、概念與結構

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

????????壓棧:棧的插入操作叫做進棧/壓棧/入棧,入數據在棧頂。

? ? ? ? 出棧:棧的刪除操作叫做出棧。出數據也在棧頂。

? ? ? ? 壓棧和出棧的示意圖如下:

? ? ? ? 棧的底層結構選型:

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

? ? ? ? 如果使用數組來實現:

? ? ? ? 此時入棧和出棧的時間復雜度都是O(1)

? ? ? ? 如果使用鏈表來實現:

? ? ? ? 此時出棧和入棧的時間復雜度也同樣都是O(1)

二、棧的實現

2.1? 頭文件的準備

? ? ? ? 我們將棧的結構和一系列棧相關的函數在頭文件Stack.h中聲明如下:

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>//定義棧的結構
typedef int STDataType;
typedef struct Stack {STDataType* arr;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);//棧是否為空
bool STEmpty(ST* ps);
//獲取棧中有效元素個數
int STSize(ST* ps);

2.2? 函數的實現

2.2.1? STInit( )函數(初始化)

? ? ? ? 函數的實現邏輯如下:

? ? ? ??1.? 初始化數組指針:先將棧的數組指針arr置為NULL,此時表示棧沒有分配任何內存空間。

ps->arr = NULL;

????????2.? 初始化棧頂指針和容量:

  • ps->top = 0:將棧頂指針設置為0,表示空棧

  • ps->capacity = 0:將棧的容量設置為0,表示當前沒有分配空間

ps->top = ps->capacity = 0;

? ? ? ? 完整代碼如下:

//初始化
void STInit(ST* ps)
{ps->arr = NULL;ps->top = ps->capacity = 0;}

2.2.2? STDestroy( )函數(銷毀)

? ? ? ? 函數實現邏輯如下:

????????1.? 釋放動態數組內存:

  • 檢查?ps->arr?是否為?NULL(是否分配了內存)

  • 如果分配了內存,使用?free()?釋放數組內存

  • 避免對?NULL?指針調用?free()

if(ps->arr)free(ps->arr);

????????2.? 重置指針和狀態:

  • ps->arr = NULL:將數組指針設置為?NULL,避免野指針

  • ps->top = 0:將棧頂指針重置為0,表示空棧

  • ps->capacity = 0:將容量重置為0,表示沒有分配空間

ps->arr = NULL;
ps->top = ps->capacity = 0;

? ? ? ? 完整代碼如下:

//銷毀
void STDesTroy(ST* ps)
{if(ps->arr)free(ps->arr);ps->arr = NULL;ps->top = ps->capacity = 0;
}

? ? ? ? 使用示例如下:

ST stack;
STInit(&stack);      // 初始化棧// 使用棧進行各種操作
STPush(&stack, 10);
STPush(&stack, 20);
// ...STDesTroy(&stack);   // 銷毀棧,釋放資源
// 現在stack可以被重新初始化或丟棄

2.2.3? STPush( )函數(入棧)

? ? ? ? 首先畫圖分析:

? ? ? ? 函數實現邏輯如下:

????????1.? 參數驗證:確保棧指針?ps?不為?NULL。

assert(ps);

????????2.? 檢查空間是否足夠:如果棧頂指針等于容量,說明棧已滿,需要擴容。

if (ps->top == ps->capacity)

????????3.? 動態擴容機制:首次分配時,如果容量為0(初始狀態),先分配四個元素的空間;后續擴容時,如果已有容量,就將容量擴大為原來的2倍。(使用?realloc?重新分配內存,可以保留原有數據)

int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;
STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));

????????4.? 錯誤處理:檢查內存分配是否成功,如果失敗就輸出錯誤信息,并退出程序。

if (tmp == NULL)
{perror("realloc fail!");exit(1);
}

????????5.? 更新指針和容量:首先更新數組指針指向新分配的內存,然后更新容量為新分配的大小。

ps->arr = tmp;
ps->capacity = newCapacity;

????????6.? 壓入元素:將元素?x?放入棧頂位置?ps->arr[ps->top],然后棧頂指針?ps->top?自增1。

ps->arr[ps->top++] = x;

? ? ? ? 完整代碼如下所示:

//入棧——棧頂
void STPush(ST* ps, STDataType x)
{assert(ps);//判斷空間是否足夠if (ps->top == ps->capacity){//增容int newCapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* tmp = (STDataType*)realloc(ps->arr, newCapacity * sizeof(STDataType));if (tmp == NULL){perror("realloc fail!");exit(1);}ps->arr = tmp;ps->capacity = newCapacity;}//空間足夠ps->arr[ps->top++] = x;
}

? ? ? ? 使用示例如下:

ST stack;
STInit(&stack);STPush(&stack, 10);  // 分配4個空間,壓入10
STPush(&stack, 20);  // 壓入20
STPush(&stack, 30);  // 壓入30  
STPush(&stack, 40);  // 壓入40,棧滿
STPush(&stack, 50);  // 擴容到8個空間,壓入50

2.2.4? STPop( )函數(出棧)

? ? ? ? 要想實現出棧函數,我們需要先實現一個STEmpty (判空)函數,如下所示:

//棧是否為空
bool STEmpty(ST* ps)
{assert(ps);return ps->top == 0;
}

? ? ? ?畫圖分析如下:

? ? ? ? STPop的實現邏輯如下:

? ? ? ? 1.? 前置條件檢查:首先使用用?STEmpty?函數檢查棧是否為空,如果棧為空,則斷言失敗,不能執行彈出操作。同時需要確保棧中至少有一個元素可彈出。

????????2.? 執行彈出操作:首先將棧頂指針?top?減1,這樣原來的棧頂元素就不再屬于棧的有效范圍,但實際上并沒有刪除數據,只是改變了棧的邊界。

ps->top--;

? ? ? ? 完整代碼如下所示:

//出棧———棧頂
void STPop(ST* ps)
{assert(!STEmpty(ps));ps->top--;
}

? ? ? ? 使用示例如下:

ST stack;
STInit(&stack);STPush(&stack, 10);
STPush(&stack, 20);
STPush(&stack, 30);
// 棧: [10, 20, 30], top=3STPop(&stack);  // 彈出30
// 棧: [10, 20], top=2STPop(&stack);  // 彈出20  
// 棧: [10], top=1STPop(&stack);  // 彈出10
// 棧: 空, top=0

2.2.5? STTop( )函數(取棧頂元素)

? ? ? ? 畫圖分析如下:

? ? ? ? 函數的實現邏輯如下:

????????1.? 前置條件檢查:首先使用?STEmpty?函數檢查棧是否為空,如果棧為空,則斷言失敗,不能獲取棧頂元素。需要確保棧中至少有一個元素。

assert(!STEmpty(ps));

? ? ? ? 2.? 返回棧頂元素:

  • ps->top?指向下一個空位置(棧頂的下一個位置)

  • ps->top - 1?就是當前棧頂元素的位置

  • 返回該位置的元素值

return ps->arr[ps->top - 1];

????????完整代碼如下:

//取棧頂元素
STDataType STTop(ST* ps)
{assert(!STEmpty(ps));return ps->arr[ps->top - 1];
}

? ? ? ? 使用示例:

ST stack;
STInit(&stack);STPush(&stack, 10);
STPush(&stack, 20);
STPush(&stack, 30);
// 棧: [10, 20, 30], top=3STDataType topValue = STTop(&stack);  // 獲取棧頂值30
printf("棧頂元素: %d\n", topValue);   // 輸出: 棧頂元素: 30// 棧仍然保持: [10, 20, 30], top=3

2.2.6? STSize( )函數(獲取棧中元素個數)

? ? ? ? 函數實現邏輯如下:

????????1.? 參數驗證:確保棧指針?ps?不為?NULL。

assert(ps);

????????2.? 返回元素數量:直接返回棧頂指針?top?的值。因為?top?既指向下一個空位置,又表示當前元素數量。

return ps->top;

? ? ? ? 完整代碼如下:

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

? ? ? ? 使用示例如下:

ST stack;
STInit(&stack);printf("初始棧大小: %d\n", STSize(&stack));  // 輸出: 0STPush(&stack, 10);
STPush(&stack, 20);
STPush(&stack, 30);printf("當前棧大小: %d\n", STSize(&stack));  // 輸出: 3STPop(&stack);
printf("彈出后棧大小: %d\n", STSize(&stack));  // 輸出: 2

總結

? ? ? ? 本期我為大家介紹了數據結構中,棧的結構和其相關函數的實現邏輯,下期我將繼續為大家帶來隊列的相關內容,請大家多多關注和支持~~~

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

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

相關文章

Elasticsearch數據遷移快照方案初探(一):多節點集群配置踩坑記

背景介紹 在生產環境中&#xff0c;我們經常需要將測試環境的Elasticsearch索引數據遷移到生產環境。這次我們遇到了一個典型的多節點集群快照配置問題&#xff1a;需要為所有節點添加path.repo配置&#xff0c;但過程中遇到了各種挑戰。 問題描述 我們的Elasticsearch集群包含…

leedcode 算法刷題第二十天

39. 組合總和 class Solution { public:vector<vector<int>> result;vector<int> temp;void backtructing(vector<int>& candidates, int target, int sum,int start){if(sumtarget){result.push_back(temp);return;}if(sum>target){return;}f…

身份證實名認證API集成—身份核驗接口-網絡平臺安全合規

在數字化浪潮席卷各行各業的今天&#xff0c;網絡空間的安全問題日益受到關注。為防范網絡詐騙、虛假注冊、身份盜用等風險&#xff0c;國家陸續出臺多項法律法規&#xff0c;如《網絡安全法》《個人信息保護法》等&#xff0c;明確要求互聯網服務提供者落實用戶真實身份核驗機…

谷歌TIGER爆火!生成式召回顛覆推薦系統:用語義ID破解冷啟動+多樣性難題,3大數據集性能碾壓傳統模型

注&#xff1a;此文章內容均節選自充電了么創始人&#xff0c;CEO兼CTO陳敬雷老師的新書《GPT多模態大模型與AI Agent智能體》&#xff08;跟我一起學人工智能&#xff09;【陳敬雷編著】【清華大學出版社】 清華《GPT多模態大模型與AI Agent智能體》書籍配套視頻課程【陳敬雷…

分享一個實用的B站工具箱(支持音視頻下載等功能)

文章目錄 ?? 介紹 ?? ?? 演示環境 ?? ?? 一款實用的B站工具箱 ?? ?? 項目亮點 ?? ??? 下載與安裝 ?? 使用指南 ?? 注意事項 ?? 相關鏈接 ?? ?? 介紹 ?? 很多小伙伴在B站追番或者學習時,總會遇到一個很頭疼的問題:想把視頻下載到本地,要么被限…

大話 IOT 技術(4) -- 答疑篇

文章目錄前言手機能與設備直接通信嗎多協議能統一用一個嗎假設我們統一用http協議假設我們統一用mqtt協議bypass服務端和設備不能mqtt直接通信設備必有wifi 和藍牙功能設備為什么不能自己連接網絡配網模式是什么后話當你迷茫的時候&#xff0c;請點擊 物聯網目錄大綱 快速查看前…

機器視覺學習-day14-繪制圖像輪廓

1. 輪廓的概念輪廓是目標物體或者區域在圖像外部的邊界線&#xff0c;通常由一系列像素點相連組成&#xff0c;這些像素點共同構成了一個封閉的形狀&#xff0c;這樣形狀就是輪廓。輪廓與邊緣不同&#xff1a;輪廓是連續的&#xff0c;邊緣可以連續也可以離散輪廓是完整的&…

Linux shell getopts 解析命令行參數

Linux shell getopts 解析命令行參數getopts語法 getopts 選項字符串 名稱 [ 參數 ...]示例1&#xff08;有前置冒號&#xff09;: while getopts ":hdo:" optname; do ...... done示例1&#xff08;無前置冒號&#xff09; while getopts "hdo:" optname…

DeepInteraction++基于多模態交互的自動駕駛感知與規劃框架

DeepInteraction++基于多模態交互的自動駕駛感知與規劃框架 1 論文核心概念 DeepInteraction++ 提出了一種名為"模態交互"(modality interaction)的新策略,用于自動駕駛中的多模態(LiDAR 和相機)感知任務。其核心思想是不將多模態信息融合為單一表示,而是分別…

憶聯參與制定消費級SSD團體標準正式出版! 以“高可靠”引領行業提質增效與用戶體驗升級

引言?在AIPC爆發、數據價值凸顯的當下&#xff0c;存儲設備已超越簡單容器&#xff0c;成為智能體驗基石&#xff0c;其性能與可靠性直接關乎用戶效率與資產安全。然而&#xff0c;消費級SSD長期缺乏統一權威的可靠性標準&#xff0c;使廠商缺乏質量對標依據&#xff0c;用戶亦…

微服務搭建(SpringBoot + Dubbo + Nacos)

1.項目接口2. 編輯pom.xml和application.yml文件2.1父工程pom.xml<?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:s…

android中常見布局及其約束

0 布局的定義 布局可以理解為一種??容器??&#xff0c;用于??組織與排列界面上的控件??。 布局是一個相框&#xff0c;控件就是你要展示的照片。? 你&#xff08;布局規則&#xff09;決定這些照片怎么排列&#xff1a;是從上到下整齊放&#xff08;LinearLayout&am…

Rust語言能干什么

Rust 語言的應用范圍非常廣&#xff0c;幾乎覆蓋了現代軟件開發的全部領域。它最初以“系統級語言”身份出道&#xff0c;但現在已經遠遠超出了這個范疇。下面我從幾個關鍵方向給你梳理一下&#xff0c;Rust 到底能干什么&#xff0c;以及為什么在這些領域它特別有優勢。 1. 系…

只需一個設置就可以解決Microsoft Edge瀏覽器打不開網頁的問題

Microsoft Edge是一款功能強大的網絡瀏覽器&#xff0c;預裝在Windows 10、11系統中。通過這個簡單易懂的教程&#xff0c;學習如何修復Microsoft Edge瀏覽器打不開的問題。1、打開計算機找到C盤&#xff0c;雙擊打開&#xff1a;2、打開【用戶】?【Admin】?【AppData】?【L…

AI 應用 圖文 解說 (二) -- 百度智能云 ASR LIM TTS 語音AI助手源碼

文章的目的為了記錄AI應用學習的經歷&#xff0c;降低AI的入門難度。同時記錄開發流程和要點有些記憶模糊&#xff0c;防止忘記。也希望可以給看到文章的朋友帶來一些收獲。 相關鏈接&#xff1a; AI 應用 圖文 解說 (一) -- 百度智能云 實現 語音 聊天-CSDN博客 AI 應用 圖文 …

計算機Python畢業設計推薦:基于Django的博客網站設計與實現【python/大數據/深度學習/機器學習定制】

精彩專欄推薦訂閱&#xff1a;在下方主頁&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主頁&#xff1a;計算機畢設木哥&#x1f525; &#x1f496; 文章目錄 一、項目介紹二、…

當 AI 開始 “篩選” 信息:算法偏見會加劇認知鴻溝嗎?如何構建公平的 AI 生態?

AI 篩選信息的現狀與原理?在信息爆炸的時代&#xff0c;AI 篩選信息已成為各領域不可或缺的關鍵技術。在社交媒體平臺上&#xff0c;如抖音、小紅書等&#xff0c;AI 根據用戶的點贊、評論、瀏覽歷史等數據&#xff0c;精準推送用戶可能感興趣的內容&#xff0c;極大提升了用戶…

2023年IEEE IOTJ SCI1區TOP,動態環境下無人機目標覆蓋任務路徑規劃,深度解析+性能實測

目錄1.摘要2.問題模型3.算法設計4.結果展示5.參考文獻6.代碼獲取7.算法輔導應用定制讀者交流1.摘要 無人機&#xff08;UAV&#xff09;作為物聯網應用的重要工具&#xff0c;正廣泛應用于智能農業監測、智能交通監測等領域&#xff0c;并逐漸成為國內外研究熱點。然而&#x…

計算機視覺(四):二值化

二值化&#xff0c;就是將圖像從彩色或灰度模式轉換為只有兩種顏色&#xff08;通常是黑色和白色&#xff09;的模式。這個過程的本質是設定一個閾值 (Threshold)&#xff0c;將圖像中所有像素的灰度值與這個閾值進行比較。 基本原理 二值化的核心原理非常簡單&#xff1a; 灰度…

(二)設計模式(Command)

文章目錄項目地址一、設計模式1.1 Command Design1. 創建命令接口2. 創建支付的Command類3. CommandScheduler4. 使用1.2 Chain of Responsibility1. 接口創建2. 審批人3. 發起審批1.3 State Pattern1. 創建簡單的狀態機定義動作和狀態狀態機使用狀態機1.x Iterator1.x Observe…