要求:
创建一个循环链表
下面是一个简单的循环链表(循环单链表)的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
指针。 - 打印链表:从头节点开始,遍历链表直到回到头节点。
- 销毁链表:释放所有节点的内存,循环释放直到再次回到头节点。
通过上面的代码,可以实现一个简单的循环链表,进行增删节点、遍历以及内存释放等基本操作。
情景设定:任务调度器
在很多嵌入式系统和实时操作系统中,经常需要多任务调度。例如,我们可以设想一个简单的定时任务调度器,在有限的硬件资源下循环顺序执行一组任务。我们可以使用循环链表来实现这种任务调度器,每个节点都表示一个待执行的任务。
每个任务执行后,将立即转移到下一个任务,形成一套循环的任务执行机制。这种设计能够保证所有任务被公平、持续地执行。
实现代码
c
#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
函数循环调用每个任务对应的函数,模拟任务被连续调度执行的过程。
此示例实现了一个简单的任务调度器,通过循环链表结构,可以公平地调度任务,并支持任务的增删。这在嵌入式系统中可以用于管理有限的周期性任务执行。