●
不带头节点:此时头指针指向第一个节点
h->a1->a2->a3->…… // 头指针存放的是第一个节点的地址,即h,也就是说(*h)表示的是第一个节点
带头结点:此时头指针指向头结点
h->headnode->a1->a2->a3->…… // 头指针存放的是头结点的地址,也就是说(*h)表示的是头结点
//初始化链表 Node* initList() { Node *head = (Node*)malloc(sizeof(Node)); head->next = NULL; //此时 head 表示的就是头指针,之中存放的就是头结点的地址, return head; //所以 head->next 表示的为头结点的下一个节点,也就是首元节点。 }
● 空表的比较
//不带头节点 h = NULL; // h 表示的是第一个节点的地址,h = NULL 表示第一个节点的地址为空,也就是空表 // 带头结点 h->next = NULL; // h 表示的是头结点的地址,h->next 就是头结点的下一个节点,即首元节点为空,也就是空表
● 添加第一个节点的区别
Node *newnode = (Node*)malloc(sizeof(Node));
//带头结点 newnode->next = h-> next; h->next = newnode; //不带头结点 newnode->next = h ; h = newnode ;
●反思:常在网上看到,不带头结点的方式比带头结点的方式在处理第一个节点的时候会繁琐一点,举个例子。
typedef struct Node { ListTpye data; struct Node *next; }Node, *LinkList; //添加节点(头插法) int add(LinkList *h, int data) { if ((*h) == NULL) return 0; Node *node = (Node*)malloc(sizeof(Node)); node->data = data; node->next = *h; (*h) = node; return 1; }
从此可以看出不带带节点的好处了,不带头节点时,使用头插法插入节点时我们要不停更改头指针,让他指向新节点,并且传入的值是头指针的指针,很容易混淆。
总结:总的来说,就是带头结点时不管是否为空表,头指针的值都不会变化,都指向头结点。而不带头结点则需要根据不同情况来修改头指针的值。所以操作不统一,有所不便,所以绝大数时候使用带头结点的方式较为方便。