链表是一种常见的数据结构,它由一系列节点(Node)组成,每个节点包含数据域和指向下一个节点的指针。链表的主要优势是其动态性和灵活性,允许高效的插入和删除操作。
以下是关于链表的详细介绍,包括定义、基本操作、以及完整示例代码。
1. 链表的定义
一个简单的链表节点结构可以定义为:
#include <stdio.h> #include <stdlib.h> // 定义链表节点结构 struct Node { int data; // 数据域 struct Node* next; // 指向下一个节点的指针 };
2. 创建链表节点
创建一个新的链表节点:
struct Node* createNode(int data) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); // 分配内存 newNode->data = data; // 设置数据 newNode->next = NULL; // 设置指针为NULL return newNode; }
3. 链表的基本操作
插入节点
在链表头部插入节点:
void insertAtHead(struct Node** head, int data) { struct Node* newNode = createNode(data); newNode->next = *head; // 新节点的下一个节点是当前的头节点 *head = newNode; // 头指针指向新节点 }
在链表尾部插入节点:
void insertAtTail(struct Node** head, int data) { struct Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; return; } struct Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; }
删除节点
从链表中删除节点:
void deleteNode(struct Node** head, int key) { struct Node* temp = *head; struct Node* prev = NULL; // 如果头节点本身是要删除的节点 if (temp != NULL && temp->data == key) { *head = temp->next; // 改变头指针 free(temp); // 释放旧头节点的内存 return; } // 搜索要删除的节点,记录前一个节点 while (temp != NULL && temp->data != key) { prev = temp; temp = temp->next; } // 如果未找到该节点 if (temp == NULL) return; // 解除链接并释放内存 prev->next = temp->next; free(temp); }
搜索节点
在链表中搜索某个节点:
struct Node* searchNode(struct Node* head, int key) { struct Node* current = head; while (current != NULL) { if (current->data == key) { return current; } current = current->next; } return NULL; }
4. 打印链表
遍历并打印链表:
void printList(struct Node* head) { struct Node* temp = head; while (temp != NULL) { printf("%d -> ", temp->data); temp = temp->next; } printf("NULL\n"); }
5. 完整示例代码
下面是一个包含所有基本操作的完整示例:
#include <stdio.h> #include <stdlib.h> // 定义链表节点结构 struct Node { int data; struct Node* next; }; // 创建一个新节点 struct Node* createNode(int data) { struct Node* newNode = (struct Node*)malloc(sizeof(struct Node)); newNode->data = data; newNode->next = NULL; return newNode; } // 在链表头部插入节点 void insertAtHead(struct Node** head, int data) { struct Node* newNode = createNode(data); newNode->next = *head; *head = newNode; } // 在链表尾部插入节点 void insertAtTail(struct Node** head, int data) { struct Node* newNode = createNode(data); if (*head == NULL) { *head = newNode; return; } struct Node* temp = *head; while (temp->next != NULL) { temp = temp->next; } temp->next = newNode; } // 删除链表中的节点 void deleteNode(struct Node** head, int key) { struct Node* temp = *head; struct Node* prev = NULL; if (temp != NULL && temp->data == key) { *head = temp->next; free(temp); return; } while (temp != NULL && temp->data != key) { prev = temp; temp = temp->next; } if (temp == NULL) return; prev->next = temp->next; free(temp); } // 在链表中搜索节点 struct Node* searchNode(struct Node* head, int key) { struct Node* current = head; while (current != NULL) { if (current->data == key) { return current; } current = current->next; } return NULL; } // 打印链表 void printList(struct Node* head) { struct Node* temp = head; while (temp != NULL) { printf("%d -> ", temp->data); temp = temp->next; } printf("NULL\n"); } // 主函数测试链表操作 int main() { struct Node* head = NULL; insertAtHead(&head, 1); insertAtHead(&head, 2); insertAtHead(&head, 3); printList(head); insertAtTail(&head, 4); insertAtTail(&head, 5); printList(head); deleteNode(&head, 3); printList(head); struct Node* found = searchNode(head, 4); if (found != NULL) { printf("Found: %d\n", found->data); } else { printf("Not found\n"); } return 0; }
6. 小结
-
创建节点:使用
createNode
函数创建一个新节点。 -
插入节点:提供在链表头部和尾部插入节点的函数。
-
删除节点:通过值删除链表中的节点。
-
搜索节点:在链表中查找节点。
-
打印链表:遍历并打印链表。
这种数据结构的灵活性在于其能够高效地进行插入和删除操作,但在访问特定元素时效率较低,因为必须从头节点开始遍历。链表的变体包括双向链表和循环链表,它们提供了不同的特性和优势。