关于单链表的存取,有时候我们在单链表的第一个结点(有效元素)之前附设一个结点,称之为头结点;
指向头结点的指针,称之为头指针;
带头结点的单链表
//定义结点的结构体
typedef struct LNode{
int data;
struct LNode *next;
}LNode,*LinkList;
- //此行的LNode是结构体struct LNode的一个别名
- //*LinkList也是结构体struct LNode的一个别名
- //换言之LinkList是结构体struct LNode类型的指针的别名
- //也就是说 struct LNode *p;这条语句等同于LinkList p;
则定义LinkList L;时,L为链表的头指针。
L=(LinkList) malloc (sizeof(LNode)); //创建一个结点
此处返回给L的是一个指针,并且赋给了头指针。
L->next=null; //这里说明我创建了一个头结点,即同时运用了头指针和头结点。
关于头指针:
- 在线性表的链式存储结构中,头指针是指链表指向第一个结点的指针,若链表有头结点,则头指针就是指向链表头结点的指针。
- 头指针具有标识作用,故常用头指针冠以链表的名字。
- 无论链表是否为空,头指针均不为空。头指针是链表的必要元素。
关于头结点:
- 头结点是为了操作的统一与方便而设立的,放在第一个元素结点之前,其数据域一般无意义(当然有些情况下也可存放链表的长度、用做监视哨等等)。
- 有了头结点后,对在第一个元素结点前插入结点和删除第一个结点,其操作与对其它结点的操作统一了。
- 首元结点也就是第一个元素的结点,它是头结点后边的第一个结点。
- 头结点不是链表所必需的。
- 在链表操作中,我们常常要用链表变量作物函数的参数,这时,用LinkListL还是LinkList *L就很值得考虑深究了,一个用不好,函数就会出现逻辑错误,其准则是:
-
如果函数会改变指针L的值,而你希望函数结束调用后保存L的值,那你就要用LinkList*L,这样,向函数传递的就是指针的地址,结束调用后,自然就可以去改变指针的值;
而如果函数只会修改指针所指向的内容,而不会更改指针的值,那么用LinkListL就行了;