c语言实例 -- 循环链表
要求:
创建一个循环链表
下面是一个简单的循环链表(循环单链表)的C语言实现。循环链表是指链表的最后一个节点的指针指向第一个节点,形成一个环形结构。这种结构的优点是在一些特定的场景可以简化操作逻辑。
循环链表的基本操作
- 初始化循环链表
- 插入节点
- 删除节点
- 打印链表
- 销毁链表
#include <stdio.h>
#include <stdlib.h>// 定义节点结构
typedef struct Node {int data;struct Node* next;
} Node;// 初始化循环链表
Node* initialize() {Node* head = NULL;return head;
}// 插入节点
void insert(Node** head, int data) {Node* newNode = (Node*)malloc(sizeof(Node));newNode->data = data;if (*head == NULL) {// 如果链表为空,新节点即为头节点*head = newNode;newNode->next = newNode;} else {Node* temp = *head;// 找到链表的最后一个节点while (temp->next != *head) {temp = temp->next;}temp->next = newNode; // 最后节点指向新节点newNode->next = *head; // 新节点指向头节点}
}// 删除节点
void delete(Node** head, int key) {if (*head == NULL) return; // 如果链表为空,不做处理Node *temp = *head, *prev;// 如果头节点就是需要删除的节点if (temp->data == key) {// 找到最后一个节点,重新设置其next指针Node* last = *head;while (last->next != *head) {last = last->next;}if (*head == last) {free(*head);*head = NULL;} else {last->next = temp->next;*head = temp->next;free(temp);}return;}// 查找要删除的节点while (temp->next != *head && temp->data != key) {prev = temp;temp = temp->next;}// 如果找到了,删除节点if (temp->data == key) {prev->next = temp->next;free(temp);}
}// 打印链表
void printList(Node* head) {if (head == NULL) return;Node* temp = head;do {printf("%d ", temp->data);temp = temp->next;} while (temp != head);printf("\n");
}// 销毁链表
void destroyList(Node** head) {if (*head == NULL) return;Node* temp = *head;Node* next;// 先处理第二个节点开始的部分while (temp->next != *head) {next = temp->next;free(temp);temp = next;}// 最后处理头节点free(temp);*head = NULL;
}// 主函数
int main() {Node* head = initialize();insert(&head, 10);insert(&head, 20);insert(&head, 30);printf("Circular Linked List: ");printList(head);delete(&head, 20);printf("After deletion of 20: ");printList(head);destroyList(&head);return 0;
}
讲解
- 初始化循环链表:创建一个头节点的指针并将其初始化为
NULL
。 - 插入节点:向链表中插入新节点时,首先创建新节点并将数据填充。如果链表为空,则新节点的
next
指针指向自己;否则,找到最后一个节点并调整指针以连接新节点,使其形成环。 - 删除节点:找到要删除的节点,如果是头节点,特别处理从
temp->next
开始的链表,调整最后一个节点的next
,或者直接删除节点并重置头节点。如果不是头节点,则找到节点前的节点以调整其next
指针。 - 打印链表:从头节点开始,遍历链表直到回到头节点。
- 销毁链表:释放所有节点的内存,循环释放直到再次回到头节点。
通过上面的代码,可以实现一个简单的循环链表,进行增删节点、遍历以及内存释放等基本操作。
情景设定:任务调度器
在很多嵌入式系统和实时操作系统中,经常需要多任务调度。例如,我们可以设想一个简单的定时任务调度器,在有限的硬件资源下循环顺序执行一组任务。我们可以使用循环链表来实现这种任务调度器,每个节点都表示一个待执行的任务。
每个任务执行后,将立即转移到下一个任务,形成一套循环的任务执行机制。这种设计能够保证所有任务被公平、持续地执行。
实现代码
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // 用于sleep函数// 定义节点结构表示一个任务
typedef struct TaskNode {char* taskName;void (*execute)(void); // 指向任务执行函数的指针struct TaskNode* next;
} TaskNode;// 初始化任务调度器
TaskNode* initializeScheduler() {return NULL;
}// 添加任务
void addTask(TaskNode** head, char* taskName, void (*execute)(void)) {TaskNode* newTask = (TaskNode*)malloc(sizeof(TaskNode));newTask->taskName = taskName;newTask->execute = execute;if (*head == NULL) {*head = newTask;newTask->next = newTask;} else {TaskNode* temp = *head;while (temp->next != *head) {temp = temp->next;}temp->next = newTask;newTask->next = *head;}
}// 删除任务
void deleteTask(TaskNode** head, char* taskName) {if (*head == NULL) return;TaskNode *current = *head, *prev = NULL;do {if (strcmp(current->taskName, taskName) == 0) {if (prev == NULL) {TaskNode* last = *head;while (last->next != *head) {last = last->next;}if (current == last) {free(current);*head = NULL;} else {last->next = current->next;*head = current->next;free(current);}} else {prev->next = current->next;free(current);}return;}prev = current;current = current->next;} while (current != *head);
}// 任务调度循环
void runScheduler(TaskNode* head) {TaskNode* current = head;if (current == NULL) return;do {printf("Executing task: %s\n", current->taskName);current->execute();current = current->next;sleep(1); // 模拟任务切换间隔} while (current != head);
}// 示例任务函数
void taskA() {printf("Task A is running.\n");
}void taskB() {printf("Task B is running.\n");
}void taskC() {printf("Task C is running.\n");
}// 主函数
int main() {TaskNode* scheduler = initializeScheduler();addTask(&scheduler, "Task A", taskA);addTask(&scheduler, "Task B", taskB);addTask(&scheduler, "Task C", taskC);printf("Task Scheduler started\n");runScheduler(scheduler);deleteTask(&scheduler, "Task B");printf("\nTask B removed\n");runScheduler(scheduler);return 0;
}
讲解
-
任务节点:每个节点存放一个任务的名称和其对应的执行函数。
-
任务调度器的初始化:通过初始化函数创建一个空的任务链表,准备好后续任务的添加。
-
添加任务:通过函数指针将具体任务的行为存储到节点中,并链接形成循环链表。
-
删除任务:从链表中找到要删除的任务节点并释放内存,把链表重新链接。
-
任务调度:通过
runScheduler
函数循环调用每个任务对应的函数,模拟任务被连续调度执行的过程。
此示例实现了一个简单的任务调度器,通过循环链表结构,可以公平地调度任务,并支持任务的增删。这在嵌入式系统中可以用于管理有限的周期性任务执行。