【探索數據結構】線性表之單鏈表

🎉🎉🎉歡迎蒞臨我的博客空間,我是池央,一個對C++和數據結構懷有無限熱忱的探索者。🙌

🌸🌸🌸這里是我分享C/C++編程、數據結構應用的樂園?

🎈🎈🎈期待與你一同在編程的海洋中遨游,探索未知的技術奧秘💞

📝專欄指路:

📘【C++】專欄:深入解析C++的奧秘,分享編程技巧與實踐。

📘【數據結構】專欄:探索數據結構的魅力,助你提升編程能力。

前言

回顧:線性表之順序表

順序表的問題及思考

1.中間/頭部的插入刪除,時間復雜度為0(N)

2.增容需要申請新空間,拷貝數據,釋放舊空間。會有不小的消耗。

3.增容一般是呈2倍的增長,勢必會有一定的空間浪費。例如當前容量為100,滿了以后增容到200,我們再繼續插入了5個數據,后面沒有數據插入了,那么就浪費了95個數據空間。

思考:如何解決以上問題呢?

是否存在一種數據結構,能夠解決以上順序表表現出來的問題:

1)中間/頭部的插入刪除,可以一步到位,不需要挪動數據

2)不需要擴容

3)不會造成空間

答案是本篇主角——(單)鏈表

文章重點介紹:不帶頭節點不循環的單鏈表

一、鏈表

鏈表是一種物理存儲單元上非連續、非順序的存儲結構,其數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點組成,每個結點都包含兩個部分:數據域和指針域。數據域用于存儲數據元素的信息,而指針域則存儲著指向下一個結點的地址信息。有單鏈表、雙鏈表、循環鏈表

優點:動態內存分配、插入和刪除高效、空間利用率高

缺點:訪問元素效率低、有額外的空間開銷、緩存不優好

二、單鏈表

1.概念

單鏈表是一種線性數據結構,其中元素在邏輯上按照線性順序排列,但在物理內存中通過指針進行鏈接。每個元素(稱為節點/結點)都包含兩部分信息:數據域和指針域。數據域存儲節點的值或數據,而指針域則包含指向下一個節點的指針。

56d7df8925e9452ebb85358278a7a2a0.png

2.分類

(1)帶頭節點

在單鏈表中,第一個節點之前通常有一個頭指針(或稱為頭節點),它指向鏈表中的第一個數據節點。如果鏈表為空,則頭指針通常指向空(NULL)。鏈表的最后一個節點的指針域被設置為空(NULL),以表示鏈表的結束。

(2)不帶頭節點

不帶頭節點的單鏈表,我們直接通過頭指針指向第一個數據節點,而不需要額外的頭節點作為起始點。

3.代碼示例

創建單鏈表結構

typedef int SLTDataType;
typedef struct SListNode SLTNode;
struct SListNode
{SLTDataType data;//節點存放的數據SLTNode* next;//存放下一個節點的地址
};

三、對單鏈表的操作

(0)打印

6582f2cea45549c58cf56b7f343c2311.png

//打印
void SLTPrint(SLTNode* phead)
{//創建指向第一個節點的指針的指針,讓phead無需改變SLTNode* pcur = phead;while (pcur){printf("%d->", pcur->data);pcur = pcur->next;}printf("NULL\n");
}

(1)創建一個新節點

//創建一個新節點
SLTNode* SLTBuyNode(SLTDataType x)
{SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL){perror("malloc fail");exit(1);//申請空間成功會返回0}newnode->data = x;newnode->next = NULL;return newnode;
}

(2)尾插

有鏈表為空和非空兩種情況

28f492b698964650aaf1fa8ebb8146d0.png

//尾插
void SLTPushBack(SLTNode** pphead, SLTDataType x)
{assert(pphead);//*pphead是指向第一個節點的指針, 存放第一個節點的地址//創建一個新節點SLTNode* newnode = SLTBuyNode(x);//空鏈表if (*pphead == NULL){*pphead = newnode;}else{//非空鏈表,找尾//創建指向第一個節點的指針的指針,讓*phead無需改變SLTNode * ptail = *pphead;while (ptail->next){ptail = ptail->next;}//新節點變為鏈表的新尾巴ptail->next = newnode;}
}

思考:為什么要用二級指針來接收實參?

9de62bf3fc9b4e759b9b2f7c358ff376.png

簡單來說,想要改變實參,傳值無法改變,要通過傳實參的地址給形參,形參的改變才會影響實參

(3)頭插

//頭插
void SLTPushFront(SLTNode** pphead, SLTDataType x)
{assert(pphead);//*pphead是指向第一個節點的指針, 存放第一個節點的地址//創建一個新節點SLTNode* newnode = SLTBuyNode(x);newnode->next = *pphead;*pphead = newnode;
}

(4)查找

//查找
SLTNode* SLTFind(SLTNode* phead, SLTDataType x)
{assert(phead);//不改變頭結點,防止要多次遍歷時找不到頭結點SLTNode* pcur = phead;while (pcur){if (pcur->data == x){return pcur;}pcur = pcur->next;}return NULL;
}

(5)頭刪

//頭刪
void SLTDelFront(SLTNode** pphead)
{assert(pphead && *pphead);//鏈表不能為空//無論有幾個節點都適用SLTNode* next = (*pphead)->next;//保存第二個節點的地址free(*pphead);*pphead = NULL;*pphead = next;//原本的第二個節點成為新頭結點
}

(6)尾刪

be0ffab1e3644b3bade0122546b802b1.png

//尾刪
void SLTDelBack(SLTNode** pphead)
{//可能會修改頭節點地址所以還是使用二級指針assert(pphead && *pphead);//鏈表不能為空//鏈表只有一個節點if ((*pphead)->next == NULL)//->優先級高于*{free(*pphead);*pphead = NULL;}//多個節點SLTNode* ptail = *pphead;SLTNode* prev = *pphead;while (ptail->next){prev = ptail;ptail = ptail->next;}prev->next = NULL;free(ptail);ptail = NULL;
}

(7)指定位置之前插入

//指定位置之前插入
void SLTInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x)
{assert(pphead && *pphead);//鏈表不能為空assert(pos);//創建一個新節點SLTNode* newnode = SLTBuyNode(x);//相當于頭插if ((*pphead) == pos){//pphead存放指向第一個節點指針的地址SLTPushFront(pphead, x);}else{SLTNode* prev = *pphead;while (prev->next != pos){prev = prev->next;}//prev->newnode->posnewnode->next = pos;prev->next = newnode;}
}

(8)指定位置之后插入

//指定位置之后插入
void SLTInsertAfter(SLTNode* pos, SLTDataType x)
{//為什么不需要頭結點,因為在指定位置插入是這樣的邏輯//pos-newnode-pos->next,通過pos我們就能找到他的下一個節點assert(pos);//創建一個新節點SLTNode* newnode = SLTBuyNode(x);newnode->next = pos->next;pos->next = newnode;//思考:上面兩行代碼順序互換可以嗎?
}

6bdb67d133f349e99d19319d65fbca05.png

不相同,不可以互換位置,第二中代碼pos->next指針先指向了newnode那么原先pos的下一個節點的地址就會找不到

(9)刪除指定節點

//刪除指定節點pos
void SLTErase(SLTNode** pphead, SLTNode* pos)
{assert(pphead && *pphead);//鏈表不能為空assert(pos);if ((*pphead) == pos){//相當于頭刪SLTDelFront(pphead);}else{SLTNode* prev = *pphead;while (prev->next!=pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}
}

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

// 刪除指定節點pos之后的數據
void SLTEraseAfter(SLTNode* pos)
{assert(pos);//如果沒有用del來存放pos->next會怎么樣?SLTNode* del = pos->next;pos->next = del->next;free(del);del = NULL;
}

(11)銷毀

一個一個銷毀

/銷毀
void SLTDestroy(SLTNode** pphead)
{assert(pphead && *pphead);//鏈表不能為空SLTNode* pcur = *pphead;while (pcur){//如果沒有保存pcur->next的地址// 在pcur釋放掉后,剩余節點找不到了,無法銷毀SLTNode* next = pcur->next;free(pcur);pcur = next;}*pphead = NULL;
}

四、測試(僅供參考)

#include"SList.h"
void STListTest01()
{//創建節點SLTNode* node1 = (SLTNode*)malloc(sizeof(SLTNode));node1->data = 1;SLTNode* node2 = (SLTNode*)malloc(sizeof(SLTNode));node2->data = 2;SLTNode* node3 = (SLTNode*)malloc(sizeof(SLTNode));node3->data = 3;//鏈接節點node1->next = node2;node2->next = node3;node3->next = NULL;//創建指向第一個節點的指針,讓node1無需改變SLTNode* plist = node1;//調用打印SLTPrint(plist);}
void STListTest02()
{SLTNode* plist = NULL;SLTNode* p = NULL;//尾插SLTPushBack(&plist, 1);SLTPushBack(&plist, 2);SLTPushBack(&p, 3);plist->next->next = p;SLTPushBack(&p, 4);SLTPrint(plist);//頭插SLTPushFront(&plist, 5);SLTPrint(plist);//尾刪SLTDelBack(&plist);SLTPrint(plist);//頭刪SLTDelFront(&plist);SLTPrint(plist);SLTNode*find=SLTFind(plist, 3);//指定位置之前插入SLTInsert(&plist, find, 5);SLTPrint(plist);//指定位置之后插入SLTInsertAfter(find, 10);SLTPrint(plist);//刪除指定節點/*SLTErase(plist, find);*///刪除指定節點之后數據SLTEraseAfter(find);SLTPrint(plist);//銷毀鏈表SLTDestroy(&plist);SLTPrint(plist);}
int main()
{//STListTest01();STListTest02();
}

下回預告:線性表之雙鏈表

持續更新中...

敬請期待

?

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

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

相關文章

Autodl服務器中Faster-rcnn(jwyang)復現(一)

前言 在做實驗時需要用到faster-rcnn做對比,本節首先完成代碼復現,用的數據集是VOC2007~ 項目地址:https://github.com/jwyang/faster-rcnn.pytorch/tree/pytorch-1.0 復現環境:autodl服務器+python3.6+cuda11.3+Ubuntu20.04+Pytorch1.10.0 目錄 一、環境配置二、編譯cud…

2024年軟考總結 信息系統管理師

選擇題 英文題,我是一題也沒把握,雖然我理解意思。 千萬不要認為考死記硬背不對。目的不在于這。工程項目中有很多重要的數字,能記住說明你合格。 案例 幾乎把答案全寫在案例中了。 計算題 今年最簡單。沒有考成本。 只考了關鍵路徑&a…

頭歌OpenGauss數據庫-I.復雜查詢第8關:兩門及以上課程不及格的學生

任務描述 本關任務:根據提供的表和數據,查詢兩門及其以上不及格課程的同學的學號(s_id)、姓名(s_name)及其平均成績(avg_score),要求計算平均成績后為整數。 student表數據: s_ids_names_sex01Mia女02Riley男03Aria女04Lucas女05Oliver男06Caden男07Lily女08Jacob男c…

安卓開發:相機水印設置

1.更新水印 DecimalFormat DF new DecimalFormat("#"); DecimalFormat DF1 new DecimalFormat("#.#");LocationManager LM (LocationManager)getSystemService(Context.LOCATION_SERVICE); LM.requestLocationUpdates(LocationManager.GPS_PROVIDER, 2…

【學習筆記】計算機組成原理(七)

指令系統 文章目錄 指令系統7.1 機器指令7.1.1 指令的一般格式7.1.2 指令字長 7.2 操作數類型和操作類型7.2.1 操作數類型7.2.2 數據在存儲器中的存放方式7.2.3 操作類型 7.3 尋址方式7.3.1 指令尋址7.3.1.1 順序尋址7.3.1.2 跳躍尋址 7.3.2 數據尋址7.3.2.1 立即尋址7.3.2.2 直…

第四十五天 | 322.零錢兌換

題目:322.零錢兌換 嘗試解答: 1.確定dp[j]含義:裝滿容量為j的背包所需要放的硬幣個數為dp[j]; 2.動態轉移方程:dp[j] dp[j - coins[i]] 1; 3.遍歷順序:本題應該為組合類題目,不考慮裝入的順序&#x…

精品PPT | 精益生產管理中MES系統的實現與應用(免費下載)

【1】關注本公眾號,轉發當前文章到微信朋友圈 【2】私信發送 MES系統的實現與應用 【3】獲取本方案PDF下載鏈接,直接下載即可。 如需下載本方案PPT/WORD原格式,請加入微信掃描以下方案驛站知識星球,獲取上萬份PPT/WORD解決方案&…

吃掉 N 個橘子的最少天數(Lc1553)——記憶化搜索

廚房里總共有 n 個橘子,你決定每一天選擇如下方式之一吃這些橘子: 吃掉一個橘子。如果剩余橘子數 n 能被 2 整除,那么你可以吃掉 n/2 個橘子。如果剩余橘子數 n 能被 3 整除,那么你可以吃掉 2*(n/3) 個橘子。 每天你只能從以上 …

Redis - 緩存場景

學習資料 學習的黑馬程序員嗶站項目黑馬點評,用作記錄和探究原理。 Redis緩存 緩存 :就是數據交換的緩沖區,是存儲數據的臨時地方,讀寫性能較高 緩存常見的場景: 數據庫查詢加速:通過將頻繁查詢的數據緩存起來&…

【挖金子game】

如果您想要編寫一個簡單的“挖金子”游戲代碼,可以使用Python這樣的編程語言來實現。以下是一個簡單的Python代碼示例,用于創建一個基本的“挖金子”游戲: import random # 游戲設置 max_gold 10 # 最大金子數量 max_digs 5 # 最大挖掘…

數據驅動(Data-Driven)和以數據為中心(Data-Centric)的區別

一、什么是數據驅動? 數據驅動(Data-Driven)是在管理科學領域經常提到的名詞。數據驅動決策(Data-Driven Decision Making,簡稱DDD)是一種方法論,即在決策過程中主要依賴于數據分析和解釋&…

Java基礎學習:java中的基礎注解

在Java中,有一些內置的(或稱為“基礎”)注解(annotation),這些注解在Java標準庫中定義,并且具有特定的用途。以下是一些主要的Java內置注解: Override: 用于表示一個方法…

Keras深度學習框架第二十七講:KerasTuner超參數優化基礎

1、超參數優化概念 1.1 什么是超參數優化 超參數調優,也稱為超參數優化或參數調優,是尋找學習算法或模型最佳超參數組合的過程。超參數是在訓練過程開始之前設置的參數,模型無法直接從數據中學習這些參數。它們控制著學習算法的行為&#x…

NDIS小端口驅動開發(二)

初始化微型端口適配器 當網絡設備可用時,系統會加載所需的 NDIS 微型端口驅動程序。 隨后,即插即用 (PnP) 管理器向 NDIS 發送即插即用 IRP 來啟動設備。 NDIS 調用微型端口驅動程序的 MiniportInitializeEx 函數來初始化用于網絡 I/O 操作的適配器。 初…

嵩山為什么稱為三水之源

三水指黃河、淮河、濟河,這三條河流環繞在嵩山周邊。 黃河橫亙在嵩山北部,其支流伊洛河從西南方環繞嵩山,然后匯入黃河。濟河,古稱濟水,源自濟源王屋山,自身河道在東晉時代被黃河奪占,從此消失。…

畢設 大數據校園卡數據分析

文章目錄 0 前言1 課題介紹2 數據預處理2.1 數據清洗2.2 數據規約 3 模型建立和分析3.1 不同專業、性別的學生與消費能力的關系3.2 消費時間的特征分析 4 Web系統效果展示5 最后 0 前言 🔥 這兩年開始畢業設計和畢業答辯的要求和難度不斷提升,傳統的畢設…

職場不是掙錢

職場怎么不是掙錢? 曾經我也一直這么想,只要做好老板安排的事情,自然就可以掙到錢了。 目的應該是沒錯的,是掙錢。 只是做好活就能掙錢,好像想得有些簡單了。 畢竟每個人都在干活,為什么就該自己掙錢呢&a…

【vue2配置】Vue Router

Vue Router官網 1、npm install vue-router4 2、創建模塊,在src目錄小創/views/map/MapIndex.vue模塊和創router/index.js文件 3、在router/index.js配置路由 import Vue from "vue"; import Router from "vue-router"; // 引入模塊 const Ma…

C語言——在頭?件中#if、_STDC_等字?起什么作??

一、問題 通常,?些程序員都不會去研究頭?件中的內容是什么含義,總覺得亂亂的,有很多 #if、_STDC_、#line 等字符,那么這些字符都各代表什么呢,在頭?件中又起到什么作?呢? 二、解答 在頭?件中存在類似…

智慧校園建設的進階之路

智慧校園的建設現已到達了老練的階段,許多學校設備充滿著數字化信息,進出宿舍樓,校園一卡通體系會記載下學生信息,外來人員闖入會報警,翻開電腦就能查到學生是否在宿舍等……學生的學習和日子都充滿了數字化的痕跡。但…