柚子快報邀請碼778899分享:數(shù)據(jù)結(jié)構(gòu)--雙向鏈表
柚子快報邀請碼778899分享:數(shù)據(jù)結(jié)構(gòu)--雙向鏈表
目錄
一.鏈表的分類
二.雙向鏈表的結(jié)構(gòu)
?三.雙向鏈表的實現(xiàn)
1.初始化
2.尾插與頭插
3.尾刪與頭刪
4.在指定位置之后插入數(shù)據(jù)
查找函數(shù)
5.刪除指定節(jié)點
6,銷毀鏈表
?四.完整代碼
List.h
List.c
一.鏈表的分類
鏈表的結(jié)構(gòu)?常多樣,以下情況組合起來就有8種(2 x 2 x 2)鏈表結(jié)構(gòu):
前面的單鏈表應(yīng)該叫不帶頭單向不循環(huán)鏈表,前面的單鏈表章節(jié)提到的頭節(jié)點只是為了方便理解,并不是真正的頭節(jié)點。數(shù)據(jù)結(jié)構(gòu)--鏈表-CSDN博客
1. ?頭單向?循環(huán)鏈表:結(jié)構(gòu)簡單,?般不會單獨?來存數(shù)據(jù)。實際中更多是作為其他數(shù)據(jù)結(jié)構(gòu)的?結(jié)構(gòu),如哈希桶、圖的鄰接表等等。
2. 帶頭雙向循環(huán)鏈表:結(jié)構(gòu)最復(fù)雜,?般?在單獨存儲數(shù)據(jù)。實際中使?的鏈表數(shù)據(jù)結(jié)構(gòu),都是帶頭雙向循環(huán)鏈表。另外這個結(jié)構(gòu)雖然結(jié)構(gòu)復(fù)雜,但是使?代碼實現(xiàn)以后會發(fā)現(xiàn)結(jié)構(gòu)會帶來很多優(yōu)勢,實現(xiàn)反?簡單了
二.雙向鏈表的結(jié)構(gòu)
帶頭鏈表?的頭節(jié)點,實際為“哨兵位”,哨兵位節(jié)點不存儲任何有效元素,只是站在這?“放哨的”
“哨兵位”存在的意義:
遍歷循環(huán)鏈表避免死循環(huán)。
?三.雙向鏈表的實現(xiàn)
test.c//測試文件
List.c//實現(xiàn)雙向鏈表的方法
List.h//雙向鏈表聲明
1.初始化
?雙向鏈表由節(jié)點組成
數(shù)據(jù)指向下一個節(jié)點的指針指向前應(yīng)該節(jié)點的指針
typedef int LTDataType;
//定義雙向鏈表節(jié)點的結(jié)構(gòu)
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
插入數(shù)據(jù)之前,鏈表必須初始化到只有一個頭結(jié)點的情況
//申請節(jié)點
LTNode* LTBuyNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail!");
exit(1);
}
node->data = x;
node->next = node->prev = node;
return node;
}
//初始化
LTNode* LTInit()
{
//給雙向鏈表創(chuàng)建一個哨兵位
LTNode* phead = LTBuyNode(-1);
return phead;
}
//打印鏈表
void LTPrint(LTNode* phead)
{
LTNode* pcur = phead->next;
while (pcur != phead)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("\n");
}
2.尾插與頭插
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
//phead phead->prev newnode
newnode->prev = phead->prev;
newnode->next = phead;
phead->prev->next = newnode;
phead->prev = newnode;
}
//頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
//phead newnode phead->next
newnode->next = phead->next;
newnode->prev = phead;
phead->next->prev = newnode;
phead->next = newnode;
}
3.尾刪與頭刪
void LTPopBack(LTNode* phead)
{
//鏈表必須有效且鏈表不能為空(只有一個哨兵位)
assert(phead && phead->next != phead);
LTNode* del = phead->prev;
//phead del->prev del
del->prev->next = phead;
phead->prev = del->prev;
//刪除del節(jié)點
free(del);
del = NULL;
}
//頭刪
void LTPopFront(LTNode* phead)
{
assert(phead && phead->next != phead);
LTNode* del = phead->next;
//phead del del->next
phead->next = del->next;
del->next->prev = phead;
//刪除del節(jié)點
free(del);
del = NULL;
}
4.在指定位置之后插入數(shù)據(jù)
查找函數(shù)
LTNode* LTFind(LTNode* phead, LTDataType x)
{
LTNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
//沒有找到
return NULL;
}
//在pos位置之后插入數(shù)據(jù)
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
//pos newnode pos->next
newnode->next = pos->next;
newnode->prev = pos;
pos->next->prev = newnode;
pos->next = newnode;
}
5.刪除指定節(jié)點
//刪除pos節(jié)點
void LTErase(LTNode* pos)
{
//pos理論上來說不能為phead,但是沒有參數(shù)phead,無法增加校驗
assert(pos);
//pos->prev pos pos->next
pos->next->prev = pos->prev;
pos->prev->next = pos->next;
free(pos);
pos = NULL;
}
6,銷毀鏈表
void LTDesTroy(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
LTNode* next = pcur->next;
free(pcur);
pcur = next;
}
//此時pcur指向phead,而phead還沒有被銷毀
free(phead);
phead = NULL;
}
?四.完整代碼
List.h
#pragma once
#include
#include
#include
typedef int LTDataType;
//定義雙向鏈表節(jié)點的結(jié)構(gòu)
typedef struct ListNode
{
LTDataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
//聲明雙向鏈表中提供的方法
//初始化
//void LTInit(LTNode** pphead);
LTNode* LTInit();
void LTDesTroy(LTNode* phead);
void LTPrint(LTNode* phead);
//插入數(shù)據(jù)之前,鏈表必須初始化到只有一個頭結(jié)點的情況
//不改變哨兵位的地址,因此傳一級即可
//尾插
void LTPushBack(LTNode* phead, LTDataType x);
//頭插
void LTPushFront(LTNode* phead, LTDataType x);
//尾刪
void LTPopBack(LTNode* phead);
//頭刪
void LTPopFront(LTNode* phead);
//在pos位置之后插入數(shù)據(jù)
void LTInsert(LTNode* pos, LTDataType x);
//刪除pos節(jié)點
void LTErase(LTNode* pos);
LTNode* LTFind(LTNode* phead, LTDataType x);
List.c
#include"List.h"
void LTPrint(LTNode* phead)
{
LTNode* pcur = phead->next;
while (pcur != phead)
{
printf("%d->", pcur->data);
pcur = pcur->next;
}
printf("\n");
}
//申請節(jié)點
LTNode* LTBuyNode(LTDataType x)
{
LTNode* node = (LTNode*)malloc(sizeof(LTNode));
if (node == NULL)
{
perror("malloc fail!");
exit(1);
}
node->data = x;
node->next = node->prev = node;
return node;
}
//初始化
//void LTInit(LTNode** pphead)
//{
// //給雙向鏈表創(chuàng)建一個哨兵位
// *pphead = LTBuyNode(-1);
//}
LTNode* LTInit()
{
LTNode* phead = LTBuyNode(-1);
return phead;
}
//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
//phead phead->prev newnode
newnode->prev = phead->prev;
newnode->next = phead;
phead->prev->next = newnode;
phead->prev = newnode;
}
//頭插
void LTPushFront(LTNode* phead, LTDataType x)
{
assert(phead);
LTNode* newnode = LTBuyNode(x);
//phead newnode phead->next
newnode->next = phead->next;
newnode->prev = phead;
phead->next->prev = newnode;
phead->next = newnode;
}
//尾刪
void LTPopBack(LTNode* phead)
{
//鏈表必須有效且鏈表不能為空(只有一個哨兵位)
assert(phead && phead->next != phead);
LTNode* del = phead->prev;
//phead del->prev del
del->prev->next = phead;
phead->prev = del->prev;
//刪除del節(jié)點
free(del);
del = NULL;
}
//頭刪
void LTPopFront(LTNode* phead)
{
assert(phead && phead->next != phead);
LTNode* del = phead->next;
//phead del del->next
phead->next = del->next;
del->next->prev = phead;
//刪除del節(jié)點
free(del);
del = NULL;
}
LTNode* LTFind(LTNode* phead, LTDataType x)
{
LTNode* pcur = phead->next;
while (pcur != phead)
{
if (pcur->data == x)
{
return pcur;
}
pcur = pcur->next;
}
//沒有找到
return NULL;
}
//在pos位置之后插入數(shù)據(jù)
void LTInsert(LTNode* pos, LTDataType x)
{
assert(pos);
LTNode* newnode = LTBuyNode(x);
//pos newnode pos->next
newnode->next = pos->next;
newnode->prev = pos;
pos->next->prev = newnode;
pos->next = newnode;
}
//刪除pos節(jié)點
void LTErase(LTNode* pos)
{
//pos理論上來說不能為phead,但是沒有參數(shù)phead,無法增加校驗
assert(pos);
//pos->prev pos pos->next
pos->next->prev = pos->prev;
pos->prev->next = pos->next;
free(pos);
pos = NULL;
}
void LTDesTroy(LTNode* phead)
{
assert(phead);
LTNode* pcur = phead->next;
while (pcur != phead)
{
LTNode* next = pcur->next;
free(pcur);
pcur = next;
}
//此時pcur指向phead,而phead還沒有被銷毀
free(phead);
phead = NULL;
}
柚子快報邀請碼778899分享:數(shù)據(jù)結(jié)構(gòu)--雙向鏈表
參考鏈接
本文內(nèi)容根據(jù)網(wǎng)絡(luò)資料整理,出于傳遞更多信息之目的,不代表金鑰匙跨境贊同其觀點和立場。
轉(zhuǎn)載請注明,如有侵權(quán),聯(lián)系刪除。