導言
大家好,很高興又和大家見面啦?。?!
經過前面幾個篇章的內容分享,相信大家對順序表和單鏈表的基本操作都已經熟練掌握了。今天咱們將繼續(xù)分享線性表的鏈式存儲的第二種形式——雙鏈表。在今天的內容中,咱們將介紹雙鏈表的創(chuàng)建以及一些基本操作,接下來跟我一起來看看吧!
一、單鏈表與雙鏈表
線性表的鏈式存儲稱為鏈表,鏈表是由數(shù)據(jù)域和指針域組成。
由一個數(shù)據(jù)域和一個指針域組成的鏈表我們稱為單鏈表,單鏈表的指針域指向后繼結點,所以我們在訪問單鏈表時只能從前往后訪問。這就導致了一個問題:我們在訪問后繼結點時的時間復雜度為O(1),但是在訪問前驅結點時的時間復雜度卻是O(n)。
為了克服單鏈表的這種單一訪問的缺點,于是我們在單鏈表的結點上新增了一個指針域,使得鏈表上的每個結點都由一個數(shù)據(jù)域和兩個指針域組成,雙鏈表的結點結構如下所示:
這兩個指針域一個指向后繼結點(next),一個指向前驅結點(prior),我們將由這種結構的結點構成的鏈表稱為雙鏈表。
雙鏈表和單鏈表一樣,雙鏈表也有帶頭結點的雙鏈表與不帶頭結點的雙鏈表,在沒有特殊說明的情況下,我們都是以帶頭結點的雙鏈表進行說明。接下來我們就來看一下與雙鏈表相關的基本操作;
二、雙鏈表類型的創(chuàng)建
我們首先來看一下雙鏈表的類型創(chuàng)建的基本格式:
//雙鏈表類型創(chuàng)建的基本格式
typedef struct DNode {
ElemType data;//數(shù)據(jù)域
struct DNode* prior, * next;//指針域
}DNode, * DLinkList;//數(shù)據(jù)類型重命名
//DNode——Double Node——強調的是雙鏈表的結點
//DLinkList——強調的是指向雙鏈表的指針,也就是整個雙鏈表
//prior——在先的,在前的,先前的——指向前驅結點的指針
//next——下一個的,緊接著的,接下來的——指向后繼結點的指針
//ElemType——數(shù)據(jù)元素的數(shù)據(jù)類型
//data——存儲鏈表數(shù)據(jù)元素的變量
從格式中可以看到,其實雙鏈表與單鏈表的類型創(chuàng)建格式是一致的,它們之間的差別有以下幾點:
- 為了對這兩種類型的鏈表有所區(qū)分,單鏈表的結點類型我們將其定義為
LNode
,雙鏈表則是DNode
; - 單鏈表的類型我們將其定義為
LinkList
,雙鏈表則是DLinkList
; - 在雙鏈表中,我們定義了一個額外的指針
prior
用于指向前驅結點;
有了這個基本格式,我們同樣還是以整型類型的數(shù)據(jù)元素為例來定義一個雙鏈表,如下所示:
//創(chuàng)建雙鏈表類型
typedef struct DNode {
int data;
struct DNode* prior, * next;
}DNode, * DLinkList;
int main()
{
DLinkList L;//定義指向雙鏈表的頭指針
return 0;
}
有了雙鏈表的頭指針,接下來我們就可以來創(chuàng)建雙鏈表的頭結點并將其初始化了;
三、雙鏈表的初始化
我們先來看一下雙鏈表初始化的基本格式:
//雙鏈表初始化的基本格式
bool InitDLinkList(DLinkList* L)
{
*L = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建頭結點
assert(*L);//如果頭結點創(chuàng)建失敗,則報錯
(*L)->prior = NULL;//初始化前驅指針
(*L)->next = NULL;//初始化后繼指針
return true;
}
可以看到,對于雙鏈表來說,我們在初始化頭結點時不僅要將后繼指針進行初始化,還要將前驅指針進行初始化,這樣是為了防止這兩個指針變成野指針。
在單鏈表中有一點我們沒有提到,就是我們在通過
malloc
和calloc
申請空間后一定要及時的對接收空間的指針進行檢測,看是否為空指針。當空間申請失敗后,這兩個函數(shù)返回的就是一個空指針,所以為了避免出現(xiàn)問題,我們可以通過assert來進行斷言,也可以通過條件語句來進行判斷。
對指針這一塊的知識掌握的不牢固的朋友可以通過【C語言必學知識點五】指針這篇博客來復習一下指針的相關知識點
我們在對雙鏈表初始化之后就可以來通過頭插法或者尾插法來創(chuàng)建一個雙鏈表了;
四、雙鏈表的創(chuàng)建
由于雙鏈表的結點結構與單鏈表的結點結構不同,因此我們在創(chuàng)建雙鏈表時的邏輯也是稍有區(qū)別的,如下圖所示:
由于多了一個前驅結點,這就導致我們在創(chuàng)建鏈表時通過頭插法在創(chuàng)建第一個表頭元素與創(chuàng)建其他的表頭元素的步驟稍有不同,如下所示;
用頭插法創(chuàng)建第一個表頭結點的步驟:
- 新結點的后繼指針指向頭結點的后繼指針指向的對象,即NULL;
- 新結點的前驅指針指向頭結點;
- 頭結點的后繼指針指向新結點;
用C語言來描述的話則是:
//頭插法創(chuàng)建第一個表頭結點的插入步驟
New_Node->next = Head->next;//新結點的后繼指針指向頭結點后繼指針指向的對象,即NULL
New_Node->prior = Head;//新結點的前驅指針指向頭結點
Head->next = New_Node;//頭結點的后繼指針指向新結點
- 注:這個插入順序要確保第3步的操作一定在第1步操作完后再執(zhí)行;第2步的操作順序可以隨意放置;
用頭插法創(chuàng)建第二個及以上的表頭結點的步驟:
- 新結點的后繼指針指向頭結點的后繼指針指向的對象,即表頭結點;
- 頭結點后繼指針指向對象的前驅結點指向新結點;
- 新結點的前驅指針指向頭結點;
- 頭結點的后繼指針指向新結點;
用C語言描述的話則是:
//頭插法創(chuàng)建第二個及以上的頭結點的插入步驟
New_Node->next = Head->next;//新結點的后繼指針指向頭結點后繼指針指向的對象,即NULL
Head->next->prior = New_Node;//頭指針的后繼指針指向對象的前驅指針指向新結點
New_Node->prior = Head;//新結點的前驅指針指向頭結點
Head->next = New_Node;//頭結點的后繼指針指向新結點
- 注:這個插入順序要確保第4步的操作一定在第1步與第2步操作完之后執(zhí)行;第3步操作的順序可以隨意放置;
接下來我們來看一下在這個邏輯下的雙鏈表的頭插法的基本格式:
//頭插法創(chuàng)建雙鏈表的基本格式
DLinkList DList_HeadInsert(DLinkList* L)
{
DNode* p;//指向新結點的指針
ElemType x = 0;//接收數(shù)據(jù)元素的變量
……;//獲取需要存儲的數(shù)據(jù)元素
while (x != EOF)//通過給循環(huán)設置結束條件來控制創(chuàng)建的結束
{
p = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(p);//當創(chuàng)建新結點失敗時,assert會對指針p進行報錯
if (!(*L)->next)//當頭結點的后繼指針指向空指針時
{
p->data = x;//將數(shù)據(jù)元素存儲到新結點的數(shù)據(jù)域中
p->next = (*L)->next;//新結點的后繼指針指向頭結點后繼指針指向的對象
p->prior = *L;//新結點的前驅指針指向頭結點
(*L)->next = p;//頭結點的后繼指針指向新結點
}
else
{
p->data = x;//將數(shù)據(jù)元素存儲到新結點的指針域中
p->next = (*L)->next;//新結點的后繼指針指向頭結點后繼指針指向的對象
(*L)->next->prior = p;//頭結點的后繼指針指向的對象的前驅指針指向新結點
p->prior = *L;//新結點的前驅指針指向頭結點
(*L)->next = p;//頭結點的后繼指針指向新結點
}
……;//獲取需要存儲的數(shù)據(jù)元素
}
return (*L);//創(chuàng)建好鏈表后返回頭指針
}
但是對于尾插法而言,不管是第一個結點還是最后一個結點的創(chuàng)建,在插入步驟上都是不影響的,因為表尾結點的后繼指針肯定是指向NULL的,因此通過尾插法創(chuàng)建的雙鏈表則不需要分情況討論,對應的尾插法創(chuàng)建格式如下所示:
//尾插法創(chuàng)建雙鏈表的基本格式
DLinkList DList_TailInsert(DLinkList* L)
{
DNode* r = *L;//指向表尾的指針
DNode* s;//指向新結點的指針
ElemType x = 0;//接收數(shù)據(jù)元素的變量
……;//獲取需要存儲的數(shù)據(jù)元素
while (x != EOF)//通過給循環(huán)設置結束條件來控制創(chuàng)建的結束
{
s = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(s);
s->data = x;//將數(shù)據(jù)元素存儲到新結點的數(shù)據(jù)域中
s->next = r->next;//新結點的后繼指針指向表尾結點的后繼指針,即NULL
s->prior = r;//新結點的前驅指針指向表尾結點
r->next = s;//表尾結點的后繼指針指向新結點
r = s;//表尾指針指向新結點
……;//獲取新的數(shù)據(jù)元素
}
return(*L);//當鏈表創(chuàng)建結束,返回頭指針
}
在創(chuàng)建好雙鏈表后,我們又該如何遍歷雙鏈表來訪問某個結點呢?
五、雙鏈表的遍歷
在給定一個結點后要想對單鏈表進行遍歷的話,我們只能從該結點往后遍歷,但是在雙鏈表中,我們既可以從給定結點開始往后遍歷,又可以從給定結點開始往前遍歷。遍歷的方式也很簡單,我們只需要將指向雙鏈表的指針往我們需要遍歷的方向進行移動就行,如下所示:
//給定結點指針p遍歷雙鏈表
while (p->next)//p的后繼結點不為空指針
{
p = p->next;//從結點p往后遍歷
}
while (p->prior)//p的前驅結點不為空指針
{
p = p->prior;//從結點p往前遍歷
}
想要對某一個結點進行想過操作時,我們就可以通過這個遍歷的方式來找到對應結點并執(zhí)行相關操作。
六、雙鏈表的查找
由于雙鏈表是與前驅結點以及后繼結點進行雙向鏈接的,因此我們在給定雙鏈表的一個結點后,不管是查找該結點的后繼結點還是前驅結點,對應的時間復雜度都為O(1);
在未給定結點的情況下,我們要想查找對應的結點,我們同樣可以通過按值查找與按位查找兩種查找方式來執(zhí)行,下面我們來看一下在雙鏈表中,這兩種查找方式的基本格式又是如何:
//雙鏈表的按位查找
DNode* GetElem(DLinkList L, int i)
{
if (i < 1)
return NULL;//當查找的位序不合理時返回空指針
DNode* p = L->next;//指向表頭結點的指針
int j = 1;//表頭結點的位序
while (p && j < i)//當查找結點為空指針時結束循環(huán);當查找結點的位序與目標位序相等時結束循環(huán)
{
p = p->next;//繼續(xù)往后遍歷
j++;
}
return p;//查找結束后返回指針p
}
如果是已知某一個結點的位序,需要查找另一個結點的位序,我們可以將函數(shù)的參數(shù)換成已知的結點以及需要查找的結點位序就行,這里就不再展開。下面我們來看一下按值查找的基本格式:
//雙鏈表的按位查找
DNode* LocateElem(DLinkList L, ElemType e)
{
DNode* p = L->next;//指向表頭結點的指針
while (p && p->data != e)//當查找結點為空指針時結束循環(huán)
//當查找結點的數(shù)據(jù)域存儲的元素與目標元素相等時結束循環(huán)
{
p = p->next;//繼續(xù)往后遍歷
}
return p;//查找結束后返回指針p
}
對于雙鏈表而言,在進行查找操作時對應的時間復雜度就有以下幾種情況:
- 如果是從表頭結點或者表尾結點開始進行查找的話,那對應的時間復雜度就是O(n);
- 如果是已知結點要查找對應的前驅結點或者后繼結點的話,那對應的時間復雜度就是O(1);
- 如果是已知某一結點,需要查找位序在該結點前面或者后面的結點的話,那對應的時間復雜度就是O(n);
七、雙鏈表的插入
雙鏈表的插入操作也是有前插與后插操作,前插操作的邏輯與單鏈表一致,都是通過在指點結點的后面插入一個新的結點,再對數(shù)據(jù)域中存儲的數(shù)據(jù)進行移動從而完成前插操作,下面我們先來看一下雙鏈表前插操作的基本格式:
//雙鏈表的前插操作
bool InsertPriorDNode(DNode* p, ElemType e)
{
assert(p);//指針p為空指針時報錯
DNode* q = p->prior;//指針p的前驅結點
assert(q);//指針q為空指針時報錯
DNode* s = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(s);//指針s為空指針時報錯
s->data = e;//將要插入的元素e放入新結點的數(shù)據(jù)域中
s->next = p;//將新結點的后繼指針指向進行前插操作的結點p
p->prior = s;//將結點p的前驅指針指向新結點s
q->next = s;//將前驅結點的后繼指針指向新結點s
s->prior = q;//將新結點的前驅指針執(zhí)行前驅結點q
return true;//完成前插操作后返回true
}
在雙鏈表中進行前插操作時,我們有幾點需要注意:
- 首先要確定該結點不是頭結點,也就是該結點的前驅結點不為空指:
- 當該結點為頭結點時,不能進行前插操作,此時給予一定的信息進行提示;
- 當該結點不為頭結點時,則可以正常進行前插操作;
- 因為雙鏈表結點的前驅指針直接指向的是前驅結點,因此我們不需要像單鏈表一樣調用函數(shù)來查找前驅結點;
- 在進行插入操作時,前驅結點的后繼指針執(zhí)行新結點的操作最好放在最后一步執(zhí)行;
下面我們來看一下雙鏈表的后插操作:
//雙鏈表的后插操作
bool InsertNextDNode(DNode* p, ElemType e)
{
assert(p);//指針p為空指針時報錯
DNode* s = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(s);//指針s為空指針時報錯
s->data = e;//將要插入的數(shù)據(jù)放入新結點的數(shù)據(jù)域中
if (p->next)//結點p的后繼結點不為空指針
{
s->next = p->next;//將新結點的后繼指針指向結點p的后繼結點
p->next->prior = s;//結點p的后繼結點的前驅指針執(zhí)行新結點
s->prior = p;//新結點的前驅指針指向結點p
p->next = s;//結點p的后繼指針指向新結點
}
else//結點p的后繼結點為空指針
{
s->next = p->next;//將新結點的后繼指針指向結點p的后繼結點
s->prior = p;//新結點的前驅指針指向結點p
p->next = s;//結點p的后繼指針指向新結點
}
return true;//完成后插操作后返回true
}
在雙鏈表中我們要執(zhí)行后插操作,我們也需要注意幾點:
- 要判斷當前結點的后繼結點是否為空指針,從而選擇插入操作的執(zhí)行步驟:
- 當前結點的后繼結點不為空指針時,需要將后繼結點的前驅指針的指向對象換成新結點;
- 當前結點的后繼結點為空指針時,只需要將新結點的后繼指針指向空指針就行
- 不管當前結點的后繼結點是否為空指針,我們最好都是將當前結點的后繼指針指向新結點的操作放在最后執(zhí)行;
對于雙鏈表而言,不管是前插操作還是后插操作,其對應的時間復雜度都是O(1),相比于單鏈表,雙鏈表的執(zhí)行效率會更高;
八、雙鏈表的刪除
如果我想刪除雙鏈表中的某個結點時,我們只需要按照以下步驟就能完成刪除操作:
- 將當前結點的前驅結點的后繼指針指向當前結點的后繼結點;
- 將當前結點的后繼結點的前驅指針指向當前結點的前驅結點;
- 釋放當前結點的空間;
將其轉換成C語言則是:
//雙鏈表的刪除操作
DNode->prior->next = DNode->next;//將前驅結點的后繼指針指向后繼結點
DNode->next->prior = DNode->prior;//將后繼結點的前驅指針指向前驅結點
free(DNode);//釋放當前結點的內存空間
如果是刪除的結點為表尾結點,則我們只需要將表尾結點的前驅結點指向空指針,然后直接釋放表尾結點的空間就行,轉換成C語言則是如下所示:
//刪除表尾結點
DNode->prior->next = NULL;//表尾結點的前驅結點的后繼指針指向空指針
DNode->prior->next = DNode->next;//前驅結點的后繼指針,指向后繼結點,即空指針
free(DNode);//釋放表尾結點的內存空間
刪除表尾結點時,第一句代碼與第二句代碼都是可以使用的,效果都一樣,二者選其一就行。下面我們將刪除操作封裝成一個函數(shù)的話,則對應的格式如下所示:
//雙鏈表的刪除操作
bool DeleteDNode(DNode* p)
{
assert(p);//指針p為空指針時報錯
DNode* q = p->prior;//p的前驅結點
assert(q);//當q為空指針時報錯
DNode* r = p->next;//p的后繼結點
if (r)//后繼結點不為空指針時
{
q->next = r;//前驅結點指向后繼結點
r->prior = q;//后繼結點指向前驅結點
free(p);//釋放結點p的內存
}
else
{
q->next = r;//前驅結點指向后繼結點,即空指針
free(p);//釋放結點p的內存
}
return true;//完成刪除操作后返回true
}
當對結點進行前刪或者后刪時,也是相同的邏輯,這不過在這個基礎上做一點小小的變動,這里我就不展開介紹了。當我們相對整個雙鏈表進行刪除時,我們只需要重復刪除表尾結點的操作即可,大家有興趣的話可以自己嘗試著編寫一下;
九、雙鏈表基本操作完整代碼展示
今天涉及到的代碼如下所示,需要的朋友可以自?。?/p>
//創(chuàng)建雙鏈表類型
typedef struct DNode {
int data;
struct DNode* prior, * next;
}DNode, * DLinkList;
//初始化雙鏈表
bool InitDLinkList(DLinkList* L)
{
*L = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建頭結點
assert(*L);//如果頭結點創(chuàng)建失敗,則報錯
(*L)->prior = NULL;//初始化前驅指針
(*L)->next = NULL;//初始化后繼指針
return true;
}
//尾插法創(chuàng)建雙鏈表
DLinkList DList_TailInsert(DLinkList* L)
{
DNode* r = *L;//指向表尾的指針
DNode* s;//指向新結點的指針
int x = 0;//接收數(shù)據(jù)元素的變量
while (scanf("%d", &x) == 1)//通過給循環(huán)設置結束條件來控制創(chuàng)建的結束
{
s = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(s);
s->data = x;//將數(shù)據(jù)元素存儲到新結點的數(shù)據(jù)域中
s->next = r->next;//新結點的后繼指針指向表尾結點的后繼指針,即NULL
s->prior = r;//新結點的前驅指針指向表尾結點
r->next = s;//表尾結點的后繼指針指向新結點
r = s;//表尾指針指向新結點
}
return(*L);//當鏈表創(chuàng)建結束,返回頭指針
}
//雙鏈表的按位查找
DNode* GetElem(DLinkList L, int i)
{
if (i < 1)
return NULL;//當查找的位序不合理時返回空指針
DNode* p = L->next;//指向表頭結點的指針
int j = 1;//表頭結點的位序
while (p && j < i)//當查找結點為空指針時結束循環(huán);當查找結點的位序與目標位序相等時結束循環(huán)
{
p = p->next;//繼續(xù)往后遍歷
j++;
}
return p;//查找結束后返回指針p
}
//雙鏈表的按值查找
DNode* LocateElem(DLinkList L, int e)
{
DNode* p = L->next;//指向表頭結點的指針
while (p && p->data != e)//當查找結點為空指針時結束循環(huán);當查找結點的數(shù)據(jù)域存儲的元素與目標元素相等時結束循環(huán)
{
p = p->next;//繼續(xù)往后遍歷
}
return p;//查找結束后返回指針p
}
//雙鏈表的前插操作
bool InsertPriorDNode(DNode* p, int e)
{
assert(p);//指針p為空指針時報錯
DNode* q = p->prior;//指針p的前驅結點
assert(q);//指針q為空指針時報錯
DNode* s = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(s);//指針s為空指針時報錯
s->data = e;//將要插入的元素e放入新結點的數(shù)據(jù)域中
s->next = p;//將新結點的后繼指針指向進行前插操作的結點p
p->prior = s;//將結點p的前驅指針指向新結點s
q->next = s;//將前驅結點的后繼指針指向新結點s
s->prior = q;//將新結點的前驅指針執(zhí)行前驅結點q
return true;//完成前插操作后返回true
}
//雙鏈表的后插操作
bool InsertNextDNode(DNode* p, int e)
{
assert(p);//指針p為空指針時報錯
DNode* s = (DNode*)calloc(1, sizeof(DNode));//創(chuàng)建新結點
assert(s);//指針s為空指針時報錯
s->data = e;//將要插入的數(shù)據(jù)放入新結點的數(shù)據(jù)域中
if (p->next)//結點p的后繼結點不為空指針
{
s->next = p->next;//將新結點的后繼指針指向結點p的后繼結點
p->next->prior = s;//結點p的后繼結點的前驅指針執(zhí)行新結點
s->prior = p;//新結點的前驅指針指向結點p
p->next = s;//結點p的后繼指針指向新結點
}
else//結點p的后繼結點為空指針
{
s->next = p->next;//將新結點的后繼指針指向結點p的后繼結點
s->prior = p;//新結點的前驅指針指向結點p
p->next = s;//結點p的后繼指針指向新結點
}
return true;//完成后插操作后返回true
}
//雙鏈表的刪除操作
bool DeleteDNode(DNode* p)
{
assert(p);//指針p為空指針時報錯
DNode* q = p->prior;//p的前驅結點
assert(q);//當q為空指針時報錯
DNode* r = p->next;//p的后繼結點
if (r)//后繼結點不為空指針時
{
q->next = r;//前驅結點指向后繼結點
r->prior = q;//后繼結點指向前驅結點
free(p);//釋放結點p的內存
}
else
{
q->next = r;//前驅結點指向后繼結點,即空指針
free(p);//釋放結點p的內存
}
return true;//完成刪除操作后返回true
}
//打印雙鏈表
void Print_DLinkList(DLinkList L)
{
printf("打印雙鏈表:>");
DNode* p = L->next;
for (p; p; p = p->next)
printf("%d ", p->data);
printf("\n");
}
int main()
{
DLinkList L;//定義指向雙鏈表的頭指針
InitDLinkList(&L);//初始化雙鏈表
DList_TailInsert(&L);//尾插法創(chuàng)建雙鏈表
Print_DLinkList(L);//打印雙鏈表
DNode* p = GetElem(L, 3);//按位查找
if (p)
{
printf("\n找到位序為%d的結點p了,該結點的地址為%p\n", 3, p);
}
if(InsertPriorDNode(p, 2))
{
printf("成功在結點p前插入了一個存放%d的新結點\n", 2);
Print_DLinkList(L);//打印雙鏈表
}
DNode* p2 = LocateElem(L, 5);//按值查找
if (p2)
{
printf("\n找到存放%d的結點p2了,該結點的地址為%p\n", 5, p2);
}
if (InsertNextDNode(p2, 6))
{
printf("成功在結點p后插入了一個存放%d的新結點\n", 6);
Print_DLinkList(L);//打印雙鏈表
}
if (DeleteDNode(p2))
{
printf("\n成功刪除了結點p2\n");
Print_DLinkList(L);//打印雙鏈表
}
return 0;
}
結語
雙鏈表的內容到這里咱們就全部介紹完了,在今天的篇章中,咱們詳細介紹了雙鏈表的創(chuàng)建、初始化、查找、插入、刪除等基本操作,并給大家附上了對應操作的代碼。希望今天的內容能夠幫助大家更好的理解雙鏈表及其基本操作。文章來源:http://www.zghlxwxcb.cn/news/detail-767460.html
在下一篇內容中,咱們將介紹循環(huán)鏈表以及靜態(tài)鏈表的相關內容,大家記得關注哦!?。∽詈蟾兄x各位的翻閱,咱們下一篇再見!文章來源地址http://www.zghlxwxcb.cn/news/detail-767460.html
到了這里,關于【數(shù)據(jù)結構】C語言實現(xiàn)雙鏈表的基本操作的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!