关注+星标公众号,不错过精彩内容
作者 | 量子君
微信公众号 | 极客工作室
前言
在有数据域的链表中,每个节点除了指针外,还包含一个数据域,用于存储实际数据。而在无数据域的链表中,节点仅包含指针,用于构建节点之间的连接关系,实际数据则存储在与节点关联的其他数据结构中。
有数据域链表 vs 无数据域双向链表
节点结构
有数据域链表:节点结构包含数据域和指向下一个节点的指针。
无数据域双向链表:节点结构仅包含指向前一个节点和后一个节点的指针。
内存消耗
有数据域链表:每个节点需要额外的空间来存储数据。
无数据域双向链表:节点本身不存储数据,节省了额外的空间。
访问数据
有数据域链表:可以直接从节点中访问数据域。
无数据域双向链表:需要通过其他数据结构与节点关联,才能访问数据。
应用场景
有数据域链表:适用于需要存储实际数据的场景,如链表排序、数据存储等。
无数据域双向链表:适用于只需要节点连接关系而不需要额外数据的场景,如资源管理、算法实现等。
代码比较
// 有数据域链表节点结构体
struct NodeWithData {
int data; // 数据域为int类型
struct NodeWithData* prev;
struct NodeWithData* next;
};
// 无数据域链表节点结构体
struct NodeWithoutData {
struct NodeWithoutData* prev;
struct NodeWithoutData* next;
};
offsetof
offsetof
。offsetof
是 C 标准库中的一个宏,用于计算结构体中成员的偏移量。它的定义在头文件 stddef.h
中,使用时需要包含该头文件。offsetof
宏接受两个参数:结构体类型和成员名,返回成员在结构体中的偏移量(以字节为单位)。type, member) ((size_t)&(((type *)0)->member)) define offsetof(
代码实现
#include <stdio.h>
#include <stddef.h> // 包含offsetof宏
// 定义节点结构体
struct Node
{
struct Node* prev;
struct Node* next;
};
// 定义测试结构体
struct Data
{
int data;
struct Node list;
};
// 插入节点到链表尾部
void insert(struct Node* head, struct Node* newNode)
{
struct Node* current = head;
while (current->next != NULL)
{
current = current->next;
}
newNode->prev = current;
newNode->next = NULL;
current->next = newNode;
}
// 打印链表内容
void printList(struct Node* head)
{
printf("List: ");
struct Node* current = head->next;
while (current != NULL)
{
// 通过偏移量找到Test结构体的地址
struct Data* test = (struct Data*)((char*)current - offsetof(struct Data, list));
printf("%d -> ", test->data);
current = current->next;
}
printf("NULL\n");
}
int main()
{
// 创建链表头节点
struct Node head;
head.prev = NULL;
head.next = NULL;
// 创建并插入节点
struct Data test1 = {1, {NULL, NULL}};
struct Data test2 = {2, {NULL, NULL}};
struct Data test3 = {3, {NULL, NULL}};
// 插入节点到链表
insert(&head, &test1.list);
insert(&head, &test2.list);
insert(&head, &test3.list);
// 打印链表内容
printList(&head);
return 0;
}