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

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

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

目錄

概念

帶頭雙向循環(huán)鏈表的實現(xiàn)

前情提示

雙向鏈表的結(jié)構(gòu)體定義

雙向鏈表的初始化

關(guān)于無頭單向非循環(huán)鏈表無需初始化函數(shù),順序表、帶頭雙向循環(huán)鏈表需要的思考

雙向鏈表在pos位置之前插入x

雙向鏈表的打印

雙鏈表刪除pos位置的結(jié)點

雙向鏈表的尾插

關(guān)于單鏈表的尾插需要用到二級指針,雙向鏈表不需要用到二級指針的思考

雙向鏈表的判空

雙向鏈表的尾刪

雙向鏈表的頭插?

雙向鏈表的頭刪

雙向鏈表查找值為x的結(jié)點

雙向鏈表的銷毀?

雙向鏈表的修改

雙向鏈表刪除值為x的結(jié)點

?雙向鏈表計算結(jié)點總數(shù)(不計phead)

雙向鏈表獲取第i位置的結(jié)點

雙向鏈表的清空

總代碼(想直接看結(jié)果的可以看這里)


概念

雙向鏈表也叫雙鏈表,是鏈表的一種,它的每個數(shù)據(jù)結(jié)點中都有兩個指針,分別指向直接后繼和直接前驅(qū)。所以,從雙向鏈表中的任意一個結(jié)點開始,都可以很方便地訪問它的前驅(qū)結(jié)點和后繼結(jié)點。我們一般構(gòu)造雙向循環(huán)鏈表。循環(huán)鏈表是一種鏈式存儲結(jié)構(gòu),它的最后一個結(jié)點指向頭結(jié)點,形成一個環(huán)。因此,從循環(huán)鏈表中的任何一個結(jié)點出發(fā)都能找到任何其它結(jié)點。

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)


帶頭雙向循環(huán)鏈表的實現(xiàn)

前情提示

List.h??用于? 引用的頭文件、雙向鏈表的定義、函數(shù)的聲明。

List.c? 用于? 函數(shù)的定義。

Test.c?用于? 雙向鏈表功能的測試。

雙向鏈表的結(jié)構(gòu)體定義

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

在List.h下

#pragma once//使同一個文件不會被包含(include)多次,不必擔(dān)心宏名沖突

//先將可能使用到的頭文件寫上
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int LTDataType;//假設(shè)結(jié)點的數(shù)據(jù)域類型為 int
//給變量定義一個易于記憶且意義明確的新名字,并且便于以后存儲其它類型時方便改動
//(比如我晚點想存double類型的數(shù)據(jù),我就直接將 int 改為 double )

// 帶哨兵位雙向循環(huán)鏈表的結(jié)構(gòu)體定義
typedef struct ListNode
{
	struct ListNode* prev;//前驅(qū)指針域:存放上一個結(jié)點的地址
	struct ListNode* next;//后繼指針域:存放下一個結(jié)點的地址
	LTDataType data;//數(shù)據(jù)域
}LTNode;
//struct 關(guān)鍵字和 ListNode 一起構(gòu)成了這個結(jié)構(gòu)類型
//typedef 為這個結(jié)構(gòu)起了一個別名,叫 LTNode,即:typedef struct ListNode LTNode 
//現(xiàn)在就可以像 int 和 double 那樣直接使用 LTNode 來定義變量

雙向鏈表的初始化

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

在List.h下

// 雙向鏈表的初始化

// 如果是單鏈表直接給個空指針就行,不需要單獨寫一個函數(shù)進行初始化
// 即:LTNode* plist = NULL;
// 那為什么順序表、帶頭雙向循環(huán)鏈表有呢?
// 因為順序表、帶頭雙向循環(huán)鏈表的結(jié)構(gòu)并不簡單,
// 如:    順序表順序表為空size要為0,還要看capacity是否要開空間,
// 若不開空間capacity=0,指針要給空,若開空間,還要檢查malloc是否成功
//	      帶頭雙向循環(huán)鏈表要開個結(jié)點,檢查malloc是否成功,然后讓結(jié)點自己指向自己
// 順序表和雙向循環(huán)鏈表的初始化有點復(fù)雜,最好構(gòu)建一個函數(shù)
LTNode* LTInit();

在List.c下

#include"List.h"http://別忘了

//動態(tài)申請一個結(jié)點
LTNode* BuyListNode(LTDataType x)
{
	LTNode* node = (LTNode*)malloc(sizeof(LTNode));
	if (node == NULL)//如果malloc失敗
	{
		perror("malloc fail");
		return NULL;
	}
	//如果malloc成功
	//初始化一下,防止野指針,如果看到返回的是空指針,那邏輯可能有些錯誤
	node->next = NULL;
	node->prev = NULL;
	node->data = x;

	return node;
}

// 雙向鏈表的初始化
LTNode* LTInit()
{
	LTNode* phead = BuyListNode(-1);//創(chuàng)建哨兵位
	//自己指向自己
	phead->next = phead;
	phead->prev = phead;

	return phead;
}

關(guān)于無頭單向非循環(huán)鏈表無需初始化函數(shù),順序表、帶頭雙向循環(huán)鏈表需要的思考

無頭單向非循環(huán)鏈表結(jié)構(gòu)太簡單了,初始化只需直接賦空指針,無需單獨寫一個函數(shù)進行初始化。

即:LTNode* plist = NULL;

那為什么順序表、帶頭雙向循環(huán)鏈表有單獨寫一個函數(shù)進行初始化呢?
因為順序表、帶頭雙向循環(huán)鏈表的結(jié)構(gòu)并不簡單。

如:

順序表順序表為空size要為0,還要看capacity是否要開空間,若不開空間capacity=0,指針要給空,若開空間,還要檢查malloc是否成功。

帶頭雙向循環(huán)鏈表要開個結(jié)點,檢查malloc是否成功,然后讓結(jié)點自己指向自己。

順序表和雙向循環(huán)鏈表的初始化有點復(fù)雜,最好構(gòu)建一個函數(shù)。

雙向鏈表在pos位置之前插入x

在List.h下

// 雙向鏈表在pos位置之前進行插入
void LTInsert(LTNode* pos, LTDataType x);

在List.c下

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表在pos位置之前進行插入
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);//pos肯定不為空

	LTNode* prev = pos->prev;
	LTNode* newnode = BuyListNode(x);//創(chuàng)建一個需要插入的結(jié)點

	prev->next = newnode;
	newnode->prev = prev;

	newnode->next = pos;
	pos->prev = newnode;
}

雙向鏈表的打印

在List.h下

// 雙向鏈表打印
void LTPrint(LTNode* phead);

在List.c下

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表打印
void LTPrint(LTNode* phead)
{
	assert(phead);//有哨兵位
	printf("<=>phead<=>");
	LTNode* cur = phead->next;//cur指向第一個要打印的結(jié)點
	while (cur != phead)//cur等于頭結(jié)點時打印就結(jié)束了
	{
		printf("%d<=>", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

在Test.c下

#include"List.h"http://別忘了

//測試函數(shù)
void TestList1()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);
}

int main()
{
	TestList1();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙鏈表刪除pos位置的結(jié)點

在List.h下

// 雙向鏈表刪除pos位置的結(jié)點
void LTErase(LTNode* pos);

在List.c下

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表刪除pos位置的結(jié)點
void LTErase(LTNode* pos)
{
	assert(pos);//pos肯定不為空

	LTNode* posprev = pos->prev;
	LTNode* posnext = pos->next;

	posprev->next = posnext;
	posnext->prev = posprev;

	free(pos);
	pos = NULL;
    //這個置空其實已經(jīng)沒有意義了,形參的改變不會改變實參
}

在Test.c下

//測試函數(shù)
void TestList1()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTErase(plist->next);
	LTPrint(plist);

}

int main()
{
	TestList1();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表的尾插

在List.h下

//雙向鏈表優(yōu)于單鏈表的點——不需要找尾、二級指針
//(我們改的不是結(jié)構(gòu)體的指針,改的是結(jié)構(gòu)體的變量)
// 雙向鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x);

在List.c下

法一:(便于新手更好地理解雙向鏈表的尾插)?

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位
    
    //法一:(便于新手更好地理解雙向鏈表的尾插)
	//一步就可完成鏈表為空/不為空的尾插——因為有哨兵位
	LTNode* newnode = BuyListNode(x);//創(chuàng)建一個要插入的結(jié)點
	LTNode* tail = phead->prev;

	tail->next = newnode;
	newnode->prev = tail;
	newnode->next = phead;
	phead->prev = newnode;
}

法二:函數(shù)復(fù)用(簡單方便)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位

	//法二:函數(shù)復(fù)用(簡單方便)
	LTInsert(phead, x);
}

關(guān)于單鏈表的尾插需要用到二級指針,雙向鏈表不需要用到二級指針的思考

單鏈表改變的是結(jié)構(gòu)體的指針,雙向鏈表改變的是結(jié)構(gòu)體的變量

二級指針和一級指針的區(qū)別在于指針?biāo)赶蜃兞康膶蛹壊煌?strong>一級指針指向的是結(jié)構(gòu)體的變量,而二級指針指向的是結(jié)構(gòu)體指針的地址。
單鏈表中,在進行鏈表結(jié)點的刪除或插入操作時,需要更新結(jié)點之間的指針指向。若使用一級指針,則操作會直接改變指向結(jié)點的指針,很難實現(xiàn)目標(biāo)。因此需要傳遞二級指針,讓函數(shù)能夠修改指向結(jié)點指針的地址,也就是修改之前結(jié)點指針變量存放的地址
而雙向鏈表中,每個結(jié)點除了保存指向下一結(jié)點的指針外,還有保存指向上一結(jié)點的指針,結(jié)點之間的雙向指針關(guān)系使得結(jié)點的插入和刪除操作更加方便。雙向鏈表不需要傳遞二級指針,因為在結(jié)點的刪除和插入操作中,只需要先修改當(dāng)前結(jié)點前后結(jié)點的指針,無需直接改變前后結(jié)點指針變量存放的地址
綜上所述,單鏈表只有指向下一結(jié)點的指針,通過傳遞二級指針來修改結(jié)點之間的指針關(guān)系,使得操作更加靈活;而雙向鏈表的結(jié)點之間有雙向指針關(guān)系,無需直接改變前后結(jié)點指針變量存放的地址,因此只需要傳遞一級指針即可。

單鏈表(對比):

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

在Test.c下

//測試函數(shù)
void TestList2()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 5);
	LTPushBack(plist, 6);
	LTPushBack(plist, 7);
	LTPushBack(plist, 8);
	LTPrint(plist);
}

int main()
{
	TestList2();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表的判空

在尾刪/頭刪之前,我們要先判斷鏈表是否為空。

在List.h下

// 雙向鏈表的判空
bool LTEmpty(LTNode* phead);

在List.c下

// 雙向鏈表的判空
bool LTEmpty(LTNode* phead)
{
	assert(phead);

	return phead->next == phead;
	//兩者相等就是空鏈表(返回真),兩者不相等就不是空鏈表(返回假)
}

雙向鏈表的尾刪

在List.h下

// 雙向鏈表的尾刪
void LTPopBack(LTNode* phead);

在List.c下

法一:(便于新手更好地理解雙向鏈表的尾刪)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表的尾刪
void LTPopBack(LTNode* phead)
{
	assert(phead);//有哨兵位
	assert(!LTEmpty(phead));//判空

    //法一:(便于新手更好地理解雙向鏈表的尾刪)
	LTNode* tail = phead->prev;
	LTNode* tailPrev = tail->prev;

	tailPrev->next = phead;
	phead->prev = tailPrev;
	free(tail);
	tail = NULL;
}

法二:函數(shù)復(fù)用(簡單方便)

// 雙向鏈表的尾刪
void LTPopBack(LTNode* phead)
{
	assert(phead);//有哨兵位
    assert(!LTEmpty(phead));//判空
	
    //法二:函數(shù)復(fù)用
	LTErase(phead->prev);
}

在Test.c下

//測試函數(shù)
void TestList2()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 5);
	LTPushBack(plist, 6);
	LTPushBack(plist, 7);
	LTPushBack(plist, 8);
	LTPrint(plist);

	LTPopBack(plist);
	LTPopBack(plist);
	LTPrint(plist);
}

int main()
{
	TestList2();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表的頭插?

在List.h下

// 雙向鏈表頭插
void LTPushFront(LTNode* phead, LTDataType x);

在List.c下

法一:只用phead和newnode兩個指針(便于新手更好地理解雙向鏈表的頭插)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位

	LTNode* newnode = BuyListNode(x);//創(chuàng)建一個要插入的結(jié)點
    
    //法一:只用phead和newnode兩個指針(便于新手更好地理解雙向鏈表的頭插)
    //順序很重要?。?!
	newnode->next = phead->next;
	phead->next->prev = newnode;

	phead->next = newnode;
	newnode->prev = phead;
}

法二:多用了first記錄第一個結(jié)點的位置(便于新手更好地理解雙向鏈表的頭插)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);//哨兵位

	LTNode* newnode = BuyListNode(x);//創(chuàng)建一個要插入的結(jié)點

	//法二:多用了first先記住第一個結(jié)點(便于新手更好地理解雙向鏈表的頭插)
	LTNode* first = phead->next;
	phead->next = newnode;
	newnode->prev = phead;

	newnode->next = first;
	first->prev = newnode;
}

法三:函數(shù)復(fù)用(簡單方便)

// 雙向鏈表頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位
	
	//法三:函數(shù)復(fù)用(簡單方便)
	LTInsert(phead->next, x);
}

在Test.c下

//測試函數(shù)
void TestList3()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 4);
	LTPrint(plist);
}

int main()
{
	TestList3();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表的頭刪

在List.h下

// 雙向鏈表頭刪
void LTPopFront(LTNode* phead);

在List.c下

法一:(便于新手更好地理解雙向鏈表的頭刪)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表頭刪
void LTPopFront(LTNode* phead)
{
	assert(phead);//有哨兵位
	assert(!LTEmpty(phead));//判空
	
    //法一:(便于新手更好地理解雙向鏈表的頭刪)
	LTNode* head = phead->next;
	LTNode* headnext = head->next;

	phead->next = headnext;
	headnext->prev = phead;

	free(head);
	head = NULL;
}

法二:函數(shù)復(fù)用(簡單方便)?

// 雙向鏈表頭刪
void LTPopFront(LTNode* phead)
{
	assert(phead);//有哨兵位
    assert(!LTEmpty(phead));//判空
	
    //法二:函數(shù)復(fù)用(簡單方便)
	LTErase(phead->next);
}

在Test.c下

//測試函數(shù)
void TestList3()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 4);
	LTPrint(plist);

	LTPopFront(plist);
	LTPopFront(plist);
	LTPrint(plist);
}

int main()
{
	TestList3();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表查找值為x的結(jié)點

在List.h下

// 雙向鏈表查找值為x的結(jié)點
LTNode* LTFind(LTNode* phead, LTDataType x);

在List.c下

// 雙向鏈表查找值為x的結(jié)點
LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位

	LTNode* cur = phead->next;
	while (cur != phead)//讓cur去遍歷
	{
		if (cur->data == x)//如果找到
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;//如果沒找到
}

在Test.c下

//測試函數(shù)
TestList4()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTNode* pos = LTFind(plist, 3);
	if (pos)
	{
		LTErase(pos);
		pos = NULL;
	}

	LTPrint(plist);
}

int main()
{
	TestList4();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表的銷毀?

在List.h下

// 雙向鏈表的銷毀
void LTDestory(LTNode* phead);

在List.c下

? ?雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

??雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

?雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

// 雙向鏈表的銷毀
void LTDestory(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;//讓cur遍歷
	while (cur != phead)
	{
		LTNode* curnext = cur->next;
		free(cur);
		cur = curnext;
	}
	free(phead);
	phead = NULL;
	//這個置空其實已經(jīng)沒有意義了,形參的改變不會改變實參
	//我們?yōu)榱吮3纸涌诘囊恢滦?不傳二級指針,選擇在測試的時候置空
}

在Test.c下

//測試函數(shù)
TestList4()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTNode* pos = LTFind(plist, 3);
	if (pos)
	{
		LTErase(pos);
		pos = NULL;
	}
	LTPrint(plist);

	LTDestory(plist);
	plist = NULL;//在這里置空
}

雙向鏈表的修改

在List.h下

// 雙向鏈表的修改,修改pos位置的值為x
void LTModify(LTNode* pos, LTDataType x);

在List.c下

// 雙向鏈表的修改,修改pos位置的值為x
void LTModify(LTNode* pos, LTDataType x)
{
	assert(pos);
	pos->data = x;
}

在Test.c下

//測試函數(shù)
TestList5()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTModify(plist->next,5);
	LTPrint(plist);
}

int main()
{
	TestList5();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表刪除值為x的結(jié)點

在List.h下

// 雙向鏈表刪除值為x的結(jié)點
void LTRemove(LTNode* phead,LTDataType x);

在List.c下

// 雙向鏈表刪除值為x的結(jié)點
void LTRemove(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位
	LTNode* pos = phead->next;
	while (pos != phead)
	{
		pos = LTFind(phead, x);
		if (pos == NULL)//如果遍歷完
		{
			return NULL;
		}
		LTErase(pos);
		pos = pos->next;
	}
}

在Test.c下

TestList6()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 3);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTInsert(plist, 3);
	LTPrint(plist);

	LTRemove(plist, 3);
	LTPrint(plist);
}

int main()
{
	TestList6();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

?雙向鏈表計算結(jié)點總數(shù)(不計phead)

在List.h下

// 雙向鏈表計算結(jié)點總數(shù)(不計phead)
int LTTotal(LTNode* phead);

在List.c下

// 雙向鏈表計算結(jié)點總數(shù)(不計phead)
int LTTotal(LTNode* phead)
{
	assert(phead);//有哨兵位

	int count = 0;//count來計數(shù)
	LTNode* cur = phead->next;//讓cur去遍歷
	while (cur != phead)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

在Test.c下

TestList6()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 3);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTInsert(plist, 3);
	LTPrint(plist);

	LTRemove(plist, 3);
	LTPrint(plist);

	printf("%d\n", LTTotal(plist));
}

int main()
{
	TestList6();
	return 0;
}

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

雙向鏈表獲取第i位置的結(jié)點

在List.h下

// 雙向鏈表獲取第i位置的結(jié)點
LTNode* LTGet(LTNode* phead, int i);

在List.c下

// 雙向鏈表獲取第i位置的結(jié)點
LTNode* LTGet(LTNode* phead, int i)
{
	assert(phead);//有哨兵位

	int length = LTTotal(phead);
	LTNode* cur = phead->next;
	if (i == 0)
	{
		return phead;
	}
	else if (i<0 || i>length)//位置不合法
	{
		return NULL;
	}
	else if (i <= (length / 2))//從表頭開始遍歷
	{
		cur = phead->next;
		for (int count = 1; count < i; count++)
		{
			cur = cur->next;
		}
	}
	else//從表尾開始遍歷
	{
		cur = phead->prev;
		for (int count = 1; count <= length - i; count++)
		{
			cur = cur->prev;
		}
	}
	return cur;
}

在Test.c下

//測試函數(shù)
TestList7()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 5);
	LTInsert(plist, 6);
	LTInsert(plist, 7);
	LTInsert(plist, 8);
	LTInsert(plist, 9);
	LTPrint(plist);

	LTNode* pos = LTGet(plist,3);
	if (pos)
	{
		LTErase(pos);
		pos = NULL;
	}
	LTPrint(plist);
}

int main()
{
	TestList7();
	return 0;
}

雙向鏈表的清空

在List.h下

// 雙向鏈表的清空
void LTClean(LTNode* phead);

在List.c下

// 雙向鏈表的清空
void LTClear(LTNode* phead)
{
	assert(phead);//有哨兵位

	while (!LTEmpty(phead))//如果不為空就一直頭刪
	{
		LTPopFront(phead);
	}
}

在Test.c下

//測試函數(shù)
TestList8()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 5);
	LTInsert(plist, 6);
	LTInsert(plist, 7);
	LTInsert(plist, 8);
	LTInsert(plist, 9);
	LTPrint(plist);

	LTClear(plist);
	LTPrint(plist);
}

int main()
{
	TestList8();
	return 0;
}

總代碼(想直接看結(jié)果的可以看這里)

在List.h下

#pragma once//使同一個文件不會被包含(include)多次,不必擔(dān)心宏名沖突


//先將可能使用到的頭文件寫上
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>

typedef int LTDataType;//假設(shè)結(jié)點的數(shù)據(jù)域類型為 int
//給變量定義一個易于記憶且意義明確的新名字,并且便于以后存儲其它類型時方便改動
//(比如我晚點想存double類型的數(shù)據(jù),我就直接將 int 改為 double )

// 帶哨兵位雙向循環(huán)鏈表的結(jié)構(gòu)體定義
typedef struct ListNode
{
	struct ListNode* prev;//前驅(qū)指針域:存放上一個結(jié)點的地址
	struct ListNode* next;//后繼指針域:存放下一個結(jié)點的地址
	LTDataType data;//數(shù)據(jù)域
}LTNode;
//struct 關(guān)鍵字和 ListNode 一起構(gòu)成了這個結(jié)構(gòu)類型
//typedef 為這個結(jié)構(gòu)起了一個別名,叫 LTNode,即:typedef struct ListNode LTNode 
//現(xiàn)在就可以像 int 和 double 那樣直接使用 LTNode 來定義變量



// 雙向鏈表的初始化

// 如果是單鏈表直接給個空指針就行,不需要單獨寫一個函數(shù)進行初始化
// 即:LTNode* plist = NULL;
// 那為什么順序表、帶頭雙向循環(huán)鏈表有呢?
// 因為順序表、帶頭雙向循環(huán)鏈表的結(jié)構(gòu)并不簡單,
// 如:順序表順序表為空size要為0,還要看capacity是否要開空間,
//若不開空間capacity=0,指針要給空,若開空間,還要檢查malloc是否成功
// 帶頭雙向循環(huán)鏈表要開個結(jié)點,檢查malloc是否成功,然后讓結(jié)點自己指向自己
// 順序表和雙向循環(huán)鏈表的初始化有點復(fù)雜,最好構(gòu)建一個函數(shù)
LTNode* LTInit();

// 雙向鏈表在pos位置之前進行插入x
void LTInsert(LTNode* pos, LTDataType x);

// 雙向鏈表的打印
void LTPrint(LTNode* phead);

// 雙向鏈表刪除pos位置的結(jié)點
void LTErase(LTNode* pos);

//雙向鏈表優(yōu)于單鏈表的點——不需要找尾、二級指針
// (我們改的不是結(jié)構(gòu)體的指針,改的是結(jié)構(gòu)體的變量)
// 雙向鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x);

// 雙向鏈表的判空
bool LTEmpty(LTNode* phead);

// 雙向鏈表的尾刪
void LTPopBack(LTNode* phead);

// 雙向鏈表頭插
void LTPushFront(LTNode* phead, LTDataType x);

// 雙向鏈表頭刪
void LTPopFront(LTNode* phead);

// 雙向鏈表查找值為x的結(jié)點
LTNode* LTFind(LTNode* phead, LTDataType x);

// 雙向鏈表的銷毀
void LTDestory(LTNode* phead);

// 雙向鏈表的修改,修改pos位置的值為x
void LTModify(LTNode* pos, LTDataType x);

// 雙向鏈表刪除值為x的結(jié)點
void LTRemove(LTNode* phead, LTDataType x);

// 雙向鏈表計算結(jié)點總數(shù)(不計phead)
int LTTotal(LTNode* phead);

// 雙向鏈表獲取第i位置的結(jié)點
LTNode* LTGet(LTNode* phead, int i);

// 雙向鏈表的清空
void LTClear(LTNode* phead);

在List.c下

#include"List.h"

//動態(tài)申請一個結(jié)點
LTNode* BuyListNode(LTDataType x)
{
	LTNode* node = (LTNode*)malloc(sizeof(LTNode));
	if (node == NULL)//如果malloc失敗
	{
		perror("malloc fail");
		return NULL;
	}
	//如果malloc成功
	//初始化一下,防止野指針,如果看到返回的是空指針,那邏輯可能有些錯誤
	node->next = NULL;
	node->prev = NULL;
	node->data = x;

	return node;
}

// 雙向鏈表的初始化
LTNode* LTInit()
{
	LTNode* phead = BuyListNode(-1);
	//自己指向自己
	phead->next = phead;
	phead->prev = phead;

	return phead;
}

// 雙向鏈表在pos位置之前進行插入x
void LTInsert(LTNode* pos, LTDataType x)
{
	assert(pos);//pos肯定不為空

	LTNode* prev = pos->prev;
	LTNode* newnode = BuyListNode(x);//創(chuàng)建一個需要插入的結(jié)點

	prev->next = newnode;
	newnode->prev = prev;

	newnode->next = pos;
	pos->prev = newnode;
}

// 雙向鏈表的打印
void LTPrint(LTNode* phead)
{
	assert(phead);//有哨兵位
	printf("<=>phead<=>");
	LTNode* cur = phead->next;//cur指向第一個要打印的結(jié)點
	while (cur != phead)//cur等于頭結(jié)點時打印就結(jié)束了
	{
		printf("%d<=>", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

// 雙向鏈表刪除pos位置的結(jié)點
void LTErase(LTNode* pos)
{
	assert(pos);//pos肯定不為空

	LTNode* posprev = pos->prev;
	LTNode* posnext = pos->next;

	posprev->next = posnext;
	posnext->prev = posprev;

	free(pos);
	pos = NULL;
	//這個置空其實已經(jīng)沒有意義了,形參的改變不會改變實參
}

// 雙向鏈表的尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位

	//法一:(便于新手更好地理解雙向鏈表的尾插)
	//一步就可完成鏈表為空/不為空的尾插
	//LTNode* newnode = BuyListNode(x);
	//LTNode* tail = phead->prev;

	//tail->next = newnode;
	//newnode->prev = tail;
	//newnode->next = phead;
	//phead->prev = newnode;

	//法二:函數(shù)復(fù)用(簡單方便)
	LTInsert(phead, x);
}

// 雙向鏈表的判空
bool LTEmpty(LTNode* phead)
{
	assert(phead);

	return phead->next == phead;
	//兩者相等就是空鏈表(返回真),兩者不相等就不是空鏈表(返回假)
}

// 雙向鏈表的尾刪
void LTPopBack(LTNode* phead)
{
	assert(phead);//有哨兵位

	//法一:(便于新手更好地理解雙向鏈表的尾刪)
	//assert(!LTEmpty(phead));//判空

	//LTNode* tail = phead->prev;
	//LTNode* tailPrev = tail->prev;

	//tailPrev->next = phead;
	//phead->prev = tailPrev;
	//free(tail);
	//tail = NULL;

	//法二:函數(shù)復(fù)用
	LTErase(phead->prev);
}

// 雙向鏈表頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位

	//LTNode* newnode = BuyListNode(x);//創(chuàng)建一個要插入的結(jié)點

	//法一:只用phead和newnode兩個指針(便于新手更好地理解雙向鏈表的頭插)
	//newnode->next = phead->next;
	//phead->next->prev = newnode;

	//phead->next = newnode;
	//newnode->prev = phead;

	//法二:多用了first先記住第一個結(jié)點(便于新手更好地理解雙向鏈表的頭插)
	//LTNode* first = phead->next;
	//phead->next = newnode;
	//newnode->prev = phead;

	//newnode->next = first;
	//first->prev = newnode;

	//法三:函數(shù)復(fù)用(簡單方便)
	LTInsert(phead->next, x);
}

// 雙向鏈表頭刪
void LTPopFront(LTNode* phead)
{
	assert(phead);//有哨兵位
	assert(!LTEmpty(phead));//判空

	//法一:(便于新手更好地理解雙向鏈表的頭刪)
	//LTNode* head = phead->next;
	//LTNode* headnext = head->next;

	//phead->next = headnext;
	//headnext->prev = phead;

	//free(head);
	//head = NULL;

	//法二:函數(shù)復(fù)用(簡單方便)
	LTErase(phead->next);
}

// 雙向鏈表查找值為x的結(jié)點
LTNode* LTFind(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位

	LTNode* cur = phead->next;
	while (cur != phead)//讓cur去遍歷
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

// 雙向鏈表的銷毀
void LTDestory(LTNode* phead)
{
	assert(phead);

	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* curnext = cur->next;
		free(cur);
		cur = curnext;
	}
	free(phead);
	phead = NULL;
	//這個置空其實已經(jīng)沒有意義了,形參的改變不會改變實參
	//我們?yōu)榱吮3纸涌诘囊恢滦?不傳二級指針,選擇在測試的時候置空
}

// 雙向鏈表的修改,修改pos位置的值為x
void LTModify(LTNode* pos, LTDataType x)
{
	assert(pos);//pos肯定不為空
	pos->data = x;
}

// 雙向鏈表刪除值為x的結(jié)點
void LTRemove(LTNode* phead, LTDataType x)
{
	assert(phead);//有哨兵位
	LTNode* pos = phead->next;
	while (pos != phead)
	{
		pos = LTFind(phead, x);
		if (pos == NULL)//如果遍歷完
		{
			return NULL;
		}
		LTErase(pos);
		pos = pos->next;
	}
}

// 雙向鏈表計算結(jié)點總數(shù)(不計phead)
int LTTotal(LTNode* phead)
{
	assert(phead);//有哨兵位

	int count = 0;//count來計數(shù)
	LTNode* cur = phead->next;//讓cur去遍歷
	while (cur != phead)
	{
		count++;
		cur = cur->next;
	}
	return count;
}

// 雙向鏈表獲取第i位置的結(jié)點
LTNode* LTGet(LTNode* phead, int i)
{
	assert(phead);//有哨兵位

	int length = LTTotal(phead);
	LTNode* cur = phead->next;
	if (i == 0)
	{
		return phead;
	}
	else if (i<0 || i>length)//位置不合法
	{
		return NULL;
	}
	else if (i <= (length / 2))//從表頭開始遍歷
	{
		cur = phead->next;
		for (int count = 1; count < i; count++)
		{
			cur = cur->next;
		}
	}
	else//從表尾開始遍歷
	{
		cur = phead->prev;
		for (int count = 1; count <= length - i; count++)
		{
			cur = cur->prev;
		}
	}
	return cur;
}

// 雙向鏈表的清空
void LTClear(LTNode* phead)
{
	assert(phead);//有哨兵位

	while (!LTEmpty(phead))//如果不為空就一直頭刪
	{
		LTPopFront(phead);
	}
}

在Test.c下

#include"List.h"

//測試函數(shù)
void TestList1()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTErase(plist->next);
	LTPrint(plist);

}

//測試函數(shù)
void TestList2()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 5);
	LTPushBack(plist, 6);
	LTPushBack(plist, 7);
	LTPushBack(plist, 8);
	LTPrint(plist);

	LTPopBack(plist);
	LTPopBack(plist);
	LTPrint(plist);

}

//測試函數(shù)
void TestList3()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 4);
	LTPrint(plist);

	LTPopFront(plist);
	LTPopFront(plist);
	LTPrint(plist);
}

//測試函數(shù)
TestList4()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTNode* pos = LTFind(plist, 3);
	if (pos)
	{
		LTErase(pos);
		pos = NULL;
	}
	LTPrint(plist);

	LTDestory(plist);
	plist = NULL;//在這里置空
}

//測試函數(shù)
TestList5()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 2);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTPrint(plist);

	LTModify(plist->next, 5);
	LTPrint(plist);

}

TestList6()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 1);
	LTInsert(plist, 3);
	LTInsert(plist, 3);
	LTInsert(plist, 4);
	LTInsert(plist, 3);
	LTPrint(plist);

	LTRemove(plist, 3);
	LTPrint(plist);

	printf("%d\n", LTTotal(plist));
}

//測試函數(shù)
TestList7()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 5);
	LTInsert(plist, 6);
	LTInsert(plist, 7);
	LTInsert(plist, 8);
	LTInsert(plist, 9);
	LTPrint(plist);

	LTNode* pos = LTGet(plist, 3);
	if (pos)
	{
		LTErase(pos);
		pos = NULL;
	}
	LTPrint(plist);

	LTClear(plist);
	LTPrint(plist);
}

//測試函數(shù)
TestList8()
{
	LTNode* plist = LTInit();
	LTInsert(plist, 5);
	LTInsert(plist, 6);
	LTInsert(plist, 7);
	LTInsert(plist, 8);
	LTInsert(plist, 9);
	LTPrint(plist);

	LTClear(plist);
	LTPrint(plist);
}

int main()
{
	//TestList1();
	//TestList2();
	//TestList3();
	//TestList4();
	//TestList5();
	//TestList6();
	//TestList7();
	TestList8();
	return 0;
}

歡迎指正?

雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)

?文章來源地址http://www.zghlxwxcb.cn/news/detail-439784.html

到了這里,關(guān)于雙向鏈表(數(shù)據(jù)結(jié)構(gòu))(C語言)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 【數(shù)據(jù)結(jié)構(gòu)】—C語言實現(xiàn)雙向鏈表(超詳細!)

    【數(shù)據(jù)結(jié)構(gòu)】—C語言實現(xiàn)雙向鏈表(超詳細!)

    ??????????????????????????????? ??? ? 食用指南:本文在有C基礎(chǔ)的情況下食用更佳 ? ????????????????????????????? ??? ? ?? 這就不得不推薦此專欄了:C語言 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 雙向鏈表 前 置知識 :單鏈表 ? ? ?

    2024年02月13日
    瀏覽(23)
  • 【數(shù)據(jù)結(jié)構(gòu)】C語言實現(xiàn)雙向鏈表(帶頭結(jié)點、循環(huán))

    【數(shù)據(jù)結(jié)構(gòu)】C語言實現(xiàn)雙向鏈表(帶頭結(jié)點、循環(huán))

    結(jié)點定義: 接口定義: 我們將申請結(jié)點的代碼封裝成函數(shù),方便后續(xù)使用 由于是帶頭結(jié)點的雙向鏈表,因此在使用鏈表前,我們需要對鏈表進行初始化。 遍歷鏈表,值得說的是,帶頭結(jié)點的雙向鏈表的循環(huán)結(jié)束條件是 cur != phead 尾插時,需要先找到尾結(jié)點,然后將新結(jié)點插

    2024年02月03日
    瀏覽(96)
  • 【數(shù)據(jù)結(jié)構(gòu)初階】四、線性表里的鏈表(帶頭+雙向+循環(huán) 鏈表 -- C語言實現(xiàn))

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

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

    2024年02月08日
    瀏覽(30)
  • 『初階數(shù)據(jù)結(jié)構(gòu) ? C語言』⑨ - 基于結(jié)點的數(shù)據(jù)結(jié)構(gòu)——鏈表(單鏈表&&雙向循環(huán)鏈表)附完整源碼

    『初階數(shù)據(jù)結(jié)構(gòu) ? C語言』⑨ - 基于結(jié)點的數(shù)據(jù)結(jié)構(gòu)——鏈表(單鏈表&&雙向循環(huán)鏈表)附完整源碼

    ? 本章內(nèi)容 1.什么是鏈表 2.鏈表常見幾種形式 3.無頭單向非循環(huán)鏈表的實現(xiàn) 3.1結(jié)點結(jié)構(gòu)的定義 3.2函數(shù)接口的實現(xiàn) 3.2.1尾插 3.2.2尾刪 4. 帶頭雙向循環(huán)鏈表的實現(xiàn) 4.1結(jié)點結(jié)構(gòu)的定義 4.2函數(shù)接口的實現(xiàn) 5.兩種鏈表的差異 ①尾插與尾刪的時間復(fù)雜度 ②頭插與頭刪的時間復(fù)雜度 ③

    2024年02月16日
    瀏覽(95)
  • 鏈接未來:深入理解鏈表數(shù)據(jù)結(jié)構(gòu)(二.c語言實現(xiàn)帶頭雙向循環(huán)鏈表)

    鏈接未來:深入理解鏈表數(shù)據(jù)結(jié)構(gòu)(二.c語言實現(xiàn)帶頭雙向循環(huán)鏈表)

    上篇文章簡述講解了鏈表的基本概念并且實現(xiàn)了無頭單向不循環(huán)鏈表:鏈接未來:深入理解鏈表數(shù)據(jù)結(jié)構(gòu)(一.c語言實現(xiàn)無頭單向非循環(huán)鏈表)-CSDN博客 那今天接著給大家?guī)韼ь^雙向循環(huán)鏈表的實現(xiàn) : 頭文件DoubleList.h:用來基礎(chǔ)準備(常量定義,typedef),鏈表表的基本框架

    2024年01月16日
    瀏覽(58)
  • C語言數(shù)據(jù)結(jié)構(gòu)(鏈表概念講解和插入操作)

    C語言數(shù)據(jù)結(jié)構(gòu)(鏈表概念講解和插入操作)

    本篇文章帶大家正式的來學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu),數(shù)據(jù)結(jié)構(gòu)是學(xué)習(xí)操作系統(tǒng),和深入C語言必不可少的,所以這篇文章開始帶大家學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的知識。 鏈表(Linked List)是一種常見的數(shù)據(jù)結(jié)構(gòu),用于存儲和組織數(shù)據(jù)元素。它由一系列節(jié)點(Node)組成,每個節(jié)點包含存儲的數(shù)據(jù)(或稱

    2024年02月06日
    瀏覽(24)
  • 數(shù)據(jù)結(jié)構(gòu)_鏈表_雙向循環(huán)鏈表的初始化、插入、刪除、修改、查詢打?。ɑ贑語言實現(xiàn))

    數(shù)據(jù)結(jié)構(gòu)_鏈表_雙向循環(huán)鏈表的初始化、插入、刪除、修改、查詢打印(基于C語言實現(xiàn))

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

    2024年04月27日
    瀏覽(36)
  • 數(shù)據(jù)結(jié)構(gòu)-鏈表結(jié)構(gòu)-雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)-鏈表結(jié)構(gòu)-雙向鏈表

    雙向鏈表也叫雙鏈表,與單向鏈表不同的是,每一個節(jié)點有三個區(qū)域組成:兩個指針域,一個數(shù)據(jù)域 前一個指針域:存儲前驅(qū)節(jié)點的內(nèi)存地址 后一個指針域:存儲后繼節(jié)點的內(nèi)存地址 數(shù)據(jù)域:存儲節(jié)點數(shù)據(jù) 以下就是雙向鏈表的最基本單位 節(jié)點的前指針域指向前驅(qū),后指針

    2024年02月04日
    瀏覽(31)
  • 【數(shù)據(jù)結(jié)構(gòu)】雙向奔赴的愛戀 --- 雙向鏈表

    【數(shù)據(jù)結(jié)構(gòu)】雙向奔赴的愛戀 --- 雙向鏈表

    關(guān)注小莊 頓頓解饞????? 引言:上回我們講解了單鏈表(單向不循環(huán)不帶頭鏈表),我們可以發(fā)現(xiàn)他是存在一定缺陷的,比如尾刪的時候需要遍歷一遍鏈表,這會大大降低我們的性能,再比如對于鏈表中的一個結(jié)點我們是無法直接訪問它的上一個結(jié)點,那有什么解決方法呢

    2024年04月08日
    瀏覽(27)
  • 數(shù)據(jù)結(jié)構(gòu)—雙向鏈表

    數(shù)據(jù)結(jié)構(gòu)—雙向鏈表

    目錄 1.? 鏈表的種類 2.? 最實用的兩種鏈表類型 3.? 實現(xiàn)雙向帶頭循環(huán)鏈表 ? ? ? ? ? ? ? ? ? 3.1 創(chuàng)建頭節(jié)點 ????????3.2 實現(xiàn)雙向循環(huán)功能—返回頭指針 ????????3.3? 尾插?? ????????3.4 頭插 ????????3.5 尾刪 ????????3.6 頭刪 4.? 實現(xiàn)兩個重要接口函數(shù) ?

    2023年04月23日
    瀏覽(28)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包