1. 程式人生 > >C語言實現簡單的雙向迴圈連結串列

C語言實現簡單的雙向迴圈連結串列

其實連結串列很簡單,跟著我的腳步走,基本是這篇部落格看完,你也就能實現簡單的連結串列操作了

陣列、連結串列是最常見的重要的資料結構,所以掌握連結串列也是很重要的咯。
一般連結串列的操作無外乎增刪改查。 今天就簡單的實現一下雙向迴圈連結串列的增刪

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;
}

執行結果
在這裡插入圖片描述