數據結構總綱以及單向鏈表詳解:

以下是基于筆記更詳細的知識梳理,從概念到細節逐層拆解,幫你吃透數據結構核心要點:

數據結構部分的重點內容:

在這里插入圖片描述

一、數據結構基礎框架

(一)邏輯結構(關注元素間“邏輯關系”)

筆記里提到“集合、線性、樹形、圖形結構”,具體含義:

  • 集合結構:元素間僅“同屬一個集合”的關系,無明確關聯規則(如存一批用戶 ID,相互獨立 )。

  • 線性結構:元素像排隊,一對一順序關聯(如數組、鏈表,每個元素(除首尾)有唯一前驅和后繼 )。

  • 在這里插入圖片描述

  • 樹形結構:元素是“一對多”層級關系(如公司組織架構,總經理→部門經理→員工 ),典型如二叉樹(每個節點最多倆子節點 )。

  • 在這里插入圖片描述

  • 圖形結構:元素“多對多”關聯(如社交網絡好友關系,A 可連 B、C,B 也能連 C、D ),強調復雜網狀連接。
    在這里插入圖片描述

(二)物理結構(關注“內存怎么存” )

筆記里的順序、鏈式、索引、散列,是數據在內存的存儲方式,直接影響增刪查改效率

  • 順序結構(如數組)

    • 存儲特點:占一整塊連續內存,像火車車廂連成片。比如 int arr[5],5 個 int 依次存在內存,地址連續。
    • 訪問效率:因內存連續,用下標訪問(如 arr[2] ),CPU 直接算偏移量,時間復雜度 O(1)O(1)O(1)(秒查 )。
    • 增刪痛點:插入/刪除元素,后續元素得“搬家”。比如數組 [1,2,3,4] 要在第 2 位插 5,就得把 2、3、4 后移,數據量大時超耗時,復雜度 O(n)O(n)O(n)
    • 內存碎片隱患:若提前分配大內存(比如預開 100 長度數組,實際只用 20 ),剩下 80 可能因“不連續”被浪費(內部碎片 )。
  • 鏈式結構(如鏈表)

    • 存儲特點:元素(節點)分散在內存,靠指針“牽線”。每個節點存數據 + 指向下一節點的指針(單向鏈表 ),雙向鏈表還多一個指向前驅的指針。
    • 增刪優勢:插入/刪除只需改指針。比如單向鏈表刪節點 B,只要讓 A 的指針跳過 BC;插入同理,改前后指針就行,復雜度 O(1)O(1)O(1)(定位到位置后秒改 )。
    • 查找劣勢:因內存不連續,找元素得從頭遍歷。比如找第 10 個節點,必須從表頭開始,一個個指針跳,復雜度 O(n)O(n)O(n)(數據多了超慢 )。
    • 內存利用靈活:不用預分配連續大內存,元素按需“零散”分配,能減少內部碎片,但動態分配多了可能產生外部碎片(小內存塊難利用 )。
  • 索引結構(筆記里“索引表”相關)

    • 核心邏輯:額外建“索引表”,存數據關鍵字 + 對應存儲位置(地址 )。比如查字典,索引表像“目錄”,找 “數據結構” 詞條,先查目錄找頁碼,再翻對應頁。
    • 適用場景:數據量大、查詢頻繁時,用索引加速。比如數據庫查用戶,用 “手機號” 做索引,不用遍歷全表,直接定位存儲位置,查得快。
    • 代價:維護索引表占額外內存,且增刪數據時,索引表也得跟著更新,耗性能。
  • 散列結構(哈希表)

    • 核心邏輯:用 哈希函數,把數據關鍵字(如用戶 ID )映射成內存地址。比如哈希函數 f(key)=key%10key=123 就存在地址 123%10=3 位置。
    • 查詢優勢:理想情況,直接算地址訪問,復雜度 O(1)O(1)O(1)(和數組下標訪問一樣快 )。
    • 哈希沖突問題:不同關鍵字可能算出相同地址(比如 1222%10=2 ),得用鏈表法、開放尋址法解決,處理沖突會增加復雜度。

二、鏈表(筆記重點,掰開揉碎講)

在這里插入圖片描述

(一)鏈表的“家族成員”

筆記里提到單向、雙向、內核鏈表、循環鏈表,逐個說:

  • 單向鏈表

    • 結構:節點 = 數據域(存值,如 int data ) + 指針域(存下一節點地址,如 struct node *pnext )。表頭是 *phead,表尾節點 pnext=NULL(標志結束 )。
    • 操作限制:只能從表頭往后遍歷,想找前一個節點?沒指針,得從頭再來,所以反向操作超麻煩(比如刪節點,得先找它前驅,單向鏈表只能遍歷 )。
  • 雙向鏈表

    • 結構升級:節點多一個指針域(struct node *pprev ),指向前一節點。這樣,往前、往后遍歷都能實現。
    • 實用場景:頻繁需要“前后跳轉”的場景。比如瀏覽器歷史記錄,回退(往前找 )、前進(往后找 ),雙向鏈表更順手。
  • 循環鏈表

    • 變種玩法:表尾節點的 pnext 不指向 NULL,而是指向表頭,形成環。比如單向循環鏈表,從任意節點出發,能遍歷全表;雙向循環鏈表同理,前后指針都能繞環。
    • 典型應用:操作系統“時間片輪轉”調度,多個進程用循環鏈表管理,輪流執行,到表尾自動回到表頭。
  • 內核鏈表(進階,理解設計思想)

    • 設計巧妙:不把數據直接放節點,而是讓節點“嵌入”數據結構里。比如 Linux 內核鏈表,用 struct list_head 做通用節點,其他結構體(如進程控制塊 task_struct )包含這個節點,實現“用一套鏈表代碼管理所有數據”,高度解耦、復用性強。
(二)鏈表的“對象封裝”(筆記里 struct link 相關 )
  • 為啥封裝:直接操作節點太零散,封裝成“鏈表對象”,方便管理。
  • struct link 里的“小心思”
    • struct node *phead:表頭指針,找鏈表入口。
    • int clen:存節點個數,想知道鏈表多長,直接讀 clen,不用遍歷統計。
    • 操作函數配套:創建鏈表(init_link() )、插入節點(insert_node() )、刪除節點(delete_node() )、銷毀鏈表(destroy_link() )等,把鏈表當“對象”用,邏輯更清晰。

三、內存碎片(筆記里“內/外碎片” )

(一)內部碎片
  • 咋產生的:用順序結構(如數組)或某些“規則數據類型”時,預分配的內存沒被完全利用。比如 C 語言 struct 按內存對齊分配,可能多占幾個字節;數組開 100 長度,只用 50,剩下 50 因“屬于數組”不能被其他數據用,成了內部碎片。
(二)外部碎片
  • 核心問題:動態分配內存(如鏈表頻繁 malloc ),釋放后,小內存塊“零散分布”,無法合并成大內存塊。比如多次 malloc 小節點,釋放后內存里有很多小空閑塊,新數據要大內存時,這些小塊沒法用,成了外部碎片。

四、數據結構“常用操作基石”

(一)指針
  • 關鍵作用:鏈式結構的“命脈”,鏈表靠指針串節點;動態內存分配(malloc )返回的也是指針,管理堆內存離不開它。
(二)結構體(struct
  • 定制化容器:把不同類型數據“打包”。比如鏈表節點 struct node,把 int data(數據 )和 struct node *pnext(指針 )放一起,讓數據 + 關聯關系“一體化”。
(三)動態內存分配(malloc/free 等 )
  • 靈活雙刃劍:鏈表節點按需 malloc,用多少開多少;但頻繁分配/釋放,容易內存泄漏(忘 free )、產生外部碎片,得小心管理。

五、總結(知識串聯,更清晰 )

數據結構的核心是**“用啥結構存數據 + 咋高效操作數據”**:

  • 存數據前,選邏輯結構(比如一對一關系用線性結構,多對多用圖形結構 )。
  • 存的時候,選物理結構(數組存連續內存,鏈表存零散內存,索引/散列加速查詢 )。
  • 操作數據時,鏈表靠指針玩“增刪自由”,數組靠下標玩“訪問速度”,各有優劣。

筆記里的鏈表、內存碎片、動態分配,都是圍繞“怎么高效存、改、查數據”展開,理解這些,學隊列、棧、樹、圖時,邏輯會更順(比如隊列基于數組/鏈表實現,本質是線性結構的“特殊規則操作” )。
在這里插入圖片描述
在這里插入圖片描述

課上代碼:

需要做到多練習,自己理解完單向鏈表之后多敲代碼熟練運用:

封裝函數部分:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include"link.h"
LINK_T *creat_link()
{LINK_T *plink=malloc(sizeof(LINK_T));if(plink==NULL){printf("malloc plink error");return NULL;}plink->phead=NULL;plink->clen=0;return plink;
}//頭插入:
int insert_node(LINK_T *plink,node_type data)
{NODE_T *pnode=malloc(sizeof(NODE_T));if(pnode==NULL){printf("malloc pnode error");return -1;}pnode->data=data;pnode->pnext=plink->phead;plink->phead=pnode;plink->clen++;return 0;
}
//遍歷:
void link_for_each(LINK_T *plink)
{NODE_T *p=plink->phead;while(p!=NULL){printf("%d ", p->data );p=p->pnext;}printf("\n");
}
//遍歷查找結點數據:
NODE_T *find_link(LINK_T *plink,node_type data)
{NODE_T *p=plink->phead;while(p!=NULL){if(p->data==data){printf("found!");return p;}p=p->pnext;}return NULL;
}
//修改結點數據:
int change_link(LINK_T *plink,node_type olddata,node_type newdata)
{NODE_T *p=find_link(plink,olddata);if(p==NULL){printf("nofound!");return -1;}p->data=newdata;return 0;
}//頭刪:
void delet_firstNode(LINK_T *plink)
{NODE_T *p=plink->phead;plink->phead=p->pnext;free(p);p=NULL;plink->clen--;
}
//指定數據對應的結點進行刪除:
int delet_specified_node(LINK_T *plink,node_type data)
{NODE_T *p=find_link(plink,data);if(p==NULL){printf("nofound!");return -1;}NODE_T *p_prehand=plink->phead;if(p_prehand==NULL){printf("無結點,無法繼續刪除結點");return -1;}while(p_prehand!=NULL){if(p_prehand->pnext==p){p_prehand->pnext=p->pnext;break;}p_prehand=p_prehand->pnext;}free(p);p=NULL;plink->clen--;return 0;
}
//封裝函數實現單向鏈表的尾插:
NODE_T *findTheLastNode(LINK_T *plink)
{NODE_T *p=plink->phead;if(p==NULL){return NULL;}while(p->pnext!=NULL){p=p->pnext;}return p;
}
int insertOneNodeAtTheEndOfTheLinkedList(LINK_T *plink,node_type data)
{NODE_T *pnode=malloc(sizeof(NODE_T));if(pnode==NULL){printf("malloc error!");return -1;}NODE_T *plastnode=findTheLastNode(plink);if(plastnode==NULL){plink->phead=pnode;plink->clen++;pnode->data=data;pnode->pnext=NULL;}else{plastnode->pnext=pnode;pnode->pnext=NULL;pnode->data=data;plink->clen++;}return 0;
}
//封裝函數實現單向鏈表的尾刪,注意只有一個結點的情況!
int delet_lastnode(LINK_T *plink)
{NODE_T *p=plink->phead;if(p==NULL){printf("無結點可刪除,程序終止!");return -1;}else{if(p->pnext==NULL){free(p);plink->phead=NULL;plink->clen--;return 0;}else{while(p->pnext->pnext!=NULL){p=p->pnext;}free(p->pnext);p->pnext=NULL;plink->clen--;}}return 0;
}
int deletAllNode(LINK_T *plink)
{NODE_T *p=plink->phead;if(p==NULL){printf("無結點可刪除");return -1;}while(plink->phead!=NULL){while(p!=NULL){p=p->pnext;}delet_lastnode(plink);}
}

頭文件部分:

#ifndef _LINK_H_
#define _LINK_H_
typedef int node_type;
typedef struct node
{node_type data;struct node *pnext;
}NODE_T;
typedef struct link
{NODE_T *phead;int clen;
}LINK_T;extern LINK_T *creat_link();
extern int insert_node(LINK_T *plink,node_type data);
extern void link_for_each(LINK_T *plink);
extern NODE_T *find_link(LINK_T *plink,node_type data);
extern int change_link(LINK_T *plink,node_type olddata,node_type newdata);
extern void delet_firstNode(LINK_T *plink);
extern int delet_specified_node(LINK_T *plink,node_type data);
extern NODE_T *findTheLastNode(LINK_T *plink);
extern int insertOneNodeAtTheEndOfTheLinkedList(LINK_T *plink,node_type data);
extern int delet_lastnode(LINK_T *plink);
extern int deletAllNode(LINK_T *plink);
#endif

主函數本部分:

#include<stdio.h>
#include"link.h"
#include<stdlib.h>
int main(void)
{link_t *plink=creat_Link();if(plink==NULL){return -1;}insert_link_head(plink,1);insert_link_head(plink,2);insert_link_head(plink,3);insert_link_head(plink,4);insert_link_head(plink,5);link_for_each(plink);
//	Node_t *pfind=find_link(plink,2);
//	if(pfind==NULL)
//	{
//		printf("nofind");
//	}
//	else
//	{
//		printf("found,value=%d\n",pfind->data);
//	}
//	change_link(plink,2,3);
//	link_for_each(plink);deletFirstNode(plink);return 0;
}

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

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

相關文章

模型學習系列之參數

背景 “GLM-4.5擁有 3550 億總參數量&#xff0c;其中 320 億活躍參數&#xff1b;GLM-4.5-Air 采用更緊湊的設計&#xff0c;擁有 1060 億總參數量&#xff0c;其中 120 億活躍參數。” 定義與關系 總參數量&#xff1a;模型中所有可訓練參數的總和&#xff08;包括嵌入層、注…

[創業之路-535]:軟件需要原型驗證、產品需要原型驗證、商業模式也需要原型驗證

原型驗證在軟件、產品開發以及商業模式探索中均扮演著至關重要的角色&#xff0c;它通過低成本、快速迭代的方式&#xff0c;幫助團隊驗證核心假設、降低風險并優化方案。以下是針對這三個領域的具體分析&#xff1a;一、軟件原型驗證&#xff1a;從概念到可交互的模型核心目的…

sublime text2配置

sublime text2配置背景配置其他背景 之前下載了就把它當記事本在使用。但是&#xff0c;在使用過程中&#xff0c;有些場景很痛苦。如果說找一個字符串中的某一部分&#xff0c;雖然它通過了這個功能&#xff0c;但是不夠明顯&#xff0c;看瞎了。。。 配置 下面是我改的一些選…

本地通信的選擇:為什么組播比廣播更適合多進程協作?

零、深入解析Linux本地通信機制,對比廣播與組播的核心差異 本地組播能讓多進程收到消息,而本地廣播不行,核心原因在于兩者的設計目標、網絡協議處理邏輯以及內核轉發機制存在本質差異。具體可以從以下幾個角度理解: 1. 通信模式與目標地址的本質區別 組播(Multicast):…

7-Django項目實戰[user]-發送郵件激活賬號

1.前期準備&#xff08;以QQ郵箱為例&#xff09; 登錄QQ郵箱 獲取授權碼 2.settings.py文件配置 1&#xff09;緩存配置 # 配置緩存 CACHES {# 郵件激活隨機數"default": {"BACKEND": "django_redis.cache.RedisCache","LOCATION&q…

社群團購市場選擇與開源技術賦能下的下沉市場開拓策略研究——以開源AI智能名片、鏈動2+1模式與S2B2C商城小程序為例

摘要&#xff1a;在社群團購行業面臨流量成本攀升與同質化競爭的背景下&#xff0c;下沉市場因其龐大用戶基數與未被充分滿足的消費需求&#xff0c;成為創業者突破增長瓶頸的關鍵賽道。本文以拼多多成功開拓小城鎮與農村市場的案例為切入點&#xff0c;結合開源AI智能名片、鏈…

Ollama前端:open-webui

github&#xff1a;https://github.com/open-webui/open-webui 官網&#xff1a;&#x1f3e1; Home | Open WebUI 1、docker安裝&#xff08;GPU&#xff09;&#xff1a; docker run -d -p 3000:8080 --gpusall -v ollama:/root/.ollama -v open-webui:/app/backend/data …

LeetCode513:找樹最左下角的值(bfs+dfs)

文章目錄一、 題目描述解法一&#xff1a;層序遍歷 (BFS) - 最直觀的解法核心思路代碼實現優缺點分析解法二&#xff1a;遞歸 (DFS) - 更深度的思考核心思路代碼實現優缺點分析四、 總結與對比LeetCode 513 - 尋找樹的最后一行的最左側的值&#xff0c;【難度&#xff1a;中等&…

把“評論”菜單從WordPress后臺移除的3種方法

在WordPress后臺移除“評論”菜單&#xff0c;可以通過以下幾種方法實現。以下是詳細步驟&#xff1a; 方法1&#xff1a;通過代碼移除(推薦) 將以下代碼添加到主題的functions.php文件中(或使用CodeSnippets插件)&#xff1a; // 移除后臺左側菜單的“評論” add_action(ad…

大語言模型 LLM 通過 Excel 知識庫 增強日志分析,根因分析能力的技術方案(4):只要過一遍LLM的簡約版本

文章大綱 只要過一遍LLM的簡約版本 1 設計原理(一句話) 2 極簡數據流 3 最小依賴實現(本地 SQLite + OpenAI 兼容端點) 3.1 一次性準備:Excel → SQLite 3.2 關鍵詞提取 + 查表(正則 / SQL) 3.3 單次 LLM 調用 4 運行結果示例 5 性能 & Token 對比 6 可擴展點 7 參考…

(轉)mybatis和hibernate的 緩存區別?

MyBatis 和 Hibernate 都是流行的 Java 持久化框架&#xff0c;它們都提供了自己的緩存機制來優化數據庫操作&#xff0c;減少數據庫的訪問次數&#xff0c;提高應用程序的性能。盡管兩者都支持緩存&#xff0c;但是它們的緩存實現方式和配置有所不同。1. 緩存機制的基本區別My…

【linux內核系列】:萬字詳解進程間通信:消息隊列

&#x1f525; 本文專欄&#xff1a;Linux &#x1f338;作者主頁&#xff1a;努力努力再努力wz &#x1f4aa; 今日博客勵志語錄&#xff1a; 你討厭的現在&#xff0c;是未來的你拼命想回去修正的戰場。 ★★★ 本文前置知識&#xff1a; 匿名管道 命名管道 共享內存 前…

React 19 革命性升級:編譯器自動優化,告別手動性能調優時代

概述 React 19 是 React 框架的一個重要里程碑版本&#xff0c;帶來了眾多突破性的改進和新特性。本文檔將詳細介紹 React 19 的主要變化&#xff0c;幫助開發者了解并遷移到新版本。 &#x1f680; 主要新特性 React Compiler (編譯器) React 19 引入了全新的 React Compi…

UE5的渲染Debug技巧

ShaderPrint UE5相對UE4使用的ComputeShader(GPU Driven)的地方多很多。因為UE5為了方便查看ComputeShader的某些值&#xff0c;開發了“ShaderPrint”&#xff0c;方便直接在Shader 打印信息到屏幕&#xff0c;而不用采用CPUReadback在print的方式。 比如r.nanite.ShowStats…

【2025/08/03】GitHub 今日熱門項目

GitHub 今日熱門項目 &#x1f680; 每日精選優質開源項目 | 發現優質開源項目&#xff0c;跟上技術發展趨勢 &#x1f4cb; 報告概覽 &#x1f4ca; 統計項&#x1f4c8; 數值&#x1f4dd; 說明&#x1f4c5; 報告日期2025-08-03 (周日)GitHub Trending 每日快照&#x1f55…

Android系統模塊編譯調試與Ninja使用指南

模塊編譯調試方法 (此處舉例framework、installd、SystemUI等模塊的編譯調試&#xff0c;其他類似) 1. Framework模塊編譯 Android系統代碼的framework目錄內&#xff0c;一共有3個模塊單獨編譯&#xff1a;framework、services、framework-res.apk。 注意&#xff1a;偶爾會有…

【硬件-筆試面試題】硬件/電子工程師,筆試面試題-51,(知識點:stm32,GPIO基礎知識)

目錄 1、題目 2、解答 3、相關知識點 一、GPIO 基本結構與特性 1. GPIO 硬件結構 2. 主要特性 二、GPIO 工作模式 1. 輸入模式 2. 輸出模式 3. 復用功能模式 4. 特殊模式 三、GPIO 配置步驟&#xff08;以 STM32Cube HAL 庫為例&#xff09; 1. 初始化 GPIO 時鐘 …

小智服務器Java安裝編譯(xinnan-tech)版

github&#xff1a;https://github.com/xinnan-tech/xiaozhi-esp32-server 一、JDK 1、JDK21下載&#xff1a; https://www.oracle.com/cn/java/technologies/downloads/#jdk21-windows RPM安裝&#xff1a; rpm -ivh jdk-21_linux-x64_bin.rpm 2、IDEA設置JDK File → P…

智能平臺的感知進化:AI × 視頻通感在群體終端協同中的應用探索

?? 引言&#xff1a;從單兵到集群&#xff0c;未來智能平臺的協同演進 從傳統的單兵執行任務到如今的“群體智能平臺編組”&#xff0c;現代感知系統正經歷一場由 AI、機器人與智能計算平臺驅動的深度變革。過去&#xff0c;履帶式無人平臺在平坦地形中承擔支援任務&#xf…

基于定制開發開源AI智能名片S2B2C商城小程序的B站私域流量引流策略研究

摘要&#xff1a;隨著移動互聯網進入存量競爭階段&#xff0c;私域流量運營成為企業數字化轉型的核心戰略。B站作為中國最大的Z世代文化社區&#xff0c;其3.41億月活躍用戶中Z世代占比達58%&#xff0c;且25歲以上用戶增速顯著&#xff0c;用戶日均使用時長超108分鐘&#xff…