目录
一 简介
单链表是一种线性数据结构,其中元素(节点)非连续存储,每个节点包含两部分:数据域存储有效数据,指针域存储指向下一个节点地址的指针。链表从头节点开始,通过指针串联各节点形成逻辑上的线性序列,插入删除操作便捷(只需更改相邻节点的指针),但访问需从头节点逐步遍历。因其动态分配内存的特点,单链表能灵活适应数据规模的变化。
二 单链表的定义(C语言)
在C语言中定义单链表通常涉及到定义一个结构体来表示链表中的节点,并声明一个指向该结构体类型的指针作为链表的头指针。以下是一个简单的单链表节点结构体定义及其头指针声明的例子:
// 定义链表节点结构体
typedef struct ListNode {
int data; // 数据域,假设存储整型数据
struct ListNode *next; // 指针域,指向下一个节点
} ListNode;
// 定义链表头指针
ListNode *head = NULL; // 初始化为NULL表示链表为空
在这个例子中,ListNode
结构体代表链表中的每一个节点,它包含两个成员:
data
:用于存储节点所承载的实际数据,这里假设是整数类型。next
:这是一个指向相同结构体类型的指针,用来指向链表中的下一个节点。
初始化链表时,将头指针设置为NULL
表示链表为空。随后通过动态内存分配(如使用malloc
函数)创建新节点并链接起来,就可以构建和操作单链表了。
三 基本操作
单链表作为一种基础的链式数据结构,具备一系列基本操作,以下是常见的单链表操作列表以及简要说明:
初始化链表:
创建一个新的空链表,设置头指针为NULL
,表示链表目前没有任何节点。
ListNode* initList() {
ListNode* head = NULL;
return head;
}
创建节点:
动态分配内存创建一个新的节点,并给其数据域赋值。
ListNode* createNode(int value) {
ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));
if (newNode != NULL) {
newNode->data = value;
newNode->next = NULL;
}
return newNode;
}
插入操作:
头插法:
在链表头部添加新节点。
void insertAtHead(ListNode** head, int value) {
ListNode* newNode = createNode(value);
newNode->next = *head;
*head = newNode;
}
尾插法:
在链表尾部添加新节点,需要遍历整个链表找到尾节点。
void insertAtTail(ListNode** head, int value) {
ListNode* newNode = createNode(value);
if (*head == NULL) {
*head = newNode;
} else {
ListNode* temp = *head;
while (temp->next != NULL) {
temp = temp->next;
}
temp->next = newNode;
}
}
指定位置插入:
在某个节点之后插入新节点,同样需要遍历链表找到相应位置。
删除操作:
删除头节点:
移除并释放头节点。
void deleteHead(ListNode** head) {
if (*head != NULL) {
ListNode* temp = *head;
*head = (*head)->next;
free(temp);
}
}
删除尾节点:
找到倒数第二个节点,将其next指针置为NULL。
void deleteTail(ListNode** head) {
if (*head != NULL) {
ListNode* current = *head;
if ((*head)->next == NULL) {
free(*head);
*head = NULL;
} else {
while (current->next->next != NULL) {
current = current->next;
}
free(current->next);
current->next = NULL;
}
}
}
删除指定值节点:
遍历链表并删除匹配值的节点。
查找操作:
查找特定值:遍历链表查找具有特定值的节点,返回指向该节点的指针,或在找不到时返回NULL。
修改操作:
修改节点值:找到具有特定值的节点并更新其data域的值。
打印链表:
遍历链表:从头节点开始,通过next
指针逐个访问并打印所有节点的data域。
以上是一些单链表的基础操作,具体实现时需要考虑边界条件及内存管理等问题。