目录
链表是一种常见的动态数据结构,它由一系列节点组成,每个节点包含数据和指向下一个节点的指针。在C语言中,可以使用指针和动态内存分配函数来实现链表的创建、遍历、插入、删除和交换操作。
创建一个单向链表的基本步骤包括定义节点结构和使用动态内存分配函数分配节点内存。节点结构通常包含两个成员:数据成员(用于存储数据)和指针成员(用于指向下一个节点)。通过将节点链接在一起,形成链表的结构。
- // 定义节点结构
- struct Node {
- int data; // 数据成员
- struct Node* next; // 指针成员
- };
-
- // 创建链表
- struct Node* createLinkedList() {
- struct Node* head = NULL; // 头指针,指向链表的第一个节点
- struct Node* temp = NULL; // 临时指针,用于创建新节点
-
- // 创建节点1
- struct Node* node1 = (struct Node*)malloc(sizeof(struct Node));
- node1->data = 1;
- node1->next = NULL;
-
- // 将节点1设为头节点
- head = node1;
-
- // 创建节点2
- struct Node* node2 = (struct Node*)malloc(sizeof(struct Node));
- node2->data = 2;
- node2->next = NULL;
-
- // 将节点2链接到节点1后面
- node1->next = node2;
-
- // 创建节点3
- struct Node* node3 = (struct Node*)malloc(sizeof(struct Node));
- node3->data = 3;
- node3->next = NULL;
-
- // 将节点3链接到节点2后面
- node2->next = node3;
-
- return head; // 返回头指针
- }
遍历链表的过程是按顺序访问链表中的每个节点,并执行相应的操作。通过使用一个指针依次指向链表中的节点,可以遍历整个链表。
- // 遍历链表并打印节点数据
- void traverseLinkedList(struct Node* head) {
- struct Node* current = head; // 从头节点开始遍历
-
- while (current != NULL) {
- printf("%d ", current->data); // 打印节点数据
- current = current->next; // 移动到下一个节点
- }
- }
在链表中插入、删除和交换节点是常见的操作,可以通过更新节点的指针来实现。
- // 在链表中插入节点
- void insertNode(struct Node* prevNode, int newData) {
- if (prevNode == NULL) {
- printf("Error: Previous node cannot be NULL.\n");
- return;
- }
-
- struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
- newNode->data = newData;
- newNode->next = prevNode->next;
- prevNode->next = newNode;
- }
-
prevNode和要插入的新数据newData作为参数。prevNode是否为NULL
newData赋值给新节点的data成员。next指针设置为prevNode的下一个节点,并将prevNode的next指针指向新节点,完成插入操作。- // 在链表中删除节点
- void deleteNode(struct Node* prevNode) {
- if (prevNode == NULL || prevNode->next == NULL) {
- printf("Error: Node to be deleted cannot be NULL.\n");
- return;
- }
-
- struct Node* nodeToDelete = prevNode->next;
- prevNode->next = nodeToDelete->next;
- free(nodeToDelete); // 释放内存
- }
prevNode作为参数。prevNode是否为NULL或者prevNode的下一个节点是否为NULL
nodeToDelete,将prevNode的next指针指向nodeToDelete的下一个节点,然后释放nodeToDelete的内存,完成删除操作。- // 在链表中交换两个节点的位置
- void swapNodes(struct Node* head, int data1, int data2) {
- if (data1 == data2) {
- printf("Error: Data values are the same.\n");
- return;
- }
-
- struct Node* prevNode1 = NULL;
- struct Node* prevNode2 = NULL;
- struct Node* currentNode = head;
-
- while (currentNode != NULL) {
- if (currentNode->next != NULL && currentNode->next->data == data1)
- prevNode1 = currentNode;
- if (currentNode->next != NULL && currentNode->next->data == data2)
- prevNode2 = currentNode;
-
- currentNode = currentNode->next;
- }
-
- if (prevNode1 == NULL || prevNode2 == NULL) {
- printf("Error: Data values not found in the list.\n");
- return;
- }
-
- struct Node* node1 = prevNode1->next;
- struct Node* node2 = prevNode2->next;
-
- if (prevNode1 != NULL)
- prevNode1->next = node2;
- else
- head = node2;
-
- if (prevNode2 != NULL)
- prevNode2->next = node1;
- else
- head = node1;
-
- struct Node* temp = node1->next;
- node1->next = node2->next;
- node2->next = temp;
- }
head以及要交换的两个节点的数据值data1和data2作为参数。data1和data2是否相等,如果相等,则打印错误消息并返回。然prevNode1、prevNode2和currentNode来遍历链表,找到包含data1和data2的节点的前一个节点。prevNode1和prevNode2是否为NULL,如果为NULL,则打印错误消息并返回。node1和node2。next指针,将node1的前一个节点的next指向node2,将node2的前一个节点的next指向node1,实现节点位置的交换。next指针,完成交换操作。下面是一个示例,演示了如何使用单向链表来实现一个简单的任务列表:
- #include
- #include
-
- struct Task {
- char name[100];
- struct Task* next;
- };
-
- struct Task* createTask(const char* name) {
- struct Task* task = (struct Task*)malloc(sizeof(struct Task));
- strcpy(task->name, name);
- task->next = NULL;
- return task;
- }
-
- void addTask(struct Task** head, const char* name) {
- struct Task* newTask = createTask(name);
- if (*head == NULL) {
- *head = newTask;
- } else {
- struct Task* current = *head;
- while (current->next != NULL) {
- current = current->next;
- }
- current->next = newTask;
- }
- }
-
- void printTasks(struct Task* head) {
- struct Task* current = head;
- while (current != NULL) {
- printf("%s\n", current->name);
- current = current->next;
- }
- }
-
- int main() {
- struct Task* taskList = NULL;
-
- addTask(&taskList, "Task 1");
- addTask(&taskList, "Task 2");
- addTask(&taskList, "Task 3");
-
- printTasks(taskList);
-
- return 0;
- }
任务列表struct Task结构体,包含一个名为name的字符数组和一个指向下一个任务的指针next。
输出:
- Task 1
- Task 2
- Task 3
除了链表,栈和队列也是常见的动态数据结构。栈是一种后进先出(LIFO)的数据结构,可以使用数组或链表来实现。队列是一种先进先出(FIFO)的数据结构,也可以使用数组或链表来实现。关于栈和队列的相关介绍详见后文。