c语言实例 -- 循环链表

server/2024/10/9 2:07:41/

要求:

创建一个循环链表

下面是一个简单的循环链表(循环单链表)的C语言实现。循环链表是指链表的最后一个节点的指针指向第一个节点,形成一个环形结构。这种结构的优点是在一些特定的场景可以简化操作逻辑。

循环链表的基本操作

  1. 初始化循环链表
  2. 插入节点
  3. 删除节点
  4. 打印链表
  5. 销毁链表
#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函数循环调用每个任务对应的函数,模拟任务被连续调度执行的过程。

此示例实现了一个简单的任务调度器,通过循环链表结构,可以公平地调度任务,并支持任务的增删。这在嵌入式系统中可以用于管理有限的周期性任务执行。


http://www.ppmy.cn/server/129040.html

相关文章

蓝桥杯—STM32G431RBT6(IIC通信--EEPROM(AT24C02)存储器进行通信)

一、什么是IIC&#xff1f;24C02存储器有什么用&#xff1f; IIC &#xff08;IIC 是半双工通信总线。半双工意味着数据在某一时刻只能沿一个方向传输&#xff0c;即发送数据的时候不能接收数据&#xff0c;接收数据的时候不能发送数据&#xff09;即集成电路总线&#xff08;…

MQ高级:RabbitMQ小细节

在之前的学习中&#xff0c;我们只介绍了消息的发送&#xff0c;但是没有考虑到异常的情况&#xff0c;今天我们就介绍一些异常情况&#xff0c;和细节的部分。 目录 生产者可靠性 生产者重连 生产者确认 MQ可靠性 持久化 Lazy Queue 消费者可靠性 消费者确认机制 失…

Spring Boot:打造下一代医院管理系统

3系统分析 3.1可行性分析 通过对本医院管理系统实行的目的初步调查和分析&#xff0c;提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本医院管理系统采用JAVA作为开发语言&#xff0c;Spring Boot框…

【项目安全设计】软件系统安全设计规范和标准(doc原件)

1.1安全建设原则 1.2 安全管理体系 1.3 安全管理规范 1.4 数据安全保障措施 1.4.1 数据库安全保障 1.4.2 操作系统安全保障 1.4.3 病毒防治 1.5安全保障措施 1.5.1实名认证保障 1.5.2 接口安全保障 1.5.3 加密传输保障 1.5.4终端安全保障 资料获取&#xff1a;私信或者进主页。…

Python知识点:如何使用Google Cloud IoT与Python进行边缘计算

开篇&#xff0c;先说一个好消息&#xff0c;截止到2025年1月1日前&#xff0c;翻到文末找到我&#xff0c;赠送定制版的开题报告和任务书&#xff0c;先到先得&#xff01;过期不候&#xff01; 如何使用Google Cloud IoT与Python进行边缘计算 边缘计算作为一种新兴的计算模式…

软件工程的详细学习要点和学习方向

软件工程的详细学习要点和学习方向主要包括以下几个方面&#xff1a; 学习要点 1. 编程语言基础&#xff1a; - 熟练掌握至少一种编程语言&#xff0c;如Java、Python、C等。 - 学习编程语言的语法、特性、常用库函数&#xff0c;并具备编写、调试和优化代码的能力。 …

SpringMVC2~~~

数据格式化 提交数据(比如表单)&#xff0c;对提交的数据进行转换和处理 基本数据类型可以和字符串自动转换 <a href"<%request.getContextPath()%>/addMonsterUI">添加妖怪</a> Controller Scope(value "prototype") public class …

掌握C#核心概念:类、继承、泛型等

C# 是一门功能强大且灵活的面向对象编程语言&#xff0c;它结合了许多现代编程语言的特点和特性。无论你是编程新手&#xff0c;还是有经验的开发者&#xff0c;理解C#中的核心概念都是非常重要的。本文将介绍C#中的类与对象、构造函数和析构函数、方法的重载与重写、继承与多态…