1. 什么是单链表
单链表是一种常见的基本数据结构,它由一系列称为节点的元素组成,每个节点包含了数据和一个指向下一个节点的指针。单链表中的节点按顺序链接在一起,每个节点只能访问其后继节点,而不能访问前驱节点。
单链表的特点
单链表具有以下特点:
节点之间通过指针链接,在内存中非连续存储。
每个节点包含两部分数据,即存储的数据和指向下一个节点的指针。
单链表中只能从头节点开始遍历,逐个访问后续节点,无法直接访问前驱节点。
尾节点的指针指向空值(NULL)。
2. 单链表的基本操作
2.1 新建链表
要创建一个单链表,需要先创建一个头节点,并把头节点赋值给链表的头指针。头节点不存储数据,只作为链表的入口。
struct ListNode
{
int data;
struct ListNode* next;
};
struct ListNode* createLinkedList()
{
struct ListNode* head = (struct ListNode*)malloc(sizeof(struct ListNode));
head->next = NULL;
return head;
}
在上述代码中,使用了一个结构体 ListNode
来表示单链表的节点,包含了一个整型数据 data
和一个指向下一个节点的指针 next
。通过 createLinkedList
函数可以创建一个空链表并返回链表的头指针。
2.2 添加元素
要向单链表中添加元素,可以分为两种情况:
在链表的头部插入元素。
在链表的尾部插入元素。
以下是分别实现这两种情况的代码:
void insertAtHead(struct ListNode* head, int data)
{
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->data = data;
newNode->next = head->next;
head->next = newNode;
}
void insertAtTail(struct ListNode* head, int data)
{
struct ListNode* newNode = (struct ListNode*)malloc(sizeof(struct ListNode));
newNode->data = data;
newNode->next = NULL;
struct ListNode* p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = newNode;
}
在 insertAtHead
函数中,我们先创建一个新的节点,将要插入的数据存入新节点的 data
字段中。然后,将新节点的 next
指针设置为原头节点的 next
指针,再将头节点的 next
指针指向新节点。
在 insertAtTail
函数中,我们先创建一个新的节点,并将要插入的数据存入新节点的 data
字段中。接着,从头节点开始遍历,直到找到尾节点(即 next
指针为 NULL
的节点),将该节点的 next
指针指向新节点。
2.3 删除元素
要从单链表中删除元素,我们可以根据元素的位置来删除:
删除链表的头节点。
删除链表的尾节点。
删除链表中的某个特定元素。
以下是相应操作的代码:
void deleteAtHead(struct ListNode* head)
{
if (head->next != NULL) {
struct ListNode* temp = head->next;
head->next = temp->next;
free(temp);
}
}
void deleteAtTail(struct ListNode* head)
{
struct ListNode* p = head;
while (p->next != NULL && p->next->next != NULL) {
p = p->next;
}
if (p->next != NULL) {
struct ListNode* temp = p->next;
p->next = NULL;
free(temp);
}
}
void deleteElement(struct ListNode* head, int data)
{
struct ListNode* p = head;
while (p->next != NULL && p->next->data != data) {
p = p->next;
}
if (p->next != NULL) {
struct ListNode* temp = p->next;
p->next = temp->next;
free(temp);
}
}
在 deleteAtHead
函数中,我们先判断头节点的 next
指针是否为空,如果不为空,则将头节点的 next
指针指向下一个节点,并释放原头节点。
在 deleteAtTail
函数中,我们找到倒数第二个节点,将其 next
指针设置为 NULL
,并释放尾节点。
在 deleteElement
函数中,我们找到要删除的节点的前驱节点,将其 next
指针指向要删除节点的下一个节点,并释放要删除的节点。
3. 单链表的应用场景
单链表的应用场景非常广泛,以下是几个常见的应用场景:
3.1 链表作为栈
单链表可以用来实现栈的数据结构。栈是一种后进先出(LIFO)的数据结构,只能从一端添加和取出元素。我们可以使用头节点作为栈顶指针,每次在头节点之后添加或删除节点来实现栈的入栈和出栈操作。
3.2 链表作为队列
单链表也可以用来实现队列的数据结构。队列是一种先进先出(FIFO)的数据结构,只能从一端添加元素,从另一端删除元素。我们可以使用头节点作为队列的队头指针,尾节点作为队尾指针,每次在尾节点之后添加节点,从头节点后面删除节点来实现队列的入队和出队操作。
3.3 链表作为哈希表
哈希表是一种常用的数据结构,用于存储键值对。每个键值对通过哈希函数计算出一个唯一的哈希码,并根据哈希码存储在对应的槽位中。哈希表可以使用单链表解决哈希冲突的问题,即多个键值对计算得到相同的哈希码的情况。
4. 总结
本文介绍了单链表的定义、特点和基本操作,包括新建链表、添加元素和删除元素等操作。单链表是一种灵活的数据结构,适用于多种场景,如栈、队列和哈希表等。在实际应用中,根据具体需求和场景,可以选择合适的操作来处理单链表。