zoukankan      html  css  js  c++  java
  • 链表 头插法 尾插法 为什么要有头结点

    学过链表的应该都知道向链表中插入元素存在两种插入方式:

    头插法:数据插入链表后,作为链表的第一个元素;
    尾插法:数据插入链表后,作为链表的最后一个元素;

    本篇博客的重点在于为什么要有头结点
    关于头结点和头指针的概念,请参考关于链表中头指针和头结点的理解

    为什么要有头结点,在网上找了半天,解释是"为了统一插入和删除对第一个结点和对其他结点的操作"
    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	",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的情况,不会有上述的特殊考虑,对第一个元素的操作和对其他元素的操作统一;

  • 相关阅读:
    [笔记].Cyclone III编程与配置的几个问题解答
    [笔记].活用Quartus II内置模板,快速输入HDL代码、TimeQuset约束及tcl语句等
    [笔记].关于在Quartus II 11.0无法正常使用SignalTap的解决方法
    [Altera在线教学].tcl介绍 与 Quartus II tcl脚本
    [笔记].关于使用Nios II Flash Programmer下载后无法从EPCS启动的一种解决方法;sof+elf>flash>hex>jic
    [笔记].菜农M0助学板之GPIO按键之边沿检测小练(寄存器操作方式)
    [笔记].QII 11.1文本编辑器,新增了“Autocomplete text”功能
    [问答].Nios II、MIPS、Microblaze、ARM这几个嵌入FPGA中的硬核,哪个运用广、前景好?
    [Altera在线教学].IP复用及其实现方法
    [资料].Altera FPGA/CPLD Allegro原理图库
  • 原文地址:https://www.cnblogs.com/jamesvoid/p/9919116.html
Copyright © 2011-2022 走看看