鏈表 頭插法 尾插法 為什么要有頭結點


學過鏈表的應該都知道向鏈表中插入元素存在兩種插入方式:

頭插法:數據插入鏈表后,作為鏈表的第一個元素;
尾插法:數據插入鏈表后,作為鏈表的最后一個元素;

本篇博客的重點在於為什么要有頭結點
關於頭結點和頭指針的概念,請參考關於鏈表中頭指針和頭結點的理解

為什么要有頭結點,在網上找了半天,解釋是"為了統一插入和刪除對第一個結點和對其他結點的操作"
but how,這一點沒有完整且直觀的代碼解釋,在這一點上,我之前的理解並不是很清晰,這里通過代碼來驗證一下:
talk is cheap,show me the code

#include<stdio.h>
#include<stdlib.h>

struct Node
{
    int data;
    struct Node *next;
}Node;

typedef struct LinkedList
{
    struct Node *head; // 頭指針
}LinkedList;

// 無頭結點初始化
void Init_List(LinkedList *list)
{
    list->head = NULL;
}

// 有頭結點初始化
void Init_List_With_Head_Node(LinkedList *list)
{
    struct Node *node = (struct Node*)malloc(sizeof(struct Node));
    node->next = NULL;
    list->head = node;
}

// 有頭結點頭插法插入數據
void Head_Insert_List(LinkedList *list,int data)
{
    struct Node *node = (struct Node*)malloc(sizeof(struct Node));
    node->data = data;
    node->next = list->head;
    list->head = node;
}

// 有頭結點尾插法插入數據
void Tail_Insert_List(LinkedList *list,int data)
{
    struct Node *node = (struct Node*)malloc(sizeof(struct Node));
    struct Node *tmp = list->head;

    node->data = data;
    node->next = NULL;

    if(tmp)
    {
        // 走到尾部
        while(tmp->next)
        {
            tmp = tmp->next;
        }
        tmp->next = node;
    }
    else
    {
        // head為 NULL
        list->head = node;
    }
}

// 有頭結點頭插法插入數據
void Head_Insert_List_With_Head_Node(LinkedList *list,int data)
{
    struct Node *node = (struct Node*)malloc(sizeof(struct Node));
    node->data = data;
    node->next = list->head->next;
    list->head->next = node;
}

// 有頭結點尾插法插入數據
void Tail_Insert_List_With_Head_Node(LinkedList *list,int data)
{
    struct Node *node = (struct Node*)malloc(sizeof(struct Node));
    struct Node *tmp = list->head;

    node->data = data;
    node->next = NULL;

    // 走到尾部
    while(tmp->next)
    {
        tmp = tmp->next;
    }
    
    tmp->next = node;
}

void print_list(LinkedList *list)
{
    int i;
    struct Node *tmp = list->head;
    while(tmp)
    {
        printf("%d\t",tmp->data);
        tmp = tmp->next;
    }
    puts("");
}

int main()
{
    LinkedList list;

    puts("無頭結點:");
    Init_List(&list);

    puts("頭插法");
    Head_Insert_List(&list,1);
    Head_Insert_List(&list,2);
    Head_Insert_List(&list,3);
    print_list(&list);

    puts("尾插法");
    Init_List(&list);
    Tail_Insert_List(&list,1);
    Tail_Insert_List(&list,2);
    Tail_Insert_List(&list,3);
    print_list(&list);

    puts("有頭結點:");
    Init_List_With_Head_Node(&list);

    puts("頭插法");
    Head_Insert_List_With_Head_Node(&list,1);
    Head_Insert_List_With_Head_Node(&list,2);
    Head_Insert_List_With_Head_Node(&list,3);
    print_list(&list);

    puts("尾插法");
    Init_List_With_Head_Node(&list);
    Tail_Insert_List_With_Head_Node(&list,1);
    Tail_Insert_List_With_Head_Node(&list,2);
    Tail_Insert_List_With_Head_Node(&list,3);
    print_list(&list);

    return 0;
}

上面的執行結果為:
運行結果

上面紅圈圈處的數字是因為沒有對頭結點的數據進行初始化,內存中的垃圾數字.

從上面可以看出:
不帶頭結點的鏈表,因為頭指針指向第一個元素結點:

  1. 尾插法添加元素時,需要判斷當前鏈表是否是沒有元素,如果沒有元素,則需要更新頭指針指向當前添加的這個元素;
  2. 刪除元素時,需要判斷刪除的元素是否為第一個元素,如果是第一個元素,需要更新頭指針指向下一個元素;

帶頭結點的鏈表
因為頭指針指向這個頭結點,不會出現頭指針為NULL的情況,不會有上述的特殊考慮,對第一個元素的操作和對其他元素的操作統一;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM