第一次嘗試
//這是 .h 部分的**
#pragma once
//使用這種方式來重新命名資料型別,這樣可以很方便的修改後續資料的資料型別,相當於#define的作用
typedef
int listtype;
//建立資料結點
typedef
struct listnode listnode;
//建立頭結點
typedef
struct listhead listhead;
//包含所有函式的宣告
//雙向鍊錶初始化
void
listinit
(listhead* list)
;//動態申請乙個節點
listnode*
buylistnode
(listtype val)
;//雙向鍊錶列印
void
listprint
(listhead* list)
;//雙向鍊錶尾插
void
listpushback
(listhead* list, listtype val)
;//雙向鍊錶尾刪
void
listpopback
(listhead* list)
;//雙向煉表頭插
void
listpushfront
(listhead* list, listtype val)
;//雙向煉表頭刪
void
listpopfront
(listhead* list)
;//雙向鍊錶在pos位置插入x
void
listinsert
(listnode* pos, listtype val)
;//雙向鍊錶刪除pos位置的值
void
listerase
(listnode* pos)
;//雙向鍊錶查詢
listnode*
slistfind
(listhead* list, listtype val)
;//雙向鍊錶的大小
intlistsize
(listhead* list)
;//雙向鍊錶的銷毀
void
listdestory
(listhead* list)
;
//這是 .c 部分的**
#include
#include
#include
"list.h"
//雙向鍊錶初始化
void
listinit
(listhead* list)
//注意,雙向鍊錶的空表其實是有乙個節點的,它的_next、_prev都指向自己,這個節點沒任何實際意義,只是為了方便操作鍊錶
list->_head =
buylistnode(0
);list->_head->_next = list->_head->_prev = list->_head;
}//動態申請乙個節點
listnode*
buylistnode
(listtype val)
return
null;}
//雙向鍊錶列印
void
listprint
(listhead* list)
//讓迴圈從第乙個有效結點開始
listnode* node = list->_head->_next;
//當結點再次返回到頭結點時,則迴圈結束
while
(node != list->_head)
printf
("\n");
}//雙向鍊錶尾插
void
listpushback
(listhead* list, listtype val)
//修改四個指標的指向
listnode* tail = list->_head->_prev;
listnode* newnode =
buylistnode
(val)
;//原煉表尾節點的_next指向新建立節點
tail->_next = newnode;
//新建立結點的_prev指向原煉表尾結點
newnode->_prev = tail;
//新建立結點的_next指向頭結點
newnode->_next = list->_head;
//頭結點的_prev指向新建立結點
list->_head->_prev = newnode;
//**復用,我們可以直接呼叫在任意位置插入函式
//listinsert(list->_head, val);
}//雙向鍊錶尾刪
void
listpopback
(listhead* list)
listnode* tail = list->_head->_prev;
listnode* taillast = tail->_prev;
//釋放最後乙個結點
free
(tail)
;//倒數第二個結點的_next指向頭結點
taillast->_next = list->_head;
//頭結點的_prev指向倒數第二個結點
list->_head->_prev = taillast;
//**復用,我們可以直接呼叫在任意位置刪除函式
//listerase(list->_head->_prev);
}//雙向煉表頭插
void
listpushfront
(listhead* list, listtype val)
//修改四個指標的指向
listnode* next = list->_head->_next;
listnode* node =
buylistnode
(val)
; list->_head->_next = node;
node->_prev = list->_head;
node->_next = next;
next->_prev = node;
//**復用,我們可以直接呼叫在任意位置插入函式
//listinsert(list->_head->_next, val);
}//雙向煉表頭刪
void
listpopfront
(listhead* list)
listnode* node = list->_head->_next;
listnode* next = node->_next;
//釋放結點
free
(node)
;//修改指標指向
list->_head->_next = next;
next->_prev = list->_head;
//**復用,我們可以直接呼叫在任意位置插入函式
//listerase(list->_head->_next);
}//雙向鍊錶在pos位置插入x
void
listinsert
(listnode* pos, listtype val)
//雙向鍊錶刪除pos位置的值
void
listerase
(listnode* pos)
//雙向鍊錶查詢
listnode*
slistfind
(listhead* list, listtype val)
listnode* node = list->_head->_next;
while
(node != list->_head)
node = node->_next;}}
//雙向鍊錶的大小
intlistsize
(listhead* list)
listnode* node = list->_head->_next;
int size =0;
while
(node != list->_head)
return size;
}//雙向鍊錶的銷毀
void
listdestory
(listhead* list)
//讓尾結點指向null
list->_head->_prev->_next =
null
; listnode* node = list->_head;
//頭指標指向null
list->_head =
null
;//從頭結點開始刪除,直到null
while
(node)
}int
main()
return0;
}
這是雙向鍊錶的建立**,此雙向鍊錶是帶頭結點、雙向向、迴圈的鍊錶,對鍊錶的每乙個功能進行了介面實現,封裝成函式,方便使用者使用;其中的頭尾插/刪,可以利用在任意位置插/刪**代替,提高復用性;
前面單鏈表的建立中,由於鍊錶結構的侷限性,不能實現在任意位置插/刪,而在雙向鍊錶中,因為有 _prev 指標的存在,這一點得到了很好地實現;另外需要注意的是,空的雙向鍊錶是存在乙個頭結點的,它的 _next 和 _prev 都是指向他自己本身,在鍊錶實現的時候要注意這點。
發表於 2020-12-16 15:15
鍊錶 帶頭結點的雙向迴圈鍊錶
還需改進 creat node這個函式應有返回型別,來判斷新建結點是否成功,不然主函式中不管成不成功都會訪問該節點成員。改了這個函式,在主函式中create node後要判斷是否成功,不成功就提示並退出函式,退出前別忘了還要釋放鍊錶!同時create link這個函式中也要判斷head是否申請成功,...
C 實現雙向迴圈鍊錶(帶頭結點)
雙向鍊錶也叫雙鏈表,是鍊錶的一種,它的每個資料結點中都有兩個指標,分別指向直接後繼和直接前驅。所以,從雙向鍊錶中的任意乙個結點開始,都可以很方便地訪問它的前驅結點和後繼結點。一般我們都構造雙向迴圈鍊錶。簡單的畫乙個雙向迴圈簡易圖 下面就用c 實現一下基本操作 當然也有 c 語言 版的,只是單鏈表操作...
建立鍊錶(帶頭 單向 不迴圈)
第一次嘗試 這是 h 部分的 pragma once 使用這種方式來重新命名資料型別,這樣可以很方便的修改後續資料的資料型別,相當於 define的作用 typedef int listtype 建立資料節點 typedef struct listnode listnode 建立頭結點 typede...