其實鏈表很簡單,跟着我的腳步走,基本是這篇博客看完,你也就能實現簡單的鏈表操作了
數組、鏈表是最常見的重要的數據結構,所以掌握鏈表也是很重要的咯。
一般鏈表的操作無外乎增刪改查。 今天就簡單的實現一下雙向循環鏈表的增刪
1. 鏈表的數據結構,主要包含指針域和數據域
雙向循環鏈表的數據結構包含至少兩個指針和至少一個數據
//用結構體封裝一下鏈表的數據結構
typedef struct _node_t{
struct _node_t *prev; //上一個節點
struct _node_t *next; //下一個節點
uint8_t data; //數據域
}Node,*pNode;
2.鏈表的初始化,即創建一個頭結點
頭結點的prev或next都是其本身,一般建議頭節點只存指針。
//鏈表初始化,即創建一個頭結點
pNode linklist_init(void){
pNode head = (pNode)malloc(sizeof(Node)); //申請內存
if(NULL == head){
perror("malloc Node failed!");
}
head->prev = head; //頭節點的prev指向本身
head->next = head; //頭節點的next指向本身
return head;
}
3.鏈表的插入
在前面插入,即在頭結點之後插入:
來來來,排隊了,,新來了一個童鞋tmp,個子比較矮的,老師讓他站在排頭的後面;
新來的tmp看了一下前面是排頭(head),後面是某某(head->next),然後他記住了自己的位置,通過自己前面和後面的童鞋定位了自己的位置;
可是還不夠啊,排頭和之前在排頭後面的童鞋不知道啊,所以之前排頭後面的童鞋,重新定位了一下自己的位置(head->next->prev)我原來在排頭後面,但是現在我前面是誰?排頭後面的換了,排頭也定位了一下自己的位置(head->next) 我後面新來的是誰呀。
pNode linklist_addhead(pNode head, uint8_t dat){
pNode tmp = (pNode)malloc(sizeof(Node)); //申請內存
if(tmp == head){
perror("malloc Node failed!");
}
tmp->prev = head; //tmp定位自己,看下前面是誰
tmp->next = head->next; //再看看後面是誰
head->next->prev = tmp; //原來在排頭後面的童鞋,看看現在自己前面的是誰
head->next = tmp; //排頭也看了下,現在自己後面的是誰
tmp->data = dat; //新來的童鞋的名字
return head; //排頭的位置不能丟,不然找不到這一隊人馬了
}
在末尾插入
這裏就不再贅述了,直接上圖,看不懂的,看上圖及描述
pNode linklist_addtail(pNode head, uint8_t dat){
pNode tmp = (pNode)malloc(sizeof(Node));
if(tmp == head){
perror("malloc Node failed!");
}
tmp->prev = head->prev; //tmp看下自己前面是誰,主要前面是排頭ing,因爲是環形的鏈表
tmp->next = head; //tmp看下自己後面的是誰
head->prev->next = tmp; //原來排頭前面的童鞋的後面是誰,來新人tmp了
head->prev = tmp; //現在排頭前面的換成了tmp了
tmp->data = dat;
return head;
}
還有其他插入方法,但是隻要掌握了頭插尾插,其他的都是浮雲
3.鏈表的刪除
從頭刪除,即將排頭後面的tmp童鞋刪除
先告訴tmp童鞋後面的童鞋(tmp->next),我走了之後你前面的是誰;然後告訴tmp童鞋前面的童鞋(這裏head),我走了之後你後面的是誰;把前後兩個童鞋定位告訴他們後就可以離開了(free);
pNode Linklist_delhead(pNode head){
pNode tmp = head->next;
if(tmp == head){
perror("linklist empty!");
return head;
}
tmp->next->prev = head; //tmp走了,tmp童鞋後面的童鞋的前面變成了排頭
head->next = tmp->next; //tmp走了,排頭後面的童鞋變成了原來排在tmp童鞋後面的童鞋
tmp->next = NULL;
tmp->prev = NULL;
free(tmp); //釋放內存
}
從尾部刪除
這裏就不再贅述了,直接上圖,看不懂的,看上圖及描述
pNode Linklist_deltail(pNode head){
pNode tmp = head->prev;
if(tmp == head){
perror("linklist empty!");
return head;
}
tmp->prev->next = head;
head->prev = tmp->prev;
tmp->next = NULL;
tmp->prev = NULL;
free(tmp);
}
4. 遍歷顯示鏈表
從排頭依次報數,輪流一圈,回到排頭就完成了
void linklist_show(pNode head){
tmp = head->next; //從排頭後面的童鞋開始遍歷
while(tmp != head){ //沒有遍歷到排頭
printf("%p:%d\n",tmp, tmp->data);
tmp = tmp->next; //指向下一個童鞋
}
}
5. 測試
int main(void){
pNode head = linklist_init();
printf("\nhead add Node!\n");
for(uint8_t i=0;i<5;i++){
linklist_addhead(head, i);
}
linklist_show(head);
printf("\nhead del!\n");
for(uint8_t i=0;i<2;i++){
Linklist_delhead(head);
}
linklist_show(head);
printf("\ntail_del!\n");
for(uint8_t i=0;i<2;i++){
Linklist_deltail(head);
}
linklist_show(head);
printf("\ntail add Node!\n");
for(uint8_t i=0;i<5;i++){
linklist_addtail(head, i);
}
linklist_show(head);
printf("\ntail del Node!\n");
Linklist_deltail(head);
linklist_show(head);
printf("\nhead del Node!\n");
Linklist_delhead(head);
linklist_show(head);
return 0;
}
運行結果