1. 定义节点结构体: 链表中的每个节点都包含一个数据域和一个指向下一个节点的指针。可以通过结构体来定义节点。
#include <stdio.h>
#include <stdlib.h>
// 定义节点结构体
typedef struct Node {
int data; // 数据域
struct Node *next; // 指针域,指向下一个节点
} Node;
这两种头插法存在细微的细节:
增
头插法1:
void headInsert(Node **head, int data) {
// 创建新节点并分配内存空间
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = data;
// 将新节点的指针指向当前头节点
newNode->next = *head;
// 更新头节点指针为新节点
*head = newNode;
}
头插法2:
Node *insertNodeAtBeginning(Node *head, int newData) {
// 创建新节点并分配内存空间
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = newData;
// 将新节点的指针指向当前头节点
newNode->next = head;
// 更新头节点指针为新节点
head = newNode;
return head;
}
主要区别在于返回值和参数的不同:
-
头插法 1 接受一个指向指针的指针作为参数,它直接修改了头指针本身,因此不需要返回值。
-
头插法 2 接受当前链表的头指针作为参数,并返回更新后的头指针。因为它不直接修改头指针本身,而是返回更新后的头指针。
以下是尾插法
尾插法1:
void tailInsert(Node **head, int data) {
// 创建新节点并分配内存空间
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = data;
newNode->next = NULL; // 将新节点的下一个节点指针设为 NULL,表示它是链表的最后一个节点
// 如果链表为空,直接将新节点设为头节点
if (*head == NULL) {
*head = newNode;
return;
}
// 找到链表的最后一个节点
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
// 将新节点连接到链表的最后一个节点之后
current->next = newNode;
}
尾插法2:
Node *tailInsert(Node *head, int newData) {
// 创建新节点并分配内存空间
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->data = newData;
newNode->next = NULL; // 新节点将成为链表的最后一个节点,因此其下一个节点指针设为 NULL
// 如果链表为空,直接将新节点设为头节点并返回
if (head == NULL) {
return newNode;
}
// 找到链表的最后一个节点
Node *current = head;
while (current->next != NULL) {
current = current->next;
}
// 将新节点连接到链表的最后一个节点之后
current->next = newNode;
// 返回原头节点
return head;
}
这个函数与头插法相比,主要区别在于返回值的处理。在尾插法中,需要保持原头节点不变,因此返回原头节点的指针。然后,将新节点插入到链表的末尾,最后返回原头节点的指针。
在使用上,头插法 1 更适合于不需要返回头指针的场景,而头插法 2 更适合于需要返回头指针的场景。通常情况下,两者的功能是相同的,只是接口设计上稍有不同。
单向链表的基本操作主要有以下5个功能,增(头插法,尾插法),删(头删法,尾删法,和删一个节点),改,查,销毁,所以,以下将会针对两种形式的无头链表进行删,改,查和销毁。
删
头删法1:
void headDelete(Node **head) {
// 如果链表为空,直接返回
if (*head == NULL) {
printf("List is empty.\n");
return;
}
// 保存头节点到临时变量
Node *temp = *head;
// 更新头节点指针为原头节点的下一个节点
*head = (*head)->next;
// 释放临时变量指向的节点的内存空间
free(temp);
}
尾删法1:
void tailDelete(Node **head) {
// 如果链表为空,直接返回
if (*head == NULL) {
printf("List is empty.\n");
return;
}
// 如果链表只有一个节点,直接释放头节点,并将头指针置为空
if ((*head)->next == NULL) {
free(*head);
*head = NULL;
return;
}
// 找到倒数第二个节点
Node *prev = *head;
while (prev->next->next != NULL) {
prev = prev->next;
}
// 保存最后一个节点到临时变量
Node *temp = prev->next;
// 倒数第二个节点的下一个节点指针设为 NULL
prev->next = NULL;
// 释放临时变量指向的节点的内存空间
free(temp);
}
删一个1:
void deleteNodeByValue(Node **head, int data) {
// 如果链表为空,直接返回
if (*head == NULL) {
printf("List is empty.\n");
return;
}
// 如果头节点是要删除的节点
if ((*head)->data == data) {
Node *temp = *head;
*head = (*head)->next;
free(temp);
return;
}
// 寻找要删除节点的前一个节点
Node *prev = *head;
while (prev->next != NULL && prev->next->data != data) {
prev = prev->next;
}
// 如果未找到要删除的节点,则返回
if (prev->next == NULL) {
printf("Node with data %d not found.\n", data);
return;
}
// 找到要删除的节点,删除它
Node *temp = prev->next;
prev->next = temp->next;
free(temp);
}
头删法2:
Node *headDelete(Node *head) {
// 如果链表为空,直接返回
if (head == NULL) {
printf("List is empty.\n");
return NULL;
}
// 保存头节点的下一个节点到临时变量
Node *temp = head->next;
// 释放头节点的内存空间
free(head);
// 返回新的头节点
return temp;
}
尾删法2:
Node *tailDelete(Node *head) {
// 如果链表为空,直接返回
if (head == NULL) {
printf("List is empty.\n");
return NULL;
}
// 如果链表只有一个节点,直接释放头节点,并返回 NULL
if (head->next == NULL) {
free(head);
return NULL;
}
// 找到倒数第二个节点
Node *prev = head;
while (prev->next->next != NULL) {
prev = prev->next;
}
// 保存最后一个节点到临时变量
Node *temp = prev->next;
// 倒数第二个节点的下一个节点指针设为 NULL
prev->next = NULL;
// 释放最后一个节点的内存空间
free(temp);
// 返回头节点
return head;
}
删一个2:
Node *deleteNodeByValue(Node *head, int data) {
// 如果链表为空,直接返回
if (head == NULL) {
printf("List is empty.\n");
return NULL;
}
// 如果头节点是要删除的节点
if (head->data == data) {
Node *temp = head;
head = head->next;
free(temp);
return head;
}
// 寻找要删除节点的前一个节点
Node *prev = head;
while (prev->next != NULL && prev->next->data != data) {
prev = prev->next;
}
// 如果未找到要删除的节点,则返回
if (prev->next == NULL) {
printf("Node with data %d not found.\n", data);
return head;
}
// 找到要删除的节点,删除它
Node *temp = prev->next;
prev->next = temp->next;
free(temp);
return head;
}
改1:
void modifyNode(Node **head, int oldData, int newData) {
// 如果链表为空,直接返回
if (*head == NULL) {
printf("List is empty.\n");
return;
}
// 查找要修改的节点
Node *current = *head;
while (current != NULL) {
if (current->data == oldData) {
current->data = newData;
return;
}
current = current->next;
}
printf("Node with data %d not found.\n", oldData);
}
查1:
Node *findNode(Node *head, int data) {
Node *current = *head;
while (current != NULL) {
if (current->data == data) {
return current;
}
current = current->next;
}
return NULL;
}
销毁1:
void destroyList(Node **head) {
// 释放链表的所有节点
while (*head != NULL) {
Node *temp = *head;
*head = (*head)->next;
free(temp);
}
}