【C語言入門】手把手教你實現順序棧

棧是計算機科學中最基礎且重要的數據結構之一,它遵循"后進先出"(LIFO)的原則。想象一下一疊盤子,你只能從最上面取放,這就是棧的直觀體現。本文將用C語言帶你一步步實現一個順序棧,即使你是編程小白也能輕松理解!

什么是順序棧?

順序棧是使用數組實現的棧結構,具有以下特點:

  • 元素在內存中連續存儲

  • 有一個指針(top)始終指向棧頂位置

  • 支持基本的入棧(push)和出棧(pop)操作

代碼實現詳解

1. 頭文件定義(Stack.h)

首先我們需要定義棧的結構和聲明相關操作函數:

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>// 定義棧中元素的數據類型
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);                  // 獲取元素個數
int StackEmpty(Stack* ps);                 // 檢查棧是否為空
void StackDestroy(Stack* ps);              // 銷毀棧

2. 棧的實現(Stack.c)

初始化棧
void StackInit(Stack* ps) {assert(ps);  // 確保指針有效ps->_a = NULL;ps->_top = 0;      // 棧頂指向下一個空閑位置ps->_capacity = 0; // 初始容量為0
}

初始化時,我們將數組指針設為NULL,棧頂位置和容量都設為0。

入棧操作
void StackPush(Stack* ps, STDataType data) {assert(ps);// 檢查棧是否已滿,需要擴容if (ps->_capacity == ps->_top) {// 如果容量為0,初始分配4個元素空間,否則容量翻倍int newcapacity = ps->_capacity == 0 ? 4 : ps->_capacity * 2;// 重新分配內存STDataType* tmp = (STDataType*)realloc(ps->_a, sizeof(STDataType) * newcapacity);if (tmp == NULL) {perror("malloc error");return;}ps->_capacity = newcapacity;ps->_a = tmp;}// 將數據放入棧頂并更新棧頂位置ps->_a[ps->_top++] = data;
}

這里使用了動態內存分配,當棧滿時自動擴容,這是實現可變大小棧的關鍵。

出棧操作
void StackPop(Stack* ps) {assert(ps);assert(ps->_top > 0); // 確保棧不為空ps->_top--; // 簡單地將棧頂指針下移
}

出棧操作實際上只是移動棧頂指針,并不真正刪除數據。

其他輔助函數
// 獲取棧頂元素
STDataType StackTop(Stack* ps) {assert(ps);assert(ps->_top > 0); // 確保棧不為空return ps->_a[ps->_top - 1]; // 返回棧頂元素
}// 獲取棧中元素個數
int StackSize(Stack* ps) {assert(ps);return ps->_top; // 棧頂位置就是元素個數
}// 檢查棧是否為空
int StackEmpty(Stack* ps) {assert(ps);return ps->_top == 0; // 如果棧頂為0,棧為空
}// 銷毀棧,釋放內存
void StackDestroy(Stack* ps) {free(ps->_a);        // 釋放數組內存ps->_a = NULL;       // 指針置空防止野指針ps->_top = 0;        // 重置棧頂ps->_capacity = 0;   // 重置容量
}

3. 測試代碼(test.c)

#include "Stack.h"void TestStack(Stack* p) {// 測試初始化StackInit(p);// 測試入棧 - 添加6個元素StackPush(p, 1);StackPush(p, 2);StackPush(p, 3);StackPush(p, 4);StackPush(p, 5);StackPush(p, 6);// 測試棧是否為空且查看棧頂元素if (!StackEmpty(p))printf("棧頂元素: %d \n", StackTop(p));else printf("棧為空\n");// 測試出棧 - 彈出5個元素StackPop(p);StackPop(p);StackPop(p);StackPop(p);StackPop(p);// 測試棧元素個數printf("棧中元素個數: %d \n", StackSize(p));// 銷毀棧StackDestroy(p);
}int main() {Stack p;TestStack(&p);return 0;
}

運行結果分析

運行測試代碼,你會看到以下輸出:

棧頂元素: 6
棧中元素個數: 1

這是因為我們依次壓入了1-6六個數字,然后彈出了五個,最后只剩下一個元素。

關鍵點解析

  1. 動態擴容:當棧滿時,我們通過realloc函數將容量翻倍,這是常見的擴容策略

  2. 棧頂指針_top指向的是下一個空閑位置,而不是當前棧頂元素的位置

  3. 斷言使用:使用assert確保函數參數的有效性,提高代碼健壯性

  4. 內存管理:記得在不再使用棧時調用StackDestroy釋放內存,防止內存泄漏

常見問題

  1. Q: 為什么出棧操作不真正刪除數據?
    A: 只需要移動棧頂指針,下次入棧時會覆蓋該位置,提高效率

  2. Q: 初始容量為什么設為4?
    A: 這是一個經驗值,太小會導致頻繁擴容,太大浪費內存

  3. Q: 如何修改棧中存儲的數據類型?
    A: 只需修改Stack.h中的STDataType定義即可

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

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

相關文章

北斗導航 | ARAIM(高級接收機自主完好性監測)算法在民航LPV-200進近中的具體實現流程

要詳細說明ARAIM(高級接收機自主完好性監測)算法在民航LPV-200進近中的具體實現流程,需結合ARAIM的核心邏輯(多星座融合、多假設解分離、風險優化分配)與LPV-200的嚴格要求(垂直保護級VPL≤35米、垂直告警限VAL=35米、有效監測門限EMT≤15米等),以下是 step-by-step 的…

AIPex:AI + 自然語言驅動的瀏覽器自動化擴展

AIPex:AI + 自然語言驅動的瀏覽器自動化擴展 引言 一、快速上手 1.1 安裝AIPex擴展 1.2 首次配置 1.3 界面介紹 第二章:30+工具詳解 2.1 標簽頁管理工具集 ??? **get_all_tabs - 全局標簽頁概覽** ?? **switch_to_tab - 智能標簽頁切換** ?? **標簽頁批量操作** ?? …

機器學習模型可信度與交叉驗證:通俗講解

先從一個故事說起&#xff1a;農場里的火雞科學家&#xff0c;觀察了一年發現“每天上午11點必有食物”&#xff0c;結果感恩節當天&#xff0c;它沒等到食物&#xff0c;反而成了人類的食物。這個故事告訴我們&#xff1a;只靠過去的經驗下結論&#xff0c;很可能出錯——機器…

HTML5和CSS3新增的一些屬性

1、HTML5新增特性這些新特性都有兼容性問題&#xff0c;基本是IE9以上版本瀏覽器才支持1&#xff09;新增語義化標簽2&#xff09;新增多媒體標簽音頻&#xff1a;<audio>視頻&#xff1a;<video>&#xff08;1&#xff09;視頻<video>---盡量使用mp4格式<…

Redis的RedLock

RedLock算法深度解析RedLock是Redis作者針對分布式環境設計的多節點鎖算法&#xff0c;核心目標是解決單點Redis在分布式鎖場景中的可靠性缺陷。傳統方案的局限性單節點Redis鎖的問題單點故障&#xff1a;單個Redis實例宕機導致所有鎖服務不可用可靠性不足&#xff1a;無法保證…

SpringMVC @RequestMapping的使用演示和細節 詳解

目錄 一、RequestMapping是什么&#xff1f; 二、RequestMapping 的使用演示 1.RequestMapping在方法上的使用&#xff1a; 2.RequestMapping同時在類和方法上使用&#xff1a; 3.RequestMapping指定請求參數&#xff1a; 4.RequestMapping使用Ant風格URL&#xff1a; 5.Requ…

flutter項目 -- 換logo、名稱 、簽名、打包

1、換logo, 透明底&#xff0c;下面5個尺寸&#xff0c;需要UI設計2、換名沒配置型的改名方式如下 打開app/src/main/AndroidManifest.xml3、簽名 運行 flutter doctor -vD:\project\Apk\keystore 自己建立的keystore文件夾&#xff0c; 注意命令后是 megoai-release-key(自…

【貪心算法】day9

&#x1f4dd;前言說明&#xff1a; 本專欄主要記錄本人的貪心算法學習以及LeetCode刷題記錄&#xff0c;按專題劃分每題主要記錄&#xff1a;&#xff08;1&#xff09;本人解法 本人屎山代碼&#xff1b;&#xff08;2&#xff09;優質解法 優質代碼&#xff1b;&#xff…

linux C 語言開發 (八) 進程基礎

文章的目的為了記錄使用C語言進行linux 開發學習的經歷。開發流程和要點有些記憶模糊&#xff0c;趕緊記錄&#xff0c;防止忘記。 相關鏈接&#xff1a; linux C 語言開發 (一) Window下用gcc編譯和gdb調試 linux C 語言開發 (二) VsCode遠程開發 linux linux C 語言開發 (…

從零學算法1094

1094.拼車 車上最初有 capacity 個空座位。車 只能 向一個方向行駛&#xff08;也就是說&#xff0c;不允許掉頭或改變方向&#xff09; 給定整數 capacity 和一個數組 trips , trips[i] [numPassengersi, fromi, toi] 表示第 i 次旅行有 numPassengersi 乘客&#xff0c;接他…

B2B企業營銷型AI Agent服務商推薦:誰更專業?如何選型?

一、引言&#xff1a;為什么B2B企業需要營銷型AI Agent&#xff1f;在當前競爭激烈的B2B市場中&#xff0c;企業普遍面臨幾大挑戰&#xff1a;線索獲取難&#xff1a;獲客成本持續上升&#xff0c;高質量線索難以篩選。銷售周期長&#xff1a;從初步接觸到簽單&#xff0c;往往…

算法-雙指針5.6

目錄 &#x1f33f;力扣611-有效三角形得個數 &#x1f9ca;題目鏈接&#xff1a;https://leetcode.cn/problems/valid-triangle-number/description/ &#x1f9ca;題目描述&#xff1a;?編輯 &#x1f9ca;解題思路&#xff1a; &#x1f9ca;解題代碼&#xff1a; &a…

超參數自動化調優指南:Optuna vs. Ray Tune 對比評測

點擊 “AladdinEdu&#xff0c;同學們用得起的【H卡】算力平臺”&#xff0c;注冊即送-H卡級別算力&#xff0c;80G大顯存&#xff0c;按量計費&#xff0c;靈活彈性&#xff0c;頂級配置&#xff0c;學生更享專屬優惠。 引言&#xff1a;從"手動煉丹"到"自動化…

軟考-局域網基礎考點總結

這篇文章用于整理軟考網絡相關的知識點&#xff0c;囊括了詳細的局域網基礎的考點&#xff0c;能夠讓你認真備考&#xff0c;基礎知識一網打盡&#xff0c;讓后續的學習更加通暢~ 第一部分&#xff1a;OSI七層參考模型 OSI(Open System Interconnection)模型是一個理論框架&am…

Node.js核心模塊介紹

1. fs 模塊fs&#xff08;File System&#xff09;模塊允許對文件系統進行操作&#xff0c;提供了文件讀寫、文件夾操作等功能。fs 支持同步和異步兩種 API。1.1. 常用方法讀取文件&#xff1a;異步: fs.readFile()同步: fs.readFileSync()寫入文件&#xff1a;異步: fs.writeF…

緩存三大劫攻防戰:穿透、擊穿、雪崩的Java實戰防御體系(二)

第二部分&#xff1a;緩存擊穿——熱點key過期引發的“DB瞬間高壓” 緩存擊穿的本質是“某個熱點key&#xff08;高并發訪問&#xff09;突然過期”&#xff0c;導致大量請求在同一時間穿透緩存&#xff0c;集中沖擊DB&#xff0c;形成“瞬間高壓”。 案例3&#xff1a;電商秒殺…

Linux相關概念和易錯知識點(45)(網絡層、網段劃分)

目錄1.網絡層&#xff08;1&#xff09;IP協議頭格式&#xff08;2&#xff09;工作流程2.網段劃分&#xff08;1&#xff09;五類地址&#xff08;2&#xff09;回環地址&#xff08;3&#xff09;網段的特殊地址&#xff08;4&#xff09;網絡建設我們前面暫時跳過了網絡層&a…

transition(過渡)和animation(動畫)——CSS

1.transition過渡可以為一個元素在不同狀態之間進行切換時添加過渡效果&#xff0c;實現不同狀態間的變化效果。通過觸發事件(鼠標懸停、點擊等)&#xff0c;在兩個狀態間切換。1.1 使用語法&#xff1a;transition: [property] [duration] [timing-function] [delay];property…

Spring Cloud項目國產化改造MySQL遷移達夢數據庫,SQL變更

達夢數據庫下載地址&#xff1a;https://eco.dameng.com/download 達夢數據庫安裝文檔&#xff1a;https://eco.dameng.com/document/dm/zh-cn/start/dm-install-linux.html 數據遷移SQLark工具使用 首先&#xff0c;本次MySQL遷移使用了SQLark工具 1.下載安裝SQLark https…

Cesium---1.133版本不修改源碼支持arcgis MapServer 4490切片

參照了這篇博文&#xff1a;https://blog.csdn.net/qq_19689967/article/details/121449888https://blog.csdn.net/qq_19689967/article/details/121449888 利用新版本的源碼進行了修改&#xff0c;可以實現服務加載&#xff1a; Event.js import { Check,defined} from &qu…