在C语言数据结构中,链表是一种常用的数据结构,用于存储和组织数据。
链表可以分为带头和不带头两种形式。
1.带头节点和不带头节点的定义——单链表示例代码
1.不带头节点的单链表定义:
代码语言:javascript复制不带头链表是指链表中没有额外的头结点,即链表的第一个结点即为链表的起始点。不带头链表的结构上的区别是,链表的第一个结点即为链表起始点,没有额外的头结点。不带头链表的形式上的区别是,在对链表进行操作时,通常从第一个结点开始遍历。
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int data;
struct ListNode* next;
};
// 创建节点函数
struct ListNode* createNode(int data) {
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 插入节点函数
void insertNode(struct ListNode** head, int data) {
struct ListNode* newNode = createNode(data);
if (*head == NULL) {
*head = newNode;
} else {
struct ListNode* current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
}
// 打印链表函数
void printList(struct ListNode* head) {
struct ListNode* current = head;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("n");
}
int main() {
struct ListNode* head = NULL;
insertNode(&head, 1);
insertNode(&head, 2);
insertNode(&head, 3);
printList(head);
return 0;
}
2.带头节点的单链表定义:
- 带头链表:带头链表是指在链表的头部添加一个额外的头结点,该头结点不存储任何数据,只是作为链表的起始点。带头链表的结构上的区别是,链表的第一个结点即为头结点的下一个结点,头结点的指针指向第一个结点。带头链表的形式上的区别是,在对链表进行操作时,通常从头结点的下一个结点开始遍历。
#include <stdio.h>
#include <stdlib.h>
struct ListNode {
int data;
struct ListNode* next;
};
// 创建头节点函数
struct ListNode* createHeadNode() {
struct ListNode* headNode = (struct ListNode*)malloc(sizeof(struct ListNode));
headNode->next = NULL;
return headNode;
}
// 创建节点函数
struct ListNode* createNode(int data) {
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->data = data;
newNode->next = NULL;
return newNode;
}
// 插入节点函数
void insertNode(struct ListNode* head, int data) {
struct ListNode* newNode = createNode(data);
struct ListNode* current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = newNode;
}
// 打印链表函数
void printList(struct ListNode* head) {
struct ListNode* current = head->next;
while (current != NULL) {
printf("%d ", current->data);
current = current->next;
}
printf("n");
}
int main() {
struct ListNode* head = createHeadNode();
insertNode(head, 1);
insertNode(head, 2);
insertNode(head, 3);
printList(head);
return 0;
}
以上是带头节点和不带头节点的单链表定义和使用的示例代码。不带头节点的单链表可以直接使用数据节点来作为头节点,而带头节点的单链表需要额外创建一个头节点来存储链表的头部信息。
输出结果都是:
代码语言:javascript复制1 2 3
2.结构上的区别:
1.带头链表:带头链表在链表的头部添加一个额外的节点,该节点不存储任何数据,仅用于方便操作链表。带头链表的第一个节点是实际存储数据的节点,从第一个节点开始遍历整个链表。
2.不带头链表:不带头链表没有额外的头节点,第一个节点即为实际存储数据的节点。
3.应用上的区别:
1.带头链表:
- 简化对链表的操作:使用带头链表可以避免链表为空时的特殊处理情况,因为带头链表中至少有一个结点,可以保证链表不为空。
- 方便在链表头部进行插入和删除操作:由于带头链表的头结点是额外添加的,不存储任何数据,因此可以方便地在链表头部进行插入和删除操作,而不需要考虑原链表是否为空的情况。
2.不带头链表:
- 节省内存空间:不带头链表不需要额外的头结点,可以节省一些内存空间。
- 部分算法更适合应用于不带头链表:在某些算法中,不带头链表的特性更适合,例如双指针法等。
4.具体应用上的说明:
1.带头链表常用于实现各种数据结构和算法,如栈、队列、图等。它可以方便地进行节点的插入、删除和遍历操作。
2.不带头链表常用于简单的数据存储和处理场景,如链表的基本操作、链表的排序等。由于不需要额外的头节点,所以在内存空间有限的情况下,可以选择使用不带头链表。