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

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

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

目錄

1.單向鏈表的劣勢

2.帶頭雙向循環(huán)鏈表

? ? ? ? 1.邏輯結(jié)構(gòu)

? ? ? ?2.結(jié)點的代碼實現(xiàn)

3.雙向鏈表接口的實現(xiàn)

????????1.接口1---初始化

????????2.接口2,3---頭插,尾插

????????3. 接口4,5---頭刪,尾刪

????????3. 接口6---查找

?????????4. 接口7,8--插入,刪除

????????5.?接口8---打印

????????6.?接口9--銷毀

4.完整代碼及效果展示?


1.單向鏈表的劣勢

? ? ? ? 上期我們講解了鏈表8種結(jié)構(gòu)中最為常用的兩種結(jié)構(gòu)之一單向不帶頭不循環(huán)鏈表的基本概念和實現(xiàn)方法(傳送門:動圖詳解單向鏈表)。但是在實現(xiàn)時我們發(fā)現(xiàn)了以下局限性:

  1. 由于單鏈表是單向的,當(dāng)我們想進行插入或者刪除時,由于無法直接找到前驅(qū)結(jié)點,導(dǎo)致我們還需再使用一個指針遍歷鏈表找到前一個結(jié)點的位置。這就導(dǎo)致了進行插入和刪除的時間復(fù)雜度為O(N),時間效率較低。
  2. 由于我們需要再使用一個指針指向鏈表前一個結(jié)點,這也可能在一些情況下導(dǎo)致出錯,例如鏈表只有一個結(jié)點。(詳情請見上一期,含動圖分析)
  3. 由于其不帶頭結(jié)點,頭指針直接指向第一個有效結(jié)點,所以在進行頭插等可能改變頭指針的操作時我們?nèi)绻麄饕患壷羔樉蜁鲥e。

2.帶頭雙向循環(huán)鏈表

? ? ? ? 1.邏輯結(jié)構(gòu)

? ? ? ? 那么,我們要如何解決以上劣勢呢?這就不得不說到另一種最為常見的鏈表結(jié)構(gòu):帶頭雙向循環(huán)鏈表。

? ? ? ? 頭結(jié)點:所謂頭結(jié)點,其作用就是標(biāo)識鏈表的有效部分。我們之前實現(xiàn)的無頭結(jié)點的鏈表,都是通過頭指針直接指向鏈表的有效數(shù)據(jù)部分。而帶頭結(jié)點的鏈表,則是用頭指針指向一個不存放有效數(shù)據(jù)的結(jié)點,這個結(jié)點就稱作頭結(jié)點。這個結(jié)點的next指針存放的下一個結(jié)點才是鏈表的有效結(jié)點部分。圖示如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

??????????帶頭雙向循環(huán)鏈表:其結(jié)構(gòu)是8種結(jié)構(gòu)中最復(fù)雜的,一般用在單獨存儲數(shù)據(jù)。實際中使用的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。此鏈表的結(jié)點在單向鏈表的基礎(chǔ)上,添加了前驅(qū)指針prev指向上一個結(jié)點,然后添加了上述所描述的頭結(jié)點,而循環(huán)則是體現(xiàn)在首尾結(jié)點相連上。另外這個結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使用代碼實現(xiàn)以后會發(fā)現(xiàn)結(jié)構(gòu)會帶來很多優(yōu)勢,實現(xiàn)起來反而更加簡單。邏輯結(jié)構(gòu)如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

注:藍色箭頭代表邏輯上指針的指向,均表示某個結(jié)點next或prev指針指向另一個結(jié)點,下同。

? ? ? ?2.結(jié)點的代碼實現(xiàn)

? ? ? ? 根據(jù)單向鏈表結(jié)點的代碼實現(xiàn)和雙向鏈表的結(jié)構(gòu)體,我們可以得出其結(jié)點的結(jié)構(gòu)體定義如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

3.雙向鏈表接口的實現(xiàn)

? ? ? ? 我們同樣先在主函數(shù)中定義一個頭指針用于指向我們的頭結(jié)點,后續(xù)通過這個指針來完成對鏈表各種接口的實現(xiàn)。由于頭指針并不直接指向有效數(shù)據(jù)部分,有效數(shù)據(jù)是從第二個結(jié)點開始的,因此當(dāng)我們對數(shù)據(jù)進行操作時并不需要改變頭指針的內(nèi)容,只需進行傳值調(diào)用,用一級指針接收即可,可以有效避免頭指針被無意修改。

????????1.接口1---初始化

? ? ? ? 在使用鏈表前,我們需要對鏈表進行初始化。我們可以在初始化接口中創(chuàng)建一個頭結(jié)點并將其返回給頭指針,代碼如下:

//用于創(chuàng)建新結(jié)點
ListNode* CreatNode(ListDateType x)
{
	ListNode* cur=(ListNode*)malloc(sizeof(ListNode));
	cur->date = x;
	cur->next = NULL;
	cur->prev = NULL;
	return cur;
}

//鏈表初始化
ListNode* InitList()
{
	ListNode* phead=CreatNode(0); //創(chuàng)建頭結(jié)點
	phead->next = phead; //前驅(qū)指針指向自身
	phead->prev = phead; //后繼指針指向自身  
	return phead; //將這個結(jié)點返回
}

????????2.接口2,3---頭插,尾插

? ? ? ? 對于頭插,根據(jù)雙向循環(huán)鏈表結(jié)構(gòu)圖,我們只需將頭結(jié)點的next指向新結(jié)點,新結(jié)點的prev指向頭結(jié)點,next指向下一結(jié)點,下一結(jié)點的prev指向新結(jié)點即可完成頭插。具體過程如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

? ? ? ? ?代碼實現(xiàn)如下:

//頭插
void ListPushFront(ListNode* phead, ListDateType x) //不改變頭指針,無需傳址
{
	assert(phead != NULL); //保證鏈表有頭結(jié)點,即完成了初始化
	ListNode* NewNode = CreatNode(x); //創(chuàng)建新結(jié)點
	ListNode* frist = phead->next; //找到鏈表頭

    //進行頭插
	phead->next = NewNode;
	NewNode->prev = phead;
	NewNode->next = frist;
	frist->prev = NewNode;
}

?????????對于尾插,由于雙向循環(huán)鏈表結(jié)構(gòu)的特殊性,我們不需要向單鏈表一樣遍歷鏈表找到鏈表尾,直接通過頭結(jié)點的prev指針就可直接找到鏈表尾,也不需要再遍歷鏈表找到上一個結(jié)點。代碼反而變得更加簡單,只需要通過改變結(jié)點的prev和next指針即可完成尾插,這就是結(jié)構(gòu)帶來的優(yōu)勢。其時間復(fù)雜度為O(1)。具體過程如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

? ? ? ? 具體代碼如下:?

//尾插
void ListPushBack(ListNode* phead, ListDateType x)
{
	assert(phead != NULL); //保證鏈表已經(jīng)初始化
	ListNode* NewNode = CreatNode(x); //創(chuàng)建新結(jié)點
	ListNode* tail = phead->prev; //找到鏈表尾

    //進行尾插
	tail->next = NewNode; 
	NewNode->prev = tail;
	NewNode->next = phead;
	phead->prev = NewNode;
}

需要注意的是,與單鏈表不同,這里是雙向循環(huán)鏈表,所以鏈表尾并不是指向NULL,而是指向頭結(jié)點。同時不會出現(xiàn)對NULL解引用的情況,不需要對單向鏈表一樣進行分類討論。

????????3. 接口4,5---頭刪,尾刪

? ? ? ??對于頭刪,我們只需要將頭結(jié)點指向下一個位置,然后將原來指向的空間free()掉即可。如果鏈表為空,我們就讓函數(shù)直接返回,具體動態(tài)效果如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

? ? ? ? ?代碼實現(xiàn)如下:

//頭刪
void ListPopFront(ListNode* phead)
{
	assert(phead != NULL); //確保鏈表初始化
	if (phead->next == phead)
	{
		return; //鏈表為空直接返回,防止把頭結(jié)點刪除
	}
	ListNode* frist = phead->next; //找到鏈表頭
	ListNode* second = frist->next; //找到鏈表頭下一個結(jié)點

    //進行頭刪
	phead->next = second;
	second->prev = phead;
	free(frist); //釋放結(jié)點
	frist = NULL;
}

????????對于尾刪,我們同樣通過頭結(jié)點的prev指針直接找到鏈表尾,然后進行刪除操作,過程與頭刪類似,時間復(fù)雜度為O(1)。具體過程如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

? ? ? ? 具體代碼如下:

//尾刪
void ListPopBack(ListNode* phead)
{
	assert(phead != NULL); //確保鏈表已經(jīng)初始化
	if (phead->next == phead)
	{
		return; //鏈表為空直接返回,防止把頭結(jié)點刪除
	}
	ListNode* tail = phead->prev; //找到鏈表尾
	ListNode* prev = tail->prev;  //找到前驅(qū)

    //進行尾刪
	phead->prev = prev;
	prev->next = phead;
	free(tail); //釋放空間
	tail = NULL;
}

????????3. 接口6---查找

? ? ? ? 對于查找,其方法與單向鏈表一樣,通過遍歷鏈表的所有結(jié)點即可。有一點不同的是我們的雙向鏈表是循環(huán)的,因此循環(huán)的條件不再是cur!=NULL而是cur!=phead,當(dāng)cur等于頭指針時則說明已經(jīng)成功遍歷一遍了。代碼如下:

//查找
ListNode* ListFind(ListNode* phead, ListDateType x)
{
	assert(phead != NULL); //確保已經(jīng)初始化
	ListNode* cur = phead->next; //指向第一個有效結(jié)點,準(zhǔn)備遍歷
	while (cur != phead) //遍歷一圈
	{
		if (cur->date == x)
		{
			return cur; //找到了,返回結(jié)點
		}
		cur = cur->next; //指向下一結(jié)點
	}

    //找不到,返回空指針
	return NULL;
}

?????????4. 接口7,8--插入,刪除

? ? ? ? 對于插入,我們可以實現(xiàn)一個在指定結(jié)點前插入一個新結(jié)點的接口,而這個指定結(jié)點我們可以通過查找接口來獲取。由于我們的鏈表是雙向的,我們就可以很容易的得到新結(jié)點的前一個與后一個結(jié)點的位置,進而實現(xiàn)插入接口,其時間復(fù)雜度為O(1)。動態(tài)效果如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

//插入
void ListInsert(ListNode* phead, ListNode* pos, ListDateType x)
{
	assert(pos != NULL); //確保已經(jīng)初始化
	ListNode* NewNode = CreatNode(x); //創(chuàng)建新結(jié)點
	ListNode* prev = pos->prev; //前一個結(jié)點

    //進行插入
	NewNode->next = pos;
	pos->prev = NewNode;
	prev->next = NewNode;
	NewNode->prev = prev;

}

? ? ? ? 對于刪除,我們同樣可以實現(xiàn)一個刪除指定結(jié)點的接口,而這個指定結(jié)點我們依舊可以通過查找接口來獲取。同樣的,由于結(jié)構(gòu)上的優(yōu)勢,我們可以很方便的直接對指定位置進行刪除,時間復(fù)雜度為O(1)。具體過程如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

? ? ? ? 具體代碼如下:?

//刪除
void ListErase(ListNode* phead, ListNode* pos)
{
	assert(pos != NULL); //確保已經(jīng)初始化
	ListNode* next = pos->next; //后一個結(jié)點
	ListNode* prev = pos->prev; //前一個結(jié)點

    //進行刪除
	prev->next = next;
	next->prev = prev;
	free(pos); //釋放空間
	pos = NULL;
}

????????5.?接口8---打印

? ? ? ? 對于打印,很簡單,遍歷一圈鏈表即可,當(dāng)cur等于頭結(jié)點地址時停止打印。動圖效果如下:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)

? ? ? ? 具體代碼如下:?

//打印
void ListPrint(ListNode* phead)
{
	assert(phead != NULL); //確保鏈表已經(jīng)初始化
	ListNode* cur = phead->next; //指向有效部分
	while (cur != phead) //遍歷一圈
	{
		printf("%d ", cur->date); //打印數(shù)據(jù)
		cur = cur->next; //指向下一結(jié)點
	}
	printf("\n");
}

????????6.?接口9--銷毀

? ? ? ? 對于銷毀,我們動態(tài)內(nèi)存申請所得到的空間,當(dāng)我們不需要的時候,需要我們進行手動銷毀。因此,我們還需要一個接口對使用完畢的鏈表進行free(),具體代碼如下:

//銷毀
void ListDestroy(ListNode* phead)
{
	assert(phead != NULL); //確保已經(jīng)初始化
	ListNode* cur = phead->next; //指向有效部分
	while (cur != phead) //釋放有效結(jié)點
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}

	//釋放頭結(jié)點
	free(phead);
	phead = NULL;
}

通過上面一個個接口的實現(xiàn),我們發(fā)現(xiàn):

? ? ? ? 雖然雙向帶頭循環(huán)鏈表的結(jié)構(gòu)比起單向鏈表結(jié)構(gòu)復(fù)雜太多,但對于各接口的實現(xiàn)反而變得更加方便,并且很多接口時間效率更加地高。因此,一個好的結(jié)構(gòu)不僅可以簡化我們的代碼量,也可以提高我們代碼的效率。

4.完整代碼及效果展示?

? ? ? ? 我們同樣采用多文件編寫的形式,將上述接口的定義實現(xiàn)放在List.c文件中,然后將接口的聲明和結(jié)構(gòu)體的定義放于List.h頭文件中,以達到封裝的效果。這樣我們?nèi)绻枰褂秒p向鏈表,就只需要在文件中包含對應(yīng)的頭文件List.h就可以使用我們上面定義的各種接口。以下為本文實現(xiàn)的帶頭雙向循環(huán)鏈表完整代碼以及效果展示:

//List.h文件,用于聲明接口函數(shù),定義結(jié)構(gòu)體
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>

typedef int ListDateType; //重命名便于維護
typedef struct ListNode
{
	ListDateType date;
	struct ListNode* next; //指向前一個結(jié)點
	struct ListNode* prev; //指向后一個結(jié)點
}ListNode;

//初始化
ListNode* InitList();
//尾插
void ListPushBack(ListNode* phead, ListDateType x);
//頭插
void ListPushFront(ListNode* phead, ListDateType x);
//尾刪
void ListPopBack(ListNode* phead);
//頭刪
void ListPopFront(ListNode* phead);
//查找
ListNode* ListFind(ListNode* phead, ListDateType x);
//刪除
void ListErase(ListNode* phead, ListNode* pos);
//插入
void ListInsert(ListNode* phead, ListNode* pos, ListDateType x);
//打印
void ListPrint(ListNode * phead);
//銷毀
void ListDestroy(ListNode* phead);
//SList.c文件,用于定義接口函數(shù)
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"

ListNode* CreatNode(ListDateType x)
{
	ListNode* cur=(ListNode*)malloc(sizeof(ListNode));
	cur->date = x;
	cur->next = NULL;
	cur->prev = NULL;
	return cur;
}
ListNode* InitList()
{
	ListNode* phead = CreatNode(0); //創(chuàng)建頭結(jié)點
	phead->next = phead; //前驅(qū)指針指向自身
	phead->prev = phead; //后繼指針指向自身  
	return phead; //將這個結(jié)點返回
}

void ListPushBack(ListNode* phead, ListDateType x)
{
	assert(phead != NULL);
	ListNode* NewNode = CreatNode(x);
	ListNode* tail = phead->prev; //找到鏈表尾
	tail->next = NewNode; 
	NewNode->prev = tail;
	NewNode->next = phead;
	phead->prev = NewNode;
}

void ListPushFront(ListNode* phead, ListDateType x) //不改變頭指針,無需傳址
{
	assert(phead != NULL); //保證鏈表有頭結(jié)點,即完成了初始化
	ListNode* NewNode = CreatNode(x); //創(chuàng)建新結(jié)點
	ListNode* frist = phead->next; //找到鏈表頭

	//進行頭插
	phead->next = NewNode;
	NewNode->prev = phead;
	NewNode->next = frist;
	frist->prev = NewNode;
}

void ListPopBack(ListNode* phead)
{
	assert(phead != NULL);
	if (phead->next == NULL)
	{
		return; //鏈表為空直接返回
	}
	ListNode* tail = phead->prev; //找到鏈表尾
	ListNode* prev = tail->prev;  //找到前驅(qū)
	phead->prev = prev;
	prev->next = phead;
	free(tail);
	tail = NULL;

}

void ListPopFront(ListNode* phead)
{
	assert(phead != NULL); //確保鏈表初始化
	if (phead->next == NULL)
	{
		return; //鏈表為空直接返回
	}
	ListNode* frist = phead->next; //找到鏈表頭
	ListNode* second = frist->next; //找到鏈表頭下一個結(jié)點

	//進行頭刪
	phead->next = second;
	second->prev = phead;
	free(frist); //釋放結(jié)點
	frist = NULL;
}

ListNode* ListFind(ListNode* phead, ListDateType x)
{
	assert(phead != NULL); //確保已經(jīng)初始化
	ListNode* cur = phead->next; //指向第一個有效結(jié)點,準(zhǔn)備遍歷
	while (cur != phead) //遍歷一圈
	{
		if (cur->date == x)
		{
			return cur; //找到了,返回結(jié)點
		}
		cur = cur->next; //指向下一結(jié)點
	}

	//找不到,返回空指針
	return NULL;
}

void ListErase(ListNode* phead, ListNode* pos)
{
	assert(pos != NULL); //確保已經(jīng)初始化
	ListNode* next = pos->next; //后一個結(jié)點
	ListNode* prev = pos->prev; //前一個結(jié)點

	//進行刪除
	prev->next = next;
	next->prev = prev;
	free(pos); //釋放空間
	pos = NULL;
}

void ListInsert(ListNode* phead, ListNode* pos, ListDateType x)
{
	assert(pos != NULL); //確保已經(jīng)初始化
	ListNode* NewNode = CreatNode(x); //創(chuàng)建新結(jié)點
	ListNode* prev = pos->prev; //前一個結(jié)點

	//進行插入
	NewNode->next = pos;
	pos->prev = NewNode;
	prev->next = NewNode;
	NewNode->prev = prev;

}

void ListPrint(ListNode* phead)
{
	assert(phead != NULL); //確保鏈表已經(jīng)初始化
	ListNode* cur = phead->next; //指向有效部分
	while (cur != phead) //遍歷一圈
	{
		printf("%d ", cur->date); //打印數(shù)據(jù)
		cur = cur->next; //指向下一結(jié)點
	}
	printf("\n");
}

void ListDestroy(ListNode* phead)
{
	assert(phead != NULL); //確保已經(jīng)初始化
	ListNode* cur = phead->next; //指向有效部分
	while (cur != phead) //釋放有效結(jié)點
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}

	//釋放頭結(jié)點
	free(phead);
	phead = NULL;
}

? ? ? ?最后, 我們在text.c文件調(diào)用雙向循環(huán)鏈表各個接口進行測試,如下:

//text.c文件,用于測試
#define _CRT_SECURE_NO_WARNINGS 1
#include "List.h"
void ListText()
{
	ListNode* plist = NULL;
	//初始化
	plist = InitList();
	printf("鏈表起始數(shù)據(jù):\n");
	ListPrint(plist);
	//尾插
	ListPushBack(plist, 1);
	ListPushBack(plist, 2);
	ListPushBack(plist, 3);
	printf("尾插后數(shù)據(jù):\n");
	ListPrint(plist);
	//頭插
	ListPushFront(plist, 4);
	ListPushFront(plist,5);
	ListPushFront(plist, 6);
	printf("頭插后數(shù)據(jù):\n");
	ListPrint(plist);
	//尾刪
	ListPopBack(plist);
	printf("尾刪后數(shù)據(jù):\n");
	ListPrint(plist);
	//頭刪
	ListPopFront(plist);
	printf("頭刪后數(shù)據(jù):\n");
	ListPrint(plist);

	//修改數(shù)據(jù)為5的結(jié)點為50
	ListNode* cur1 = ListFind(plist, 5); //找數(shù)據(jù)為5結(jié)點
	if (cur1)
	{
		cur1->date = 50; //查找附帶著修改的作用
	}
	printf("修改數(shù)據(jù)為5的結(jié)點為50后\n");
	ListPrint(plist);

	//在date為4的結(jié)點前插入數(shù)據(jù)為7的結(jié)點
	ListNode* cur2 = ListFind(plist,4); //找數(shù)據(jù)為4結(jié)點
	if (cur2) 
	{
		ListInsert(plist, cur2, 7); //插入
	}
	printf("在4前插入7后數(shù)據(jù):\n");
	ListPrint(plist);
	//刪除數(shù)據(jù)為1的結(jié)點
	ListNode* cur3 = ListFind(plist, 1); //找數(shù)據(jù)為1結(jié)點
	if (cur3) 
	{
		ListErase(plist, cur3); //刪除
	}
	printf("刪除1后數(shù)據(jù):\n");
	ListPrint(plist);
	//銷毀
	ListDestroy(plist);
}
int main()
{
	ListText();
	return 0;
}

? ? ? ? 以下就是測試的最終效果:

雙向鏈表動畫演示,數(shù)據(jù)結(jié)構(gòu),鏈表,數(shù)據(jù)結(jié)構(gòu),c語言,學(xué)習(xí)


?以上,就是本期的全部內(nèi)容。

制作不易,能否點個贊再走呢qwq文章來源地址http://www.zghlxwxcb.cn/news/detail-819143.html

到了這里,關(guān)于【數(shù)據(jù)結(jié)構(gòu)】動圖詳解雙向鏈表的文章就介紹完了。如果您還想了解更多內(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):詳解【鏈表】的實現(xiàn)(單向鏈表+雙向鏈表)

    數(shù)據(jù)結(jié)構(gòu):詳解【鏈表】的實現(xiàn)(單向鏈表+雙向鏈表)

    1.順序表的問題和思考 問題: 中間/頭部的插入刪除,時間復(fù)雜度為O(N)。 增容需要申請新空間,拷貝數(shù)據(jù),釋放舊空間,會有不小的消耗。 增容一般是呈2倍的增長,勢必會有一定的空間浪費。例如當(dāng)前容量為100,滿了以后增容到200,我們再繼續(xù)插入了5個數(shù)據(jù),后面沒有數(shù)據(jù)

    2024年03月26日
    瀏覽(36)
  • 數(shù)據(jù)結(jié)構(gòu)之雙向鏈表詳解

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

    ??博主CSDN主頁:小源_?? ???個人專欄:《數(shù)據(jù)結(jié)構(gòu)》??? ??努力追逐大佬們的步伐~ 上一篇文章中我們重點講解了無頭單向非循環(huán)鏈表的模擬實現(xiàn),現(xiàn)在我們來講解LinkedList(無頭雙向鏈表實現(xiàn) )的模擬實現(xiàn)。 本章重點: 本文著重講解了LinkedList(無頭雙向單鏈表)的實現(xiàn)

    2024年02月04日
    瀏覽(20)
  • 數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)分享之雙向鏈表詳解

    數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)分享之雙向鏈表詳解

    ? ? ??博主CSDN:杭電碼農(nóng)-NEO???????? ? ? ? ?專欄分類:數(shù)據(jù)結(jié)構(gòu)學(xué)習(xí)分享(持續(xù)更新中??)??????? ? ? ? 我們上一期說到,兩鏈表中有兩個最常用的結(jié)構(gòu),一個是最簡單的無頭不循環(huán)單向鏈表,還有一個就是 結(jié)構(gòu)相對比較復(fù)雜的帶頭雙向循環(huán)鏈表 ,我們這一章節(jié)就來

    2024年02月04日
    瀏覽(27)
  • 數(shù)據(jù)結(jié)構(gòu) - 鏈表詳解(二)—— 帶頭雙向循環(huán)鏈表

    數(shù)據(jù)結(jié)構(gòu) - 鏈表詳解(二)—— 帶頭雙向循環(huán)鏈表

    鏈表的結(jié)構(gòu)一共有 八種 :帶頭單向循環(huán)鏈表、帶頭單向非循環(huán)鏈表、帶頭雙向循環(huán)鏈表、帶頭雙向非循環(huán)鏈表、無頭單向循環(huán)鏈表、無頭單向非循環(huán)鏈表、無頭雙向循環(huán)鏈表、無頭雙向非循環(huán)鏈表。 今天我們來詳解帶頭雙向循環(huán)鏈表 帶頭雙向循環(huán)鏈表是一種數(shù)據(jù)結(jié)構(gòu),它通

    2024年04月26日
    瀏覽(21)
  • 數(shù)據(jù)結(jié)構(gòu):線性表之-循環(huán)雙向鏈表(萬字詳解)

    數(shù)據(jù)結(jié)構(gòu):線性表之-循環(huán)雙向鏈表(萬字詳解)

    目錄 基本概念 1,什么是雙向鏈表 2,與單向鏈表的區(qū)別 雙向鏈表詳解 功能展示: 1. 定義鏈表 2,創(chuàng)建雙向鏈表 3,初始化鏈表 4,尾插 5,頭插 6,尾刪 判斷鏈表是否被刪空 尾刪代碼 7,頭刪 8,pos位置之前插入 優(yōu)化后的頭插 優(yōu)化后的尾插 9,刪除pos位置的節(jié)點 優(yōu)化后的尾刪 優(yōu)

    2024年02月09日
    瀏覽(23)
  • 數(shù)據(jù)結(jié)構(gòu):圖文詳解雙向鏈表的各種操作(頭插法,尾插法,任意位置插入,查詢節(jié)點,刪除節(jié)點,求鏈表的長度... ...)

    數(shù)據(jù)結(jié)構(gòu):圖文詳解雙向鏈表的各種操作(頭插法,尾插法,任意位置插入,查詢節(jié)點,刪除節(jié)點,求鏈表的長度... ...)

    目錄 一.雙向鏈表的概念 二.雙向鏈表的數(shù)據(jù)結(jié)構(gòu) 三.雙向鏈表的實現(xiàn) 節(jié)點的插入 頭插法 尾插法 任意位置插入 節(jié)點的刪除 刪除鏈表中第一次出現(xiàn)的目標(biāo)節(jié)點 刪除鏈表中所有與相同的節(jié)點 節(jié)點的查找 鏈表的清空 鏈表的長度 四.模擬實現(xiàn)鏈表的完整代碼 前言: 在上一

    2024年02月05日
    瀏覽(29)
  • 數(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) - 雙向鏈表

    文章目錄 目錄 文章目錄 前言 一、什么是雙向鏈表? 雙向鏈表有什么優(yōu)勢? 二、雙向鏈表的設(shè)計和實現(xiàn) 1.設(shè)計思想 尾增 : 在鏈表的末尾添加新的元素 ?頭插 : 在鏈表頭部插入節(jié)點 ?刪除 : 根據(jù)val的值刪除節(jié)點 ?查找 : 根據(jù)索引的值查找并返回節(jié)點 總結(jié) 大家好,今天給大家講解

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

    單向鏈表:一塊內(nèi)存指向下一個內(nèi)存。 單鏈表存在一些缺陷: 1.查找速度慢。 2.不能從后往前找。 3.找不到前驅(qū)。 鏈表的結(jié)構(gòu)分為8種: 1.單向和雙向 2.帶頭和不帶頭 帶頭的鏈表有一個帶哨兵位的頭結(jié)點,這個節(jié)點不存儲有效數(shù)據(jù)。 好處 :尾插更方便,不需要二級指針了,

    2024年02月02日
    瀏覽(25)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包