链表头结点作用

转自:http://blog.chinaunix.net/space.php?uid=20754930&do=blog&id=3336495

数据结构中,在单链表的开始结点之前附设一个类型相同的结点,称之为头结点。头结点的数据域可以不存储任何信息,头结点的指针域存储指向开始结点的指针(即第一个元素结点的存储位置)。

作用
1、防止单链表是空的而设的.当链表为空的时候,带头结点的头指针就指向头结点.如果当链表为空的时候,单链表没有带头结点,那么它的头指针就为NULL.
2、是为了方便单链表的特殊操作,插入在表头或者删除第一个结点.这样就保持了单链表操作的统一性!
3、单链表加上头结点之后,无论单链表是否为空,头指针始终指向头结点,因此空表和非空表的处理也统一了,方便了单链表的操作,也减少了程序的复杂性和出现bug的机会。
4、对单链表的多数操作应明确对哪个结点以及该结点的前驱。不带头结点的链表对首元结点、中间结点分别处理等;而带头结点的链表因为有头结点,首元结点、中间结点的操作相同 ,从而减少分支,使算法变得简单 ,流程清晰。对单链表进行插入、删除操作时,如果在首元结点之前插入或删除的是首元结点,不带头结点的单链表需改变头指针的值,在C 算法的函数形参表中头指针一般使用指针的指针(在C+ +中使用引用 &); 而带头结点的单链表不需改变头指针的值,函参数表中头结点使用指针变量即可。
 
// extern.cpp : 定义控制台应用程序的入口点。
//

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

typedef struct Node
{
    int value;
    struct Node *next;

}*pNode;


pNode creatList()
{
    pNode p = (pNode)malloc(sizeof(struct Node));
    p->next = NULL;

    if (p == NULL)
    {
        exit(1);
    }
    return p;
}

int insertNode(pNode& pRoot, int value)
{
    pNode pPre = pRoot;
    pNode pCur = pPre->next;

    while (pCur != NULL && pCur->value < value)
    {
        pPre = pPre->next;
        pCur = pPre->next;
    }

    pNode pNew = (pNode)malloc(sizeof(struct Node));
    if (pNew == NULL)
    {
        return 0;
    }
    pPre->next = pNew;
    pNew->next = pCur;
    pNew->value = value;

    return 1;
}


void printList(pNode& pRoot)
{
    pNode pFirst = pRoot->next;
    while(pFirst != NULL)
    {
        printf("%d\n", pFirst->value);
        pFirst = pFirst->next;
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    int i;
    int array[] = {5, 12, 25, 4, 26, 7};
    pNode pList = creatList();

    for (i = 0;i < 6; i++)
    {
        insertNode(pList, array[i]);
    }

    printList(pList);   
	return 0;
}


 

### 单表头结点的概念与实现 #### 头结点作用 在单表中,头结点是一个特殊的结点,它并不用于存储实际的数据信息[^1]。它的主要作用在于简化对表的操作逻辑。通过引入头结点,可以使得表的第一个数据结点与其他结点具有相同的处理方式,从而无需针对第一个数据结点单独编写额外的代码逻辑。 #### 不带头结点与带头结点的区别 对于不带头结点的单表而言,头指针直接指向第一个数据结点;而对于带头结点的单表来说,头指针指向的是头结点,而头结点的指针域则指向第一个数据结点。这种设计的好处在于,无论是空表还是非空表,头指针总是指向一个有效的结点(即头结点),这有助于统一对表的各种操作。 #### 带头结点表的初始化 以下是带头结点表初始化的一个简单实现: ```c #include <stdio.h> #include <stdlib.h> // 定义单结点结构体 typedef struct Node { int data; struct Node* next; } Node; // 初始化单表 Node* initList() { Node* head = (Node*)malloc(sizeof(Node)); // 分配内存给头结点 if (!head) { printf("Memory allocation failed!\n"); exit(EXIT_FAILURE); } head->next = NULL; // 设置头结点的下一个指针为空 return head; } ``` 上述代码展示了如何创建一个带有头结点的单表,并将其初始状态设置为空表[^2]。 #### 插入操作 为了进一步说明头结点的重要性,在插入新结点时,可以通过以下两种方式进行操作:按位插入和指定结点插入。这里以按位插入为例展示其实现过程。 ```c // 按位插入结点 void insertByPosition(Node* head, int pos, int value) { if (pos < 0) { // 如果位置非法,则返回错误提示 printf("Invalid position\n"); return; } Node* newNode = (Node*)malloc(sizeof(Node)); if (!newNode) { printf("Memory allocation failed!\n"); return; } newNode->data = value; newNode->next = NULL; if (pos == 0) { // 若要插入到第一位 newNode->next = head->next; head->next = newNode; } else { Node* current = head; for (int i = 0; i < pos && current != NULL; ++i) { current = current->next; } if (current == NULL) { printf("Position out of range\n"); free(newNode); // 释放分配的新结点空间以防泄漏 return; } newNode->next = current->next; current->next = newNode; } } ``` 此函数实现了向任意位置插入一个新的结点的功能,其中利用了头结点来减少边界条件判断的复杂度。 #### 总结 通过以上分析可以看出,头结点的存在极大地提高了单表操作的一致性和便利性。无论是在初始化阶段还是后续各种增删查改的过程中,都可以借助头结点使程序更加简洁高效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值