国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)單向鏈表

這篇具有很好參考價(jià)值的文章主要介紹了數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)單向鏈表。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

??前言

  • 單鏈表是一種常見的數(shù)據(jù)結(jié)構(gòu),用于存儲(chǔ)一系列的數(shù)據(jù)元素,每個(gè)節(jié)點(diǎn)包含數(shù)據(jù)和指向下一個(gè)節(jié)點(diǎn)的指針。

  • 單鏈表通常用于實(shí)現(xiàn)某些算法或數(shù)據(jù)結(jié)構(gòu),如鏈?zhǔn)角跋蛐?、哈希表、鏈?zhǔn)綏?、?duì)列等等。

  • 單鏈表在程序設(shè)計(jì)中的作用不可忽略,是很多基礎(chǔ)算法的核心數(shù)據(jù)結(jié)構(gòu)之一。

  • 學(xué)習(xí)單鏈表有助于提高算法和數(shù)據(jù)結(jié)構(gòu)的基本能力并增強(qiáng)編程的實(shí)踐經(jīng)驗(yàn)。

  • 本篇博客將介紹單鏈表的基本操作及其算法應(yīng)用,旨在幫助讀者掌握單鏈表數(shù)據(jù)結(jié)構(gòu)及相關(guān)算法的設(shè)計(jì)和實(shí)現(xiàn),進(jìn)一步提高編程的能力和水平。

總之,單鏈表是一種常見的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu),與編程和算法設(shè)計(jì)密切相關(guān),了解和掌握單鏈表的基本概念和操作,對于提高編程能力和設(shè)計(jì)程序算法都有幫助。

??單鏈表與順序表的對比

數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)單向鏈表

單鏈表的優(yōu)點(diǎn):

  • 動(dòng)態(tài)性:單鏈表可以在任意位置進(jìn)行插入和刪除操作,不必像順序表那樣需要移動(dòng)元素,操作比較靈活。
  • 空間利用效率高:單鏈表的結(jié)構(gòu)只需要記錄一個(gè)指針域和一個(gè)數(shù)據(jù)域,不像順序表需要預(yù)留一定的存儲(chǔ)空間,因此空間利用率較高。

單鏈表的缺點(diǎn):

  • 存儲(chǔ)空間分配不靈活:由于單鏈表的結(jié)構(gòu)決定了只有通過指針才能訪問相鄰元素,因此不能隨機(jī)訪問。
  • 存儲(chǔ)密度較低:由于每個(gè)結(jié)點(diǎn)只包含一個(gè)指針域和一個(gè)數(shù)據(jù)域,因此存儲(chǔ)密度比較低,會(huì)占用更多的空間。

順序表的優(yōu)點(diǎn):

  • 存儲(chǔ)密度較高:由于所有元素在連續(xù)的存儲(chǔ)空間中,因此存儲(chǔ)密度比較高,可以節(jié)省空間。
  • 存取效率高:由于所有元素在連續(xù)的存儲(chǔ)空間中,因此可以通過元素的下標(biāo)進(jìn)行隨機(jī)存取,存取效率比較高。

順序表的缺點(diǎn):

  • 插入和刪除操作較慢:由于需要移動(dòng)元素,因此插入和刪除操作比較慢。
  • 維護(hù)困難:當(dāng)順序表達(dá)到一定的長度后,插入和刪除操作會(huì)變得更加困難,在需要頻繁進(jìn)行插入和刪除操作時(shí),順序表的效率會(huì)比較低。

總的來說,單鏈表和順序表各有優(yōu)點(diǎn)和缺點(diǎn),需要根據(jù)具體的應(yīng)用場景進(jìn)行選擇。如果需要頻繁進(jìn)行插入和刪除操作,單鏈表的效率更高;如果需要頻繁進(jìn)行隨機(jī)存取操作,順序表更為適合。
數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)單向鏈表

??單鏈表的初始操作及結(jié)構(gòu)體

  • 單鏈表的實(shí)現(xiàn)也是需要搭建3個(gè)文件,一個(gè)是SList.h(頭文件),SList.c(各函數(shù)的實(shí)現(xiàn)文件),Test.c(測試文件)。
  • 搭建好之后我們只需要在SList.cTest.c文件開頭包含#include"SList.h"即可將三個(gè)文件鏈接起來。
  • 寫單鏈表的結(jié)構(gòu)體時(shí),需要定義包含兩個(gè)成員的結(jié)構(gòu)體類型,一個(gè)成員用于存儲(chǔ)結(jié)點(diǎn)的數(shù)據(jù),另一個(gè)成員用于存儲(chǔ)下一個(gè)結(jié)點(diǎn)的指針。一般而言,結(jié)構(gòu)體類型的名稱和結(jié)構(gòu)體變量的名稱都需要有意義,以便于程序的閱讀和理解。
    相關(guān)功能代碼:
#pragma once
// 輸入輸出所需頭文件
#include<stdio.h>
// malloc 所需頭文件
#include<stdlib.h>
// assert 所需頭文件
#include<assert.h>

// 每個(gè)節(jié)點(diǎn)的數(shù)據(jù)的類型
typedef int SLTDataType;

// 每個(gè)節(jié)點(diǎn)的結(jié)構(gòu)體
typedef struct SListNode
{
	// 存放該結(jié)點(diǎn)的數(shù)據(jù)
	SLTDataType data;
	// 存放下一個(gè)節(jié)點(diǎn)的地址,將整個(gè)結(jié)構(gòu)串聯(lián)成一個(gè)單鏈表
	struct SListNode* next;
}SLTNode;  // 用 typedef 將結(jié)構(gòu)體重命名為 SLTNode 便于后續(xù)寫程序 

??申請一個(gè)節(jié)點(diǎn)

  • 單鏈表的節(jié)點(diǎn)是單鏈表中最基本的單位。每個(gè)節(jié)點(diǎn)由兩部分組成,分別是數(shù)據(jù)域和指針域。數(shù)據(jù)域存儲(chǔ)節(jié)點(diǎn)的數(shù)據(jù)或者信息,而指針域指向下一個(gè)節(jié)點(diǎn)的地址。因此,單鏈表是由一連串的節(jié)點(diǎn)構(gòu)成的數(shù)據(jù)結(jié)構(gòu)。具體來說,單鏈表的節(jié)點(diǎn)通常包含以下信息:

  • 1.數(shù)據(jù)域:存儲(chǔ)節(jié)點(diǎn)的數(shù)據(jù)或信息,可以是任何數(shù)據(jù)類型,例如整數(shù)、字符、字符串、結(jié)構(gòu)體等。

  • 2.指針域:指向下一個(gè)節(jié)點(diǎn)的地址。在C語言中可以使用結(jié)構(gòu)體來表示一個(gè)節(jié)點(diǎn),節(jié)點(diǎn)結(jié)構(gòu)體至少包含一個(gè)數(shù)據(jù)項(xiàng)和一個(gè)指向下一個(gè)節(jié)點(diǎn)的指針。

單鏈表的節(jié)點(diǎn)是非常靈活和可擴(kuò)展的,因?yàn)槊總€(gè)節(jié)點(diǎn)都只需要存儲(chǔ)自身的信息和指向下一個(gè)節(jié)點(diǎn)的指針就可以了,這就使得單鏈表更易于被實(shí)現(xiàn)和擴(kuò)展。當(dāng)需要插入或刪除節(jié)點(diǎn)時(shí),只需更新相應(yīng)節(jié)點(diǎn)的指針域即可。
同時(shí),這種設(shè)計(jì)也帶來了一定的缺點(diǎn),即單鏈表不能直接訪問任何一個(gè)節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)。

  • 節(jié)點(diǎn)應(yīng)至少包括一個(gè)數(shù)據(jù)項(xiàng)(例如整數(shù)或字符串)和一個(gè)指向下一個(gè)節(jié)點(diǎn)的指針。
  • 申請內(nèi)存要?jiǎng)?chuàng)建一個(gè)新的節(jié)點(diǎn),你需要使用C語言的stdlib.h庫中的malloc函數(shù)來為其分配內(nèi)存。將分配一個(gè)大小為SListNode結(jié)構(gòu)體的內(nèi)存塊,并將其指針指向newnode。在這個(gè)節(jié)點(diǎn)被使用完畢之后,應(yīng)該使用free函數(shù)釋放它的內(nèi)存。
  • 經(jīng)過內(nèi)存分配后,你需要用正確的值初始化節(jié)點(diǎn)。在這種情況下,節(jié)點(diǎn)的值可以作為函數(shù)的參數(shù)進(jìn)行傳遞。初始化一個(gè)新的節(jié)點(diǎn)并返回這個(gè)節(jié)點(diǎn)的指針。
  • 我們首先為節(jié)點(diǎn)分配內(nèi)存,然后將value賦值給節(jié)點(diǎn)的data字段,并把next設(shè)為NULL(因?yàn)檫@個(gè)節(jié)點(diǎn)尚未鏈接到另一個(gè)節(jié)點(diǎn)上)。

這樣,我們就成功地創(chuàng)建了一個(gè)新的節(jié)點(diǎn),并初始化了它的數(shù)據(jù)元素和指向下一個(gè)節(jié)點(diǎn)的指針。


SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

??打印

  • 單鏈表的打印操作是指遍歷單鏈表并輸出其中所有節(jié)點(diǎn)的數(shù)據(jù)或信息,這是單鏈表中常用的一種操作,也是單鏈表中尤為基礎(chǔ)的一部分。
  • 定義一個(gè)指針變量,指向單鏈表的頭節(jié)點(diǎn),命名為cur。其中,head為單鏈表頭節(jié)點(diǎn)的指針。
  • 使用while循環(huán)遍歷整個(gè)單鏈表,直到當(dāng)前的指針變量為空。
  • 在循環(huán)中,使用p指針變量訪問當(dāng)前節(jié)點(diǎn)(即p所指向的節(jié)點(diǎn)),并打印其數(shù)據(jù)或信息。在實(shí)際操作中,可以根據(jù)需要定制輸出樣式。
  • 將指針變量p更新為下一個(gè)節(jié)點(diǎn)的地址,即p = p->next,繼續(xù)訪問下一個(gè)節(jié)點(diǎn)。直到循環(huán)結(jié)束,所有的節(jié)點(diǎn)都被遍歷,并輸出了其中所有的數(shù)據(jù)或信息。
    相關(guān)功能代碼:
void SLPrint(SLTNode* phead)
{
    struct Node* cur = phead; // 定義指針變量,指向頭節(jié)點(diǎn)
    while(cur != NULL){ // 循環(huán)條件
        printf("%d ", cur->val); // 輸出節(jié)點(diǎn)數(shù)據(jù)或信息
        cur = cur->next; // 修改指針變量,指向下一個(gè)節(jié)點(diǎn)
    }
}

需要注意的是,單鏈表的打印操作在多種算法或數(shù)據(jù)結(jié)構(gòu)中都有應(yīng)用。
同時(shí),其中包含單個(gè)強(qiáng)迫離散節(jié)點(diǎn)間轉(zhuǎn)移到下一個(gè)節(jié)點(diǎn)的元素。其執(zhí)行步驟、方式及相關(guān)內(nèi)容會(huì)因場景而異,需要結(jié)合實(shí)際情況進(jìn)行設(shè)計(jì)。

??銷毀

  • 單鏈表的銷毀是指將單鏈表中的所有節(jié)點(diǎn)都刪除,并將鏈表中的所有內(nèi)存空間釋放。
  • 具體步驟:
  • 1.定義一個(gè)指針變量pos來保存待刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)。
  • 2.使用while循環(huán)遍歷整個(gè)單鏈表,直到當(dāng)前指針plist為空。
  • 3.在循環(huán)中,保存當(dāng)前節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)的指針,即pos = pos->next。
  • 4.使用free函數(shù)釋放當(dāng)前節(jié)點(diǎn)的內(nèi)存空間,即free(head),釋放節(jié)點(diǎn)所占用的內(nèi)存空間。
  • 5.將指針head指向下一個(gè)節(jié)點(diǎn)。即plist = pos。
    重復(fù)步驟3-5,直到整個(gè)單鏈表中的所有節(jié)點(diǎn)都被刪除并釋放了內(nèi)存空間。最后在返回。
  • 需要注意的是,有指針就別忘了要assert
  • 需要注意的是,在進(jìn)行單鏈表的尾插操作時(shí),需要保證單鏈表不為空??梢栽诤瘮?shù)外創(chuàng)建一個(gè)頭節(jié)點(diǎn),排除空鏈表情況,并將其傳入SLPushBack函數(shù)中進(jìn)行操作。另外,為新節(jié)點(diǎn)分配內(nèi)存空間之后,也需要對內(nèi)存申請情況進(jìn)行檢查,以避免發(fā)生內(nèi)存泄漏等問題。
    相關(guān)程序代碼:
void SLDestory(SLTNode* plist,SLTNode* pos)
{
	assert(plist);

	while (pos)
	{
		plist = pos;
		pos = pos->next;
		free(plist);
		plist->next = NULL;
	}
	return;
}

還需要注意的是,在使用上述函數(shù)時(shí),需要首先保證單鏈表中所有節(jié)點(diǎn)都已經(jīng)被訪問或使用,否則可能會(huì)造成內(nèi)存泄漏。

??尾插

  • 單鏈表尾插是單鏈表中的一種常用操作,而且非常實(shí)用,它可以在單鏈表的末尾插入一個(gè)新節(jié)點(diǎn)。
  • 找到單鏈表的尾部節(jié)點(diǎn),即包含指針域值為NULL的節(jié)點(diǎn)。可以用一個(gè)循環(huán)來找到它。
  • 創(chuàng)建一個(gè)新節(jié)點(diǎn),將其數(shù)據(jù)放入其中。需要調(diào)用BuyLTNode函數(shù)為新節(jié)點(diǎn)分配內(nèi)存空間。
  • 將新節(jié)點(diǎn)連接到單鏈表的尾部節(jié)點(diǎn)上,即將尾部節(jié)點(diǎn)的指針域指向新節(jié)點(diǎn)。至此,新的節(jié)點(diǎn)已經(jīng)成功插入到了單鏈表的末尾。
  • 為新節(jié)點(diǎn)分配內(nèi)存空間之后,也需要對內(nèi)存申請情況進(jìn)行檢查(assert),以避免發(fā)生內(nèi)存泄漏等問題。
    相關(guān)程序代碼:
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);
	assert(*pphead);
	//1,空鏈表
	//2,非空鏈表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

??尾刪

  • 單鏈表尾刪是指刪除單鏈表中的尾節(jié)點(diǎn),使其前一個(gè)節(jié)點(diǎn)成為新的尾節(jié)點(diǎn)。
  • 找到單鏈表的倒數(shù)第二個(gè)節(jié)點(diǎn)??梢允褂靡粋€(gè)循環(huán)遍歷直到找到該節(jié)點(diǎn)。注意,需要判斷單鏈表中是否有節(jié)點(diǎn),否則刪除操作無法進(jìn)行
  • 保存單鏈表尾節(jié)點(diǎn)的指針,以便后續(xù)釋放它所占用的內(nèi)存空間。
  • 將尾節(jié)點(diǎn)從單鏈表中刪除,即將p節(jié)點(diǎn)的指針域設(shè)置為NULL。
  • 釋放單鏈表尾節(jié)點(diǎn)占用的內(nèi)存空間。
    相關(guān)程序代碼:
void SLPopBack(SLTNode** pphead)
{
	//assert(pphead);   //鏈表為空,pphead也不能為空,因?yàn)樗穷^指針plist的地址
	assert(*pphead);  //鏈表為空,不能頭刪
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		//找尾
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

需要注意的是,在進(jìn)行單鏈表的尾刪操作時(shí),需要先對單鏈表進(jìn)行判空處理,避免出現(xiàn)訪問空指針的錯(cuò)誤。

??頭插

  • 單鏈表頭插是指在單鏈表的頭部插入一個(gè)新的節(jié)點(diǎn),使其成為新的頭節(jié)點(diǎn)。
  • 創(chuàng)建一個(gè)新的節(jié)點(diǎn),并將新節(jié)點(diǎn)的指針域指向原來的頭節(jié)點(diǎn)。需要調(diào)用BuyLTNode函數(shù)為新節(jié)點(diǎn)分配內(nèi)存空間。
  • 將頭指針指向新節(jié)點(diǎn),即將頭指針修改為新節(jié)點(diǎn)的地址。
    相關(guān)程序代碼:
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

	newnode->next = *pphead;
	*pphead = newnode;	
}

需要注意的是,在進(jìn)行單鏈表的頭插操作時(shí),需要先對頭指針進(jìn)行檢查,避免出現(xiàn)空指針的錯(cuò)誤。此外,在新建節(jié)點(diǎn)并為其分配內(nèi)存空間時(shí),也需要進(jìn)行內(nèi)存申請情況的檢查,以避免出現(xiàn)內(nèi)存泄漏等問題。

??頭刪

  • 單鏈表頭刪是指刪除單鏈表中的頭節(jié)點(diǎn),使其后一個(gè)節(jié)點(diǎn)成為新的頭節(jié)點(diǎn)。
  • 保存單鏈表頭節(jié)點(diǎn)的指針,以便后續(xù)釋放它所占用的內(nèi)存空間。
  • 釋放原來的頭節(jié)點(diǎn)所占用的內(nèi)存空間。
    相關(guān)程序代碼:
void SLPopFront(SLTNode** pphead)
{
	//assert(pphead);   //鏈表為空,pphead也不能為空,因?yàn)樗穷^指針plist的地址
	assert(*pphead);  //鏈表為空,不能頭刪。

	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

需要注意的是,在進(jìn)行單鏈表的頭刪操作時(shí),需要先對頭指針進(jìn)行檢查,避免出現(xiàn)空指針的錯(cuò)誤。此外,在釋放原來的頭節(jié)點(diǎn)所占用的內(nèi)存空間時(shí),也需要進(jìn)行內(nèi)存申請情況的檢查,以避免出現(xiàn)內(nèi)存泄漏等問題。

??數(shù)據(jù)的查找

  • 在單鏈表中查找數(shù)據(jù)通常需要遍歷整個(gè)鏈表,找到匹配的節(jié)點(diǎn)并返回其位置或指針。
  • 使用一個(gè)指針指向鏈表的頭結(jié)點(diǎn),依次遍歷鏈表中的每一個(gè)節(jié)點(diǎn)。
  • 在每個(gè)節(jié)點(diǎn)中,檢查該節(jié)點(diǎn)中存儲(chǔ)的元素是否與待查找元素相同。如果相同,則返回該節(jié)點(diǎn)的位置或指針。
  • 如果遍歷整個(gè)鏈表都找不到相匹配的節(jié)點(diǎn),則返回NULL表示查找失敗。
    相關(guān)程序代碼:

SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}
需要注意的是,在進(jìn)行單鏈表中數(shù)據(jù)查找操作時(shí),需要先對單鏈表進(jìn)行判空處理,避免出現(xiàn)訪問空指針的錯(cuò)誤。 此外,還需注意的是,本算法只能查找鏈表中第一個(gè)匹配的元素,無法查找所有匹配的元素。

??數(shù)據(jù)的修改

  • 在單鏈表中修改指定節(jié)點(diǎn)的數(shù)據(jù),通常需要先通過遍歷找到該節(jié)點(diǎn),之后直接修改其存儲(chǔ)的數(shù)據(jù)。
  • 使用一個(gè)指針指向鏈表的頭結(jié)點(diǎn),依次遍歷鏈表中的每一個(gè)節(jié)點(diǎn)。
  • 在每個(gè)節(jié)點(diǎn)中,檢查該節(jié)點(diǎn)中存儲(chǔ)的元素是否與待修改元素相同。如果相同,則直接修改該節(jié)點(diǎn)中存儲(chǔ)的數(shù)據(jù)。
  • 如果遍歷整個(gè)鏈表都找不到匹配的節(jié)點(diǎn),則返回NULL表示操作失敗。
    相關(guān)程序代碼:
SLTNode* SLModify(SLTNode* phead, int target, int newdata) 
{
	SLTNode* cur = phead;
	while (cur != NULL) {
		if (cur->data == target) {
			cur->data = newdata;
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

需要注意的是,在進(jìn)行單鏈表中數(shù)據(jù)修改操作時(shí),需要先對單鏈表進(jìn)行判空處理,避免出現(xiàn)訪問空指針的錯(cuò)誤。此外,本算法只能修改鏈表中第一個(gè)匹配的元素,無法修改所有匹配的元素。

??在pos位置之后插入節(jié)點(diǎn)

  • 首先對pos進(jìn)行判空操作。
  • 創(chuàng)建一個(gè)新節(jié)點(diǎn) newnode,調(diào)用BuyLTNode函數(shù)。
  • newnodenext指向pos位置的next,在用posnext指向newnode。
    相關(guān)程序代碼:
//在pos之后插入
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}

??在pos位置之前插入節(jié)點(diǎn)

  • pos位置之前插入,因?yàn)閱捂湵砭哂袉蜗蛐?,因此這里需要遍歷單鏈表找到pos位置的前一個(gè)節(jié)點(diǎn),才能進(jìn)行插入。
  • 但是你會(huì)發(fā)現(xiàn),如果是pos剛好指向頭結(jié)點(diǎn)就可以直接用頭插。
  • 因?yàn)檫@里調(diào)用了頭插,所以這里也要使用二級(jí)指針來操作。
    相關(guān)程序代碼:
//在pos之前插入
void SLInsertFront(SLTNode** pphead,SLTNode* pos,SLTDataType x)
{
	assert(pphead);
	assert(pos);
	//如果pos為第一個(gè)節(jié)點(diǎn),直接調(diào)用前面的頭插
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}

??刪除pos位置之后的節(jié)點(diǎn)

  • 找到要?jiǎng)h除節(jié)點(diǎn)的位置。
  • 將要?jiǎng)h除節(jié)點(diǎn)的 next 指向NULL。
  • 找到前一個(gè)節(jié)點(diǎn),將其next指向NULL。
  • 釋放要?jiǎng)h除節(jié)點(diǎn)及其后繼節(jié)點(diǎn)內(nèi)存空間。
    相關(guān)程序代碼:
void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}

??刪除pos位置之前的節(jié)點(diǎn)

  • 首先斷言(assert),然后再調(diào)用頭刪(SLPopFront).
  • 之后再將 prevnext 指向要?jiǎng)h除節(jié)點(diǎn)的next。
  • 釋放要?jiǎng)h除節(jié)點(diǎn)的內(nèi)存空間。
  • 釋放要?jiǎng)h除及其前面的節(jié)點(diǎn)。
    相關(guān)程序代碼:
void SLEraseFront(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		prev->next = pos->next;
		free(pos);
	}
}

??完整代碼

SList.h

#pragma once
// 輸入輸出所需頭文件
#include<stdio.h>
// malloc 所需頭文件
#include<stdlib.h>
// assert 所需頭文件
#include<assert.h>

// 每個(gè)節(jié)點(diǎn)的數(shù)據(jù)的類型
typedef int SLTDataType;

// 每個(gè)節(jié)點(diǎn)的結(jié)構(gòu)體
typedef struct SListNode
{
	// 存放該結(jié)點(diǎn)的數(shù)據(jù)
	SLTDataType data;
	// 存放下一個(gè)節(jié)點(diǎn)的地址,將整個(gè)結(jié)構(gòu)串聯(lián)成一個(gè)單鏈表
	struct SListNode* next;
}SLTNode;  // 用 typedef 將結(jié)構(gòu)體重命名為 SLTNode 便于后續(xù)寫程序 

//申請一個(gè)節(jié)點(diǎn)(包含初始化)
SLTNode* BuyLTNode(SLTDataType x);

//單鏈表的打印
void SLTPrint(SLTNode* phead);

//頭插節(jié)點(diǎn)
void SLPushFront(SLTNode** pphead, SLTDataType x);

//尾插節(jié)點(diǎn)
void SLPushBack(SLTNode** pphead, SLTDataType x);

//頭刪節(jié)點(diǎn)
void SLPopFront(SLTNode** pphead);

//尾刪節(jié)點(diǎn)
void SLPopBack(SLTNode** pphead);

//節(jié)點(diǎn)的查找
SLTNode* SLFind(SLTNode* phead, SLTDataType x);

//節(jié)點(diǎn)的修改
SLTNode* SLModify(SLTNode* phead, int target, int newdata);

//pos位置之前插入節(jié)點(diǎn)
void SLInsertFront(SLTNode** pphead, SLTNode* pos, SLTDataType x);

//pos位置之后插入節(jié)點(diǎn)
void SLInsertAfter(SLTNode* pos, SLTDataType x);

//pos位置之前刪除節(jié)點(diǎn)
void SLEraseFront(SLTNode** pphead, SLTNode* pos);

//pos位置之后刪除節(jié)點(diǎn)
void SLEraseAfter(SLTNode* pos);

//節(jié)點(diǎn)的銷毀
void SLDestory(SLTNode* plist, SLTNode* pos);

SList.c

#include"SList.h"

//單鏈表的打印
void SLPrint(SLTNode* phead)
{
	SLTNode* cur = phead;
	while (cur != NULL)
	{
		printf("%d->", cur->data);
		cur = cur->next;
	}
	printf("NULL\n");
}

//申請一個(gè)節(jié)點(diǎn)(包含初始化)
SLTNode* BuyLTNode(SLTDataType x)
{
	SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->next = NULL;

	return newnode;
}

//頭插節(jié)點(diǎn)
void SLPushFront(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);

	newnode->next = *pphead;
	*pphead = newnode;	
}

//尾插節(jié)點(diǎn)
void SLPushBack(SLTNode** pphead, SLTDataType x)
{
	SLTNode* newnode = BuyLTNode(x);
	assert(*pphead);
	//1,空鏈表
	//2,非空鏈表
	if (*pphead == NULL)
	{
		*pphead = newnode;
	}
	else
	{
		SLTNode* tail = *pphead;
		while (tail->next != NULL)
		{
			tail = tail->next;
		}

		tail->next = newnode;
	}
}

//頭刪節(jié)點(diǎn)
void SLPopFront(SLTNode** pphead)
{
	//assert(pphead);   //鏈表為空,pphead也不能為空,因?yàn)樗穷^指針plist的地址
	assert(*pphead);  //鏈表為空,不能頭刪。

	SLTNode* del = *pphead;
	*pphead = (*pphead)->next;
	free(del);
}

//尾刪節(jié)點(diǎn)
void SLPopBack(SLTNode** pphead)
{
	//assert(pphead);   //鏈表為空,pphead也不能為空,因?yàn)樗穷^指針plist的地址
	assert(*pphead);  //鏈表為空,不能頭刪
	if ((*pphead)->next == NULL)
	{
		free(*pphead);
		*pphead = NULL;
	}
	else
	{
		SLTNode* tail = *pphead;
		//找尾
		while (tail->next->next)
		{
			tail = tail->next;
		}
		free(tail->next);
		tail->next = NULL;
	}
}

//查找單鏈表的節(jié)點(diǎn)
SLTNode* SLFind(SLTNode* phead, SLTDataType x)
{
	SLTNode* cur = phead;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}

	return NULL;
}

//修改單鏈表的節(jié)點(diǎn)
SLTNode* SLModify(SLTNode* phead, int target, int newdata) 
{
	SLTNode* cur = phead;
	while (cur != NULL) {
		if (cur->data == target) {
			cur->data = newdata;
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//在pos之前插入節(jié)點(diǎn)
void SLInsertFront(SLTNode** pphead,SLTNode* pos,SLTDataType x)
{
	assert(pphead);
	assert(pos);
	if (*pphead == pos)
	{
		SLPushFront(pphead, x);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}
		SLTNode* newnode = BuyLTNode(x);
		prev->next = newnode;
		newnode->next = pos;
	}
}


//在pos之后插入節(jié)點(diǎn)
void SLInsertAfter(SLTNode* pos, SLTDataType x)
{
	assert(pos);

	SLTNode* newnode = BuyLTNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}


 //刪除pos位置之前的節(jié)點(diǎn)
void SLEraseFront(SLTNode** pphead, SLTNode* pos)
{
	assert(pphead);
	assert(pos);

	if (pos == *pphead)
	{
		SLPopFront(pphead);
	}
	else
	{
		SLTNode* prev = *pphead;
		while (prev->next != pos)
		{
			prev = prev->next;
		}

		prev->next = pos->next;
		free(pos);
	}
}

//刪除pos位置之后的節(jié)點(diǎn)
void SLEraseAfter(SLTNode* pos)
{
	assert(pos);
	assert(pos->next);

	SLTNode* next = pos->next;
	pos->next = next->next;
	free(next);
}


//單鏈表的銷毀
void SLDestory(SLTNode* plist,SLTNode* pos)
{
	assert(plist);

	while (pos)
	{
		plist = pos;
		pos = pos->next;
		free(plist);
		plist->next = NULL;
	}
	return;
}

Test,c


#include"SList.h"

void TestSList1()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPrint(plist);

	SLPushBack(&plist, 1);
	SLPushBack(&plist, 2);
	SLPushBack(&plist, 3);
	SLPushBack(&plist, 4);

	SLPrint(plist);

	SLPushBack(&plist, 5);

	SLPrint(plist);

	SLPopBack(&plist, 1);
	SLPopBack(&plist, 2);
	SLPopBack(&plist, 3);
	SLPopBack(&plist, 4);
	SLPopBack(&plist, 5);

	SLPrint(plist);

	SLPopFront(&plist, 1);
	SLPopFront(&plist, 2);
	SLPopFront(&plist, 3);
	SLPopFront(&plist, 4);

	SLPrint(plist);

}

void TestSList2()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLPushFront(&plist, 7);
	SLPrint(plist);


	SLModify(plist, 1, 999);
	SLPrint(plist);
	SLModify(plist, 2, 999);
	SLPrint(plist); 
	SLModify(plist, 3, 999);
	SLPrint(plist); 
	SLModify(plist, 4, 999);
	SLPrint(plist);
	SLModify(plist, 5, 999);
	SLPrint(plist);
	SLModify(plist, 6, 999);
	SLPrint(plist);
	SLModify(plist, 7, 999);
	SLPrint(plist);
}

void TestSList3()
{
	SLTNode* plist = NULL;
	SLPushFront(&plist, 1);
	SLPushFront(&plist, 2);
	SLPushFront(&plist, 3);
	SLPushFront(&plist, 4);
	SLPushFront(&plist, 5);
	SLPushFront(&plist, 6);
	SLPushFront(&plist, 7);
	SLPrint(plist);


	SLFind(&plist, 3);
	SLPrint(plist);
}
int main()
{
	//TestSList1();
	//TestSList2();
	TestSList3();
	return 0;
}

??寫在最后

單鏈表是一種與數(shù)組相對的數(shù)據(jù)結(jié)構(gòu),在實(shí)際的開發(fā)中很常見。它雖然不能像數(shù)組那樣隨機(jī)訪問,但它具有動(dòng)態(tài)的特點(diǎn),可以高效地進(jìn)行插入和刪除操作。了解單鏈表的實(shí)現(xiàn)方式和使用方法,有助于我們在實(shí)際開發(fā)中更加靈活地運(yùn)用它。

在本篇博客中,我們介紹了單鏈表的基本知識(shí),包括如何在單鏈表中插入節(jié)點(diǎn)和刪除節(jié)點(diǎn)。
需要注意的是,在單鏈表操作的過程中,對指針的操作十分關(guān)鍵,需要謹(jǐn)慎地操作。

感謝各位閱讀本小白的博客,希望能幫助到大家!也請大家嚴(yán)厲指出并糾正我在文章中的錯(cuò)誤。??文章來源地址http://www.zghlxwxcb.cn/news/detail-466186.html

到了這里,關(guān)于數(shù)據(jù)結(jié)構(gòu)——實(shí)現(xiàn)單向鏈表的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【數(shù)據(jù)結(jié)構(gòu)初階】三、 線性表里的鏈表(無頭+單向+非循環(huán)鏈表 -- C語言實(shí)現(xiàn))

    【數(shù)據(jù)結(jié)構(gòu)初階】三、 線性表里的鏈表(無頭+單向+非循環(huán)鏈表 -- C語言實(shí)現(xiàn))

    ========================================================================= 相關(guān)代碼gitee自取 : C語言學(xué)習(xí)日記: 加油努力 (gitee.com) ?========================================================================= 接上期 : 【數(shù)據(jù)結(jié)構(gòu)初階】二、 線性表里的順序表(C語言實(shí)現(xiàn)順序表)-CSDN博客 ?=========================

    2024年02月08日
    瀏覽(35)
  • 【數(shù)據(jù)結(jié)構(gòu)】單向鏈表

    【數(shù)據(jù)結(jié)構(gòu)】單向鏈表

    哈嘍,大家好,今天我們學(xué)習(xí)的是數(shù)據(jù)結(jié)構(gòu)里的鏈表,這里主要講的是不帶哨兵衛(wèi)頭節(jié)點(diǎn)的單向鏈表,下篇將會(huì)繼續(xù)帶大家學(xué)習(xí)雙向鏈表。 目錄 1.鏈表的概念 2.單向鏈表接口的實(shí)現(xiàn) 2.1動(dòng)態(tài)申請一個(gè)節(jié)點(diǎn) 2.2單鏈表打印 2.3單鏈表尾插 2.4單鏈表頭插 2.5單鏈表尾刪 2.6單鏈表頭刪

    2024年02月11日
    瀏覽(27)
  • 數(shù)據(jù)結(jié)構(gòu)入門(C語言版)線性表中鏈表介紹及無頭單向非循環(huán)鏈表接口實(shí)現(xiàn)

    數(shù)據(jù)結(jié)構(gòu)入門(C語言版)線性表中鏈表介紹及無頭單向非循環(huán)鏈表接口實(shí)現(xiàn)

    概念 : 線性表的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)的特點(diǎn)是用一組任意的存儲(chǔ)單元存儲(chǔ)線性表的數(shù)據(jù)元素 。因此,為了表示每個(gè)數(shù)據(jù)元素與其直接后繼數(shù)據(jù)元素之間的邏輯關(guān)系,對數(shù)據(jù)元素來說,除了存儲(chǔ)其本身的信息之外,還需存儲(chǔ)一個(gè)指示其直接后繼的信息(即直接后繼的存儲(chǔ)位置)。這

    2023年04月09日
    瀏覽(32)
  • 數(shù)據(jù)結(jié)構(gòu)_鏈表_單向循環(huán)鏈表的初始化、插入、刪除、修改、查詢打印(基于C語言實(shí)現(xiàn))

    數(shù)據(jù)結(jié)構(gòu)_鏈表_單向循環(huán)鏈表的初始化、插入、刪除、修改、查詢打?。ɑ贑語言實(shí)現(xiàn))

    版本: 2024年4月25日 V1.0 發(fā)布于博客園 目錄 目錄 單向循環(huán)鏈表公式 初始化單向循環(huán)鏈表 構(gòu)建單向循環(huán)鏈表結(jié)點(diǎn) 創(chuàng)建一個(gè)空鏈表(僅頭結(jié)點(diǎn)) 創(chuàng)建一個(gè)新結(jié)點(diǎn) 插入數(shù)據(jù) 頭插 中插 尾插 刪除數(shù)據(jù) 頭刪 中刪 尾刪 查詢打印數(shù)據(jù) 遍歷打印 測試 測試結(jié)果: 完整代碼 CircularLinkedLis

    2024年04月25日
    瀏覽(51)
  • 數(shù)據(jù)結(jié)構(gòu)與算法(三):單向鏈表

    數(shù)據(jù)結(jié)構(gòu)與算法(三):單向鏈表

    鏈表是一種物理存儲(chǔ)單元上非連續(xù)、非順序的存儲(chǔ)結(jié)構(gòu),數(shù)據(jù)元素的邏輯是通過鏈表種的指針鏈接次序?qū)崿F(xiàn)的。鏈表由一系列節(jié)點(diǎn)組成,每個(gè)節(jié)點(diǎn)包括兩部分:一個(gè)是存儲(chǔ)數(shù)據(jù)元素的數(shù)據(jù)域,一個(gè)是存儲(chǔ)下一個(gè)節(jié)點(diǎn)地址的指針域。單向鏈表從頭節(jié)點(diǎn)(也可以沒有頭節(jié)點(diǎn))開始

    2024年02月15日
    瀏覽(28)
  • 【數(shù)據(jù)結(jié)構(gòu)】動(dòng)圖詳解單向鏈表

    【數(shù)據(jù)結(jié)構(gòu)】動(dòng)圖詳解單向鏈表

    目錄 1.什么是鏈表 ? ? ? ? 1.問題引入 ? ? ? ? 2. 鏈表的概念及結(jié)構(gòu) ? ? ? ? 3. 問題解決 2.單向鏈表接口的實(shí)現(xiàn) ????????1.接口1,2---頭插,尾插 ????????2. 接口3,4---頭刪,尾刪 ????????3. 接口5---查找 ?????????4. 接口6,7---插入,刪除 ????????5.?接口

    2024年01月18日
    瀏覽(27)
  • 【數(shù)據(jù)結(jié)構(gòu)篇】手寫雙向鏈表、單向鏈表(超詳細(xì))

    【數(shù)據(jù)結(jié)構(gòu)篇】手寫雙向鏈表、單向鏈表(超詳細(xì))

    什么是鏈表 ? 鏈表(Linked List)是用鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)實(shí)現(xiàn)的線性表。鏈表示意圖: 鏈表的組成 : 數(shù)據(jù)域 + 引用域 (數(shù)據(jù)域和引用域合稱結(jié)點(diǎn)或元素) 數(shù)據(jù)域存放數(shù)據(jù)元素自身的數(shù)據(jù) 引用域存放相鄰結(jié)點(diǎn)的地址 鏈表的特點(diǎn) : 鏈表中元素的聯(lián)系依靠引用域 具有線性結(jié)構(gòu)的特

    2024年02月11日
    瀏覽(30)
  • 數(shù)據(jù)結(jié)構(gòu):線性表之-單向鏈表(無頭)

    數(shù)據(jù)結(jié)構(gòu):線性表之-單向鏈表(無頭)

    目錄 什么是單向鏈表 順序表和鏈表的區(qū)別和聯(lián)系 順序表: 鏈表: 鏈表表示(單項(xiàng))和實(shí)現(xiàn) 1.1 鏈表的概念及結(jié)構(gòu) 1.2單鏈表(無頭)的實(shí)現(xiàn) 所用文件 將有以下功能: 鏈表定義 創(chuàng)建新鏈表元素 尾插 頭插 尾刪 頭刪 查找-給一個(gè)節(jié)點(diǎn)的指針 改 pos位置之前插入 刪除pos位置的值 成品

    2024年02月09日
    瀏覽(96)
  • 數(shù)據(jù)結(jié)構(gòu)——單向鏈表(C語言版)

    在數(shù)據(jù)結(jié)構(gòu)和算法中,鏈表是一種常見的數(shù)據(jù)結(jié)構(gòu),它由一系列節(jié)點(diǎn)組成,每個(gè)節(jié)點(diǎn)包含數(shù)據(jù)和指向下一個(gè)節(jié)點(diǎn)的指針。在C語言中,我們可以使用指針來實(shí)現(xiàn)單向鏈表。下面將詳細(xì)介紹如何用C語言實(shí)現(xiàn)單向鏈表。 目錄 1. 定義節(jié)點(diǎn)結(jié)構(gòu)體 2. 初始化鏈表 3. 插入節(jié)點(diǎn) 4. 刪除節(jié)點(diǎn)

    2024年03月24日
    瀏覽(33)
  • 數(shù)據(jù)結(jié)構(gòu)《鏈表》無頭單向非循環(huán)-動(dòng)圖詳解

    數(shù)據(jù)結(jié)構(gòu)《鏈表》無頭單向非循環(huán)-動(dòng)圖詳解

    前面學(xué)習(xí)了順序表發(fā)現(xiàn),順序表雖然好,但也有很多不足的地方,比方說,順序表是一塊連續(xù)的物理空間,如果頭插或者頭刪,那么整個(gè)數(shù)組的數(shù)據(jù)都要移動(dòng)。但是鏈表不一樣,鏈表是通過指針訪問或者調(diào)整,鏈表是物理空間是不連續(xù)的,通過當(dāng)前的next指針找到下一個(gè)。 插

    2024年02月06日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包