C語言_數據結構總結6:鏈式棧

?純c語言代碼,不涉及C++

順序棧的實現,歡迎查看這篇文章:C語言_數據結構總結5:順序棧-CSDN博客?

0. 結構單元

#include<stdio.h>
#include<stdlib.h>

typedef int ElemType;
typedef struct Linknode {
?? ?ElemType data; ?//數據域
?? ?struct Linknode* next; ?//指針域
}LinkStack;

1.1? 初始化(返回頭結點) 推薦

LinkStack* InitLinkStack1() {LinkStack* L = (LinkStack*)malloc(sizeof(LinkStack));  //定義一個頭結點(棧頂結點)if (L == NULL) {printf("內存分配失敗\n");return NULL;}L->next = NULL;return L;
}

1.2??初始化方法2(不返回頭結點指針) 不推薦

void InitLinkStack2(LinkStack** L) {*L = (LinkStack*)malloc(sizeof(LinkStack));  //定義一個頭結點if (*L == NULL){printf("內存分配失敗!\n");return;  //提前結束該函數}(*L)->next = NULL;
}

首先:在鏈式棧的初始化操作中,返回頭結點的指針是一種常見且推薦的做法,但并不是絕對必須的,
推薦返回頭結點指針的原因:
1.方便后續操作
返回頭結點的指針可以讓調用者方便地對鏈式棧進行后續操作。因為鏈式棧的各種操作(如入棧、出棧、獲取棧頂元素等)都需要通過頭結點來訪問棧中的元素,調用者持有頭結點的指針后,就可以直接將其作為參數傳遞給這些操作函數

2.符合模塊化設計原則
將初始化操作設計為返回頭結點指針,使得初始化函數的功能更加獨立和清晰。調用者可以明確知道初始化函數會返回一個指向鏈式棧頭結點的指針,便于在不同的代碼模塊中復用該函數。

2. 1 判空方法1?(采用指針傳遞) 推薦

int LinkStackEmpty1(LinkStack* L) {return L->next == NULL;
}

2.2? 判空方法2?(采用值傳遞) 不推薦

int LinkStackEmpty2(LinkStack L) {return L.next == NULL;
}

首先:從語法和功能角度來看,傳入 LinkStack L 是可行的。
因為判空操作僅僅是讀取棧的信息,不涉及對棧結構的修改,所以即使采用值傳遞,也能正確完成判空的邏輯。

在上述代碼中,LinkStackEmpty2 函數接收的是 LinkStack 類型的變量,通過判斷其 next 指針是否為 NULL 來確定棧是否為空。

不建議值傳遞(傳入LinkStack L)的原因(其它類似操作以此類推):
1. 內存開銷較大
當使用值傳遞(傳入 LinkStack L)時,會在函數調用時復制整個 LinkStack 結構體。
對于鏈式棧來說,雖然結構體本身可能不大,但復制操作仍然會帶來額外的內存開銷。而使用指針傳遞(傳入 LinkStack* L),只需要復制一個指針,其內存開銷遠遠小于復制整個結構體。

2. 性能問題
值傳遞的復制操作會消耗一定的時間,尤其是在結構體較大或者頻繁調用判空函數的情況下,會對程序的性能產生影響。指針傳遞則避免了這種復制操作,能夠提高程序的執行效率。

3. 代碼一致性
在鏈式棧的其他操作(如入棧、出棧等)中,通常需要修改棧的結構,因此需要使用指針傳遞。為了保持代碼的一致性,建議在判空操作中也使用指針傳遞,這樣可以讓代碼更加統一和易于理解。

3. 入棧

int push(LinkStack* L, ElemType value) {LinkStack* s = (LinkStack*)malloc(sizeof(LinkStack));if (s == NULL){printf("內存分配失敗!\n");return -2;}s->data = value;s->next = L->next;L->next = s;return 0;  //入棧(插入成功)
}

4. 出棧

?value:用于存儲出棧元素的值,是一個指向元素類型的指針

int pop(LinkStack* L, ElemType* value) {if (LinkStackEmpty1(L)){printf("棧空,無法出棧!\n");return -2;}LinkStack* p = L->next;*value = p->data;L->next = p->next;free(p);return 0;  //出棧成功}

5. 獲取棧頂元素

int gettopValue(LinkStack* L, ElemType* value) {if (LinkStackEmpty1(L)){printf("棧空,無法獲取元素!\n");return -2;}LinkStack* p = L->next;*value = p->data;  // 合并:*value = L->next->datareturn 0;  //獲取棧頂信息成功
}

6. 打印棧內元素

void printLinkStack(LinkStack L) {if (LinkStackEmpty1(&L)){printf("棧空,無法獲取元素!\n");return;}LinkStack* p = L.next;printf("棧中的元素(從棧頂到棧底)為: ");while (p != NULL) {printf("%d ", p->data);p = p->next;}printf("\n-----------------------------------------------\n");
}

7.銷毀

void destroyLinkStack(LinkStack* L) {LinkStack* p = L;while (p != NULL) {LinkStack* s = p;p = p->next;free(s);}
}

8.測試

int main() {//第二種初始化方式LinkStack* L1;  // 定義一個頭指針InitLinkStack2(&L1);  // 初始化時,將該頭指針指向了頭結點//第一種初始化方式LinkStack* L = InitLinkStack1();if (L == NULL){return -1;  }printLinkStack(*L);  // 棧空,無法獲取元素!// 測試進棧操作push(L, 11);push(L, 22);push(L, 33);printLinkStack(*L);  // 棧中的元素(從棧頂到棧底)為: 33 22 11// 獲取棧頂元素ElemType value;if (gettopValue(L,&value) == 0){printf("當前棧頂元素為:%d\n", value);  // 當前棧頂元素為:33}// 測試出棧操作if (pop(L, &value) == 0) {printf("出棧的元素為:%d\n", value);  // 出棧的元素為:33}printf("元素出棧后,");printLinkStack(*L);  // 元素出棧后,棧中的元素(從棧頂到棧底)為: 22 11// 銷毀棧destroyLinkStack(L);return 0;
}

9. 完整代碼

//鏈式棧的基本實現
//頭結點的下一個結點是棧頂元素
#include<stdio.h>
#include<stdlib.h>typedef int ElemType;
typedef struct Linknode {ElemType data;  //數據域struct Linknode* next;  //指針域
}LinkStack;// 操作1——初始化(返回頭結點) 推薦
LinkStack* InitLinkStack1() {LinkStack* L = (LinkStack*)malloc(sizeof(LinkStack));  //定義一個頭結點(棧頂結點)if (L == NULL) {printf("內存分配失敗\n");return NULL;}L->next = NULL;return L;
}// 操作1.1——初始化(不返回頭結點指針) 不推薦
void InitLinkStack2(LinkStack** L) {*L = (LinkStack*)malloc(sizeof(LinkStack));  //定義一個頭結點if (*L == NULL){printf("內存分配失敗!\n");return;  //提前結束該函數}(*L)->next = NULL;
}// 操作2——判空(采用指針傳遞) 推薦
int LinkStackEmpty1(LinkStack* L) {return L->next == NULL;
}// 操作2.1——判空(采用值傳遞) 不推薦
int LinkStackEmpty2(LinkStack L) {return L.next == NULL;
}// 操作3——入棧
int push(LinkStack* L, ElemType value) {LinkStack* s = (LinkStack*)malloc(sizeof(LinkStack));if (s == NULL){printf("內存分配失敗!\n");return -2;}s->data = value;s->next = L->next;L->next = s;return 0;  //入棧(插入成功)
}// 操作4——出棧,類似于鏈表的頭刪法
// value:用于存儲出棧元素的值,是一個指向元素類型的指針
int pop(LinkStack* L, ElemType* value) {if (LinkStackEmpty1(L)){printf("棧空,無法出棧!\n");return -2;}LinkStack* p = L->next;*value = p->data;L->next = p->next;free(p);return 0;  //出棧成功}// 操作5——獲取棧頂元素
int gettopValue(LinkStack* L, ElemType* value) {if (LinkStackEmpty1(L)){printf("棧空,無法獲取元素!\n");return -2;}LinkStack* p = L->next;*value = p->data;  // 合并:*value = L->next->datareturn 0;  //獲取棧頂信息成功
}// 操作6——打印棧
void printLinkStack(LinkStack L) {if (LinkStackEmpty1(&L)){printf("棧空,無法獲取元素!\n");return;}LinkStack* p = L.next;printf("棧中的元素(從棧頂到棧底)為: ");while (p != NULL) {printf("%d ", p->data);p = p->next;}printf("\n-----------------------------------------------\n");
}// 操作7——銷毀棧
void destroyLinkStack(LinkStack* L) {LinkStack* p = L;while (p != NULL) {LinkStack* s = p;p = p->next;free(s);}
}int main() {//第二種初始化方式LinkStack* L1;  // 定義一個頭指針InitLinkStack2(&L1);  // 初始化時,將該頭指針指向了頭結點//第一種初始化方式LinkStack* L = InitLinkStack1();if (L == NULL){return -1;  }printLinkStack(*L);  // 棧空,無法獲取元素!// 測試進棧操作push(L, 11);push(L, 22);push(L, 33);printLinkStack(*L);  // 棧中的元素(從棧頂到棧底)為: 33 22 11// 獲取棧頂元素ElemType value;if (gettopValue(L,&value) == 0){printf("當前棧頂元素為:%d\n", value);  // 當前棧頂元素為:33}// 測試出棧操作if (pop(L, &value) == 0) {printf("出棧的元素為:%d\n", value);  // 出棧的元素為:33}printf("元素出棧后,");printLinkStack(*L);  // 元素出棧后,棧中的元素(從棧頂到棧底)為: 22 11// 銷毀棧destroyLinkStack(L);return 0;
}

10. 運行截圖

本人菜鳥一只,文章如有問題,歡迎評論區指正!

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

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

相關文章

新品速遞 | 多通道可編程衰減器+矩陣系統,如何破解復雜通信測試難題?

在無線通信技術快速迭代的今天&#xff0c;多通道可編程數字射頻衰減器和衰減矩陣已成為測試領域不可或缺的核心工具。它們憑借高精度、靈活配置和強大的多通道協同能力&#xff0c;為5G、物聯網、衛星通信等前沿技術的研發與驗證提供了關鍵支持。從基站性能測試到終端設備校準…

AI自動化應用的影響

生產力的迭代也終將伴隨著一代人的落幕。 2025年是AI應用爆發的開局之年&#xff0c;預計3-5年現有生產關系將出現顛覆性改革。 AI自動化對經濟和就業的影響是一個復雜且多維的問題&#xff0c;其長期影響取決于技術進步、政策調控、社會適應能力等多重因素的綜合作用。以下從技…

潤開鴻重磅首發基于“RISC-V+OpenHarmony+星閃”的“鴻銳”AI開發平臺

潤開鴻重磅首發基于“RISC-VOpenHarmony星閃”的“鴻銳”AI開發平臺 2月28日&#xff0c;2025中國RISC-V生態大會在北京中關村國際創新中心隆重召開。作為領先的鴻蒙生態專業技術公司和終端操作系統發行版提供商&#xff0c;以及不斷推進基于RISC-V與OpenHarmony全棧開源生態構…

Java 深度復制對象:從基礎到實戰

目錄 一、深度復制的概念二、實現深度復制的方法1. 使用序列化2. 手動實現深度復制 三、總結 在 Java 編程中&#xff0c;對象的復制是一個常見的需求。然而&#xff0c;簡單的復制操作&#xff08;如直接賦值&#xff09;只會復制對象的引用&#xff0c;而不是創建一個新的對象…

C++ Primer 交換操作

歡迎閱讀我的 【CPrimer】專欄 專欄簡介&#xff1a;本專欄主要面向C初學者&#xff0c;解釋C的一些基本概念和基礎語言特性&#xff0c;涉及C標準庫的用法&#xff0c;面向對象特性&#xff0c;泛型特性高級用法。通過使用標準庫中定義的抽象設施&#xff0c;使你更加適應高級…

FFmpeg-chapter7和chapter8-使用 FFmpeg 解碼視頻(原理篇和實站篇)

解碼流程如下圖 流程&#xff1a;首先&#xff0c;通過 avcodec_alloc_context3(nullptr) 分配一個 AVCodecContext 結構體&#xff0c;然后使用 avcodec_parameters_to_context 將參數復制到上下文中&#xff0c;接著通過 avcodec_find_decoder 查找指定的解碼器&#xff0c;并…

2025 docker安裝TiDB數據庫

1.確保安裝了docker和docker-compose sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-composesudo chmod x /usr/local/bin/docker-compose2.編寫 Docker Compose 文…

定制化開發的WooCommerce獨立站商城更安全

定制化開發的WooCommerce獨立站商城在安全性、交易風險控制以及整體用戶體驗方面有顯著優勢。以下是定制化開發在這些方面的具體表現&#xff1a; 1. 安全性更高 定制化開發允許開發者從底層架構開始設計和優化&#xff0c;確保網站的安全性。以下是具體表現&#xff1a; (1…

CSS【實戰】模擬 html 的 title 屬性(鼠標懸浮顯示提示文字)

效果 原理 提示內容的定位&#xff1a;子絕父相鼠標懸浮前&#xff0c;提示內容visibility: hidden;通過 :hover 觸發鼠標懸浮樣式&#xff0c;提示內容變為 visibility: visible; 代碼 <!DOCTYPE html> <html lang"en"><head><meta charset&qu…

K8s控制器Deployment詳解

回顧 ReplicaSet 控制器,該控制器是用來維護集群中運行的 Pod 數量的&#xff0c;但是往往在實際操作的時候&#xff0c;我們反而不會去直接使用 RS&#xff0c;而是會使用更上層的控制器&#xff0c;比如說 Deployment。 Deployment 一個非常重要的功能就是實現了 Pod 的滾動…

【MYSQL數據庫異常處理】執行SQL語句報超時異常

MYSQL執行SQL語句異常&#xff1a;The last packet successfully received from the server was 100,107 milliseconds ago. The last packet sent successfully to the server was 100,101 milliseconds ago. 這個錯誤表明 MySQL 服務器與 JDBC 連接之間的通信超時了。通常由…

HJ C++11 Day2

Initializer Lists 對于一個類P class P{P(int a, int b){cout << "P(int, int), a" << a << ", b " << b << endl;}P(initializer_list<int> initlist){cout << "P(initializer_list<int>), val…

樹莓派5首次開機保姆級教程(無顯示器通過VNC連接樹莓派桌面)

第一次開機詳細步驟 步驟一&#xff1a;樹莓派系統燒錄1 搜索打開燒錄軟件“Raspberry Pi Imager”2 選擇合適的設備、系統、SD卡3 燒錄配置選項 步驟二&#xff1a;SSH遠程樹莓派1 樹莓派插電2 網絡連接&#xff08;有線或無線&#xff09;3 確定樹莓派IP地址 步驟三&#xff…

裝飾器模式--RequestWrapper、請求流request無法被重復讀取

目錄 前言一、場景二、原因分析三、解決四、更多 前言 曾經遇見這么一段代碼&#xff0c;能看出來是把request又重新包裝了一下&#xff0c;核心信息都不會改變 后面了解到這叫 裝飾器模式&#xff08;Decorator Pattern&#xff09; &#xff1a;也稱為包裝模式(Wrapper Pat…

大語言模型進化論:從達爾文到AI的啟示與展望

文章大綱 引言大語言模型中的“進化論”思想體現遺傳變異過度繁殖和生存斗爭大模型“過度繁殖”與“生存競爭”機制解析**一、過度繁殖:技術迭代的指數級爆發****二、生存競爭:計算資源的達爾文戰場****三、生存競爭勝出關鍵要素****四、行業競爭格局演化趨勢**核心結論自然選…

監聽 RabbitMQ 延時交換機的消息數、OpenFeign 路徑參數傳入斜杠無法正確轉義

背景 【MQ】一套為海量消息和高并發熱點消息&#xff0c;提供高可用精準延時服務的解決方案 我現在有一個需求&#xff0c;就是監聽 RabbitMQ 一個延時交換機的消息數&#xff0c;而 RabbitTemplate 是不存在對應的方法來獲取的。 而我們在 RabbitMQ 的控制臺卻可以發現延時交…

分布式網絡

分布式網絡&#xff08;Distributed Network&#xff09;指的是一種計算機網絡架構&#xff0c;其中計算資源&#xff08;計算、存儲、數據處理等&#xff09;分布在多個物理或邏輯上的節點上&#xff0c;而不是集中在單一的服務器或數據中心中。這種架構的主要目標是提高系統的…

【Elasticsearch】Elasticsearch 中使用 HDFS 存儲快照

在 Elasticsearch 中使用 HDFS 存儲快照的步驟如下&#xff1a; 1.安裝 HDFS 插件 要使用 HDFS 存儲 Elasticsearch 的索引快照&#xff0c;需要在 Elasticsearch 集群的所有節點上安裝 HDFS 插件。 ? 在線安裝&#xff1a;適用于網絡環境良好的場景&#xff0c;執行以下命…

淺談 DeepSeek 對 DBA 的影響

引言&#xff1a; 在人工智能技術飛速發展的背景下&#xff0c;DeepSeek 作為一款基于混合專家模型&#xff08;MoE&#xff09;和強化學習技術的大語言模型&#xff0c;正在重塑傳統數據庫管理&#xff08;DBA&#xff09;的工作模式。通過結合其強大的自然語言處理能力、推理…

STM32F4 UDP組播通信:填一填ST官方HAL庫的坑

先說寫作本文的原因&#xff0c;由于開項目開發中需要用到UDP組播接收的功能&#xff0c;但是ST官方沒有提供合適的參考&#xff0c;使用STM32CubeMX生成的代碼也是不能直接使用的&#xff0c;而我在網上找了一大圈&#xff0c;也沒有一個能夠直接解決的方案&#xff0c;deepse…