C語言鏈表設計及應用

鏈表

  • 鏈表
  • 節點
  • 設計鏈表項目
  • 鏈表中的傳址調用
  • 檢查申請空間
  • 鏈表尾插
  • 鏈表頭插
  • 鏈表尾部刪除
  • 鏈表頭部刪除
  • 鏈表的查找
  • 指定位置之前插入
  • 指定位置之后插入數據
  • 刪除指定位置(節點)數據
  • 刪除指定位置(節點)之后的數據
  • 鏈表的銷毀

前面學習了順序表,在順序表中,雖然可以用動態內存開辟的方法來靈活改變空間大小,但順序表本身仍然存在著一些局限性:

  • 頭插/尾插中,每插入一次數據,其它數據要提前挪動以空出空間。
  • 開辟空間是以現有空間的倍數進行的,一般為2~3倍。

而隨之帶來空間和時間兩個方向上的問題:

  • 數據頻繁地挪動需要占用時間性能
  • 空間開辟后還是會不可避免的浪費。

鏈表

概念:鏈表是一種物理存儲結構上非連續、非順序的存儲結構,數據元素的邏輯順序是通過鏈表中的指針(也叫節點、結點)鏈接次序實現的。

在這里插入圖片描述


節點

節點組成部分:

  1. 數據(實際往往是運用 / 保存指針)
  2. 指向下一個節點的指針

定義鏈接的節點結構:

struct SlistNode     //single list node  單鏈表
{int data;struct SlistNode* next;
};

設計鏈表項目

文件有

  • 源文件:Slist.c、test.c
  • 頭文件:Slist.h

鏈表中的傳址調用

鏈表中,經常會出現函數傳值調用的錯誤。
在這里插入圖片描述
如圖,想要改變鏈表plist,就要傳址操作。而其本身就是地址,因此函數的參數類型應該是二級指針。

鏈表的創建是下面這兩行代碼,創建數據和指向下一個節點的指針。數據要開辟空間,所以內容使用指針接收。

SN* Node1 = (SN*)malloc(sizeof(SN));
Node1->Data = 21;

檢查申請空間

在對鏈表進行操作(尤其是增刪)的時候,要先對空間進行檢查,防止內存溢出或者越界訪問。
此函數,申請成功返回新節點,失敗報錯。

SN* Creat_newlistNode(DataType i)
{SN* newNode = (SN*)malloc(sizeof(SN));if (newNode == NULL){perror("malloc");exit(1);}newNode->Data = i;newNode->next = NULL;return newNode;
}

此函數真正使用如下:

SN* newNold = Creat_newlistNode(i);//創建一個保存數據i的鏈表。

鏈表尾插

先考慮非空鏈表
鏈表尾插,遍歷鏈表找尾,將要插入的節點放到最后。
接著,要考慮無法遍歷的情況——空鏈表
以上思路完成后,考慮將代碼更為嚴謹、完善。如指針的合法等。
最后進行最終的測試。(每完成一個功能,也就應該測試一次。)

void SNPushBack(SN** pphead, DataType i)
{assert(pphead);SN* new = Creat_newlistNode(i);assert(new);//空鏈表和非空鏈表if (*pphead==NULL){*pphead = new;}else{SN* ptail = *pphead;while (ptail->next){ptail = ptail->next;}ptail->next = new;}
}

鏈表頭插

現申請一個新的節點newnold。
將新節點和原有鏈表連接起來,并且新節點將作為頭結點使用。

void SNPushFront(SN** pphead, DataType i)
{assert(pphead);SN* newNold = Creat_newlistNode(i);newNold->next= *pphead;*pphead = newNold;//空鏈表、非空鏈表都需要考慮(此代碼兩者都已通過)
}

鏈表尾部刪除

鏈表的尾刪,分為兩個方向考慮:存在一個節點、存在多個節點
判斷一個節點時,直接刪除
多個節點時,循環找到最后一個(并且保留前一個),然后刪除并將保留的那個指針指向置為空。

void SNPopBack(SN** pphead)
{assert(pphead && *pphead);//分為只有一個節點、多個節點if ((*pphead)->next == NULL)//  -> 優先級高于 *{free(*pphead);*pphead = NULL;}else{SN* ptail = *pphead;SN* prev = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}free(ptail);ptail = NULL;prev->next = NULL;}}

鏈表頭部刪除

頭刪只需要將鏈表指向改為下一個(在更改指向前創建臨時變量保存),
后使用臨時變量釋放掉第一個節點的空間。
最后一步是測試,多個節點、一個節點是否有問題。

void SNPopFront(SN** pphead)
{assert(pphead&& *pphead);SN* tmp = (*pphead)->next;free(*pphead);*pphead = tmp;
}

鏈表的查找

鏈表的修改,只需遍歷尋找即可。
由于查找不涉及鏈表修改,因此函數參數的形參為一級指針。
往后遍歷直到找到即可:

SN* FindSN(SN* phead, DataType i)
{assert(phead);SN* tmp = phead;while (tmp){if (tmp->Data == i){return tmp;}tmp = tmp->next;}return NULL;
}

在此函數的使用時,不要給參數帶上 & 符號!!!(鏈表節名本身就是地址類型不可再亂加&)

void test3()
{SN* one = NULL;SNPushBack(&one, 99);SNPushBack(&one, 88);SNPushBack(&one, 77);SNPushBack(&one, 66);SNPushBack(&one, 55);SNPushBack(&one, 44);SNPrint(one);SN* find=FindSN(one, 66);//注意此時不涉及改變不需要使用 & 符號if (find==NULL){printf("找不到");}else{printf("可以找到%d", find->Data);}
}

指定位置:使用上面用于查找鏈表的函數,返回值即是這個位置


指定位置之前插入

首先考慮正常情況的多個節點。
鏈表中,只能由前找后,不能從后找到前。
因此確立分清三個節點:插入節點之前的節點,插入的節點,指點位置的節點。
創建插入的節點后,建立三個結點之間的聯系。
再考慮特殊情況(只有一個節點的時候)
此時插入原理就是頭插。
不需考慮無節點情況。

void SNInsert(SN** pphead, SN* pos, DataType i)//指定位置之前插入數據
{assert(*pphead);assert(pphead);SN* NewNold = Creat_newlistNode(i);//分為一個節點、多個節點if (*pphead == pos){SNPushFront(pphead,i);}else{SN* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = NewNold;NewNold->next = pos;}
}

指定位置之后插入數據

參數只需要指定的位置和數據即可。

void SNInsertAfter(SN* pos, DataType i)
{assert(pos);SN* NewNold = Creat_newlistNode(i);NewNold->next = pos->next;pos->next = NewNold;
}

需要特別提出來說明的是,這兩句代碼的順序問題。

NewNold->next = pos->next;  //1
pos->next = NewNold;        //2

如果順序顛倒,先進行

pos->next = NewNold;   //2

再進行

NewNold->next = pos->next;  //1

造成的結果等價于NewNold->next = NewNold,這個代碼將會自己指向自己。


刪除指定位置(節點)數據

指定位置刪除數據,先考慮正常多節點情況
依舊需要弄清楚:刪除位置之前的節點、刪除位置的節點、刪除位置之后的節點。
使用循環找到刪除位置之前的節點,然后與后面的節點建立連接。
此時鏈表之中已不存在要刪除的節點,但是空間沒有釋放一定要釋放空間。

我們會發現,如果是一個節點,我們要指定位置刪除。
代碼并不適用。
所以要分情況來執行代碼,使用 if 語句將兩種情況分開討論。
一個節點,指定位置刪除的操作其實就是頭刪。拷貝或調用函數都可以。

void SNErase(SN** pphead, SN* pos)//指定位置刪除數據
{assert(pphead && *pphead);assert(pos);if (pphead == pos){(*pphead)->next = NULL;      //或者頭刪函數也行//SNPopFront(pphead);}else{SN* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}

刪除指定位置(節點)之后的數據

刪除指定位置之后的數據,思路如下:

  1. 保存這個數據(指定位置之后的數據的位置)
  2. 鏈表重新建立連接(這一步完成后,鏈表中將不存在指定位置之后的>數據)
  3. 根據預先保存的數據找到被刪除的數據,將其從內存中刪除。
void SNEraseAfter(SN* pos)
{assert(pos && pos->next);   //  -> 優先級大于 &&SN* del = pos->next;pos->next = del->next;free(del);del = NULL;
}

在測試時,出現了錯誤,記錄下來:

在這里插入圖片描述

在測試指定位置刪除時,使用findSN函數找到位置find,然后刪除了這個位置的節點。后面又想測試指定位置之后刪除,可是find這個位置的節點已經被刪除,所以無法找到find,更無法找到find后面的節點了。


鏈表的銷毀

鏈表是一個一個創建的,銷毀也是一個一個的銷毀。
思路是:創建兩個指針,一個指針銷毀節點使用,一個指針保存下一個節點。循環直到鏈表結束。

void DestorySN(SN** pphead)
{assert(pphead && *pphead);SN* pcur = *pphead;while (pcur){SN* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

以上就是我對于單鏈表的學習記錄了,單鏈表的理論到此結束。

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

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

相關文章

使用 YAML 自動化 Azure DevOps 管道

1. 在 Azure DevOps 中設置 YAML 管道 開始之前,您需要擁有一個 Azure DevOps 帳戶和一個 git 倉庫。 要創建 YAML 管道, 1. 導航至 Azure DevOps → 選擇您的項目 2. 前往“管道”→ 點擊“新建管道” 3. 選擇您的倉庫(Azure Repos、GitHub 等) 4. 選擇“Starter Pipelin…

基于Spring Boot的幼兒園管理系統

基于Spring Boot的幼兒園管理系統 源碼獲取:https://mbd.pub/o/bread/YZWXlZtsbQ 引言 在數字化轉型的浪潮中,教育行業的信息化建設顯得尤為重要。幼兒園作為基礎教育的重要環節,其管理系統的現代化水平直接關系到教育質量和運營效率。本文…

【NVIDIA-B200】 ‘CUDA driver version is insufficient for CUDA runtime version‘

目錄 一、錯誤核心原因 二、排查步驟 1. 檢查當前驅動版本 2. 檢查 CUDA 運行時版本 3. 驗證驅動與 CUDA 的兼容性 三、解決方法 1. 確保驅動正確加載 2. 重新安裝匹配的驅動與 CUDA 3. 驗證環境正確性 四、關鍵注意事項 報錯日志: bash nccl.sh ------------5.安…

Android中如何實現自動化測試

目錄 前言: 一、方法介紹 1、UI Automator 3、shell腳本 二、shell腳本實現自動化測試原理和步驟 1、 原理 2、步驟 三、shell自動化測試實例 前言: 在開發項目的過程中,我們將某個階段的需求完成并且提測,通常,在測試工程師更細致的測…

綠聯科技全球化突圍:業財一體化如何打通全球電商全鏈路數字化

綠聯科技專注數碼配件20年,產品覆蓋全球100多個國家,年銷售額突破30億。作為"連接"領域的專家,綠聯深知連接的真諦不僅在于硬件產品,更在于數據的全球化連接。在全球電商競爭日益激烈的今天,綠聯率先探索業財…

uv教程 虛擬環境

什么是uv 可以創建虛擬環境 安裝依賴 安裝uv 參見官方文檔 安裝 | uv-zh-cn 自定義安裝目錄,winr 輸入powershell,輸入如下命令 $env:UV_INSTALL_DIR "C:\Custom\Path";powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/inst…

繞過codex在vscode中登錄403的問題

codex安裝: npm i -g openai/codex codex升級: npm install -g openai/codexlatest 繞過codex在vscode中登錄403的問題: https://linux.do/t/topic/924206/4 1.在windows端powelshell登陸好codex; $env:HTTP_PROXY"http://…

軟件研發如何選對方法論?傳統計劃驅動與敏捷價值驅動的全面對比

軟件項目研發中的方法論是一個核心話題,它決定了團隊如何規劃、執行和交付軟件。下面我將對這些方法論進行一個全面的概述,從傳統的到現代的,并說明它們的核心思想、適用場景和趨勢。 一、 方法論的核心分類 軟件研發方法論主要分為兩大陣營:傳統計劃驅動(Plan-Driven)…

【服務器】將本地項目部署到服務器

當我們已經有了一個服務器后 如何將本地項目部署到服務器呢第一步,找到云服務器實例,查看公網IP地址第二步,推薦使用 Windows 自帶的 PowerShell ssh root你的公網IP # 例如: ssh root47.98.123.45如果超時,首先檢查服…

Flink中的 BinaryRowData 以及大小端

背景 本文基于 Flink 1.17.0 寫此文章的目的是為了說明 Flink 堆內和堆外內存以及 內部 BinaryRowData 行處理的優化。 分析 堆內和堆外內存 跟Spark的內存管理不一樣,Flink 中的堆內和堆外一直都是存在的。 堆內內存(JVM Heap)存儲用戶對象和…

HTTP/3.0:網絡通信的技術革新與性能飛躍

🌐 HTTP/3.0:網絡通信的技術革新與性能飛躍 Refer:PPP PRIVATE NETWORK? 2 企業級虛擬以太網接入綜合解決方案介紹 🚀 引言:悄然來臨的網絡革命 你是否曾期待視頻加載卡頓成為過去?YouTube 已經邁出了重…

【golang學習筆記 gin 】1.1 路由封裝和mysql 的使用封裝

安裝gin go get -u github.com/gin-gonic/gin go get -u github.com/go-sql-driver/mysql創建相關目錄 gotest->conifg->database.go->redis.go->controller ->index.go->model->user.go->router->router.gomain.go 創建用戶模型 package model imp…

SQL 層面行轉列

背景:如果對一些評論、點贊、收藏等互動數據,使用了按照 type 分類存儲,num 也是對應的。這樣如果創建一個帖子,那么就會出現 3 行數據(type 不同,num 不同,對應評論點贊和收藏)&…

langchain4j筆記篇(陽哥)

一 概述1.1 概述langchain4j:langchain for java1.2 作用langchain4j的目標是簡化將LLM集成到java應用程序中的過程。二 案例簡單helloworld2.1 大模型調用三件套1.阿里百煉平臺的通義模型: https://bailian.console.aliyun.com/2獲取api-key&#x…

有鹿機器人的365天奇幻日記:我在景區當掃地僧

第一章 古建守護者:2cm的極致藝術琉璃瓦下的秘密記得那是個晨霧繚繞的清晨,我接到首個重要任務:清掃明代琉璃碑亭。這里的每塊地磚都是文物,傳統清潔工具根本不敢靠近。每天以2cm的精準貼邊沿碑座作業,如今我每周都要為…

Objective-C方法參數標簽怎么設置

在Objective-C中,方法名稱可以通過幾個標簽名稱組成,這是跟C/C中完全不一樣的地方。每個標簽都是字段冒號的寫法,冒號后面是方法的參數,參數包括參數類型和參數變量,其中參數類型要用括號括起。方法參數的標簽是通過在…

20250910_《SQL Server 數據庫事務日志定期清理方案(精簡優化版)》以10.1.1.31服務器的gtp-default數據庫為例

《SQL Server 數據庫事務日志定期清理方案(精簡優化版)》 一、前提條件 數據庫 gtp-default 已設置為完整恢復模式 (FULL)。 每天凌晨02:00執行完整備份,保證日志備份可用。 SQL Server Agent 已啟用。 作業所有者為 sa,具有 sysadmin 權限。 Agent 服務賬號 NT Service\S…

實習項目包裝--HTTP 協議和 Web API

好的,完全沒問題!你問到了一個非常核心且基礎的知識領域,這是現代Web開發和幾乎所有網絡應用的基石。我們暫別嵌入式系統,專門來上一堂關于 HTTP 協議和 Web API 的詳細課程。 我會從最根本的概念講起,逐步深入到你所…

ICCV-2025 | 中科院自動化所世界模型助力具身導航!NavMorph:連續環境中的視覺語言導航自演化世界模型

作者:Xuan Yao1,2^{1,2}1,2, Junyu Gao1,2^{1,2}1,2, Changsheng Xu1,2,3^{1,2,3}1,2,3單位:1^{1}1中科院自動化所多模態人工智能系統國家重點實驗室,2^{2}2中國科學院大學人工智能學院,3^{3}3鵬城實驗室論文標題:NavM…

【ARDUINO】ESP8266的AT指令返回內容集合

一、基礎測試指令(確認模塊通信) 1. AT(測試模塊是否響應) 功能:檢測ESP8266與控制器(如Arduino)的串口通信是否正常。 返回內容: 成功:OK(無額外數據,僅確認通信正常) 失敗:無返回(可能是波特率不匹配、接線錯誤) 示例:發送:AT 返回: OK二、Wi-Fi模式配置指…