头结点和头指针
线性表使用顺序(数组)存储时有个弊端,那就是在插入和删除时需要大量的移动数据,这显示是非常消耗时间的,所以可以采用链式存储,即有一个指针域(单链表),来记录下个结点的存储位置(地址),这样在插入和删除结点时只需要修改指针域即可,从而大量减少移动数据所消耗的时间。来看链表的定义:
struct node { int data; struct node *next; };
其中有两个元素,data为数据域,用于存储数据,next为指针域,用于存储下个结点的位置(地址)。那么什么是头指针呢?我们把指向第一个结点的指针称为头指针,那么每次访问链表时都可以从这个头指针依次遍历链表中的每个元素,例如:
struct node first; struct node *head = &first;
这个head指针就是头指针。
这个头指针的意义在于,在访问链表时,总要知道链表存储在什么位置(从何处开始访问),由于链表的特性(next指针),知道了头指针,那么整个链表的元素都能够被访问,也就是说头指针是必须存在的。示例如下:
#include <stdio.h> struct node { int data; struct node *next; }; int main(void) { struct node *head, first, second; head = &first; first.data = 1; first.next = &second; second.data = 2; second.next = NULL; while (head) { printf("%d\n", head->data); head = head->next; } return 0; }
需要着重注意的是while那部分(通过头指针遍历完整个链表)。
那么什么又是头结点呢?很多时候,会在链表的头部附加一个结点,该结点的数据域可以不存储任何信息,这个结点称为头结点,
头结点的指针域指向第一个结点,例如:
struct node head, first; head.next = &first;
那么这里的头指针又是谁呢,不在是指向第一个结点的指针,而是指向头结点的指针,例如:
struct node *root = &head;
即root指针才是头指针。示例如下:
#include <stdio.h> struct node { int data; struct node *next; }; int main(void) { struct node *root, head, first, second; root = &head; root->data = 0; root->next = &first; first.data = 1; first.next = &second; second.data = 2; second.next = NULL; while (root) { printf("%d\n", root->data); root = root->next; } return 0; }