c语言实例 -- 循环链表

要求:

创建一个循环链表

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

循环链表的基本操作

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

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

相关推荐
zh_xuan25 分钟前
c++ 单例模式
开发语言·c++·单例模式
老胖闲聊1 小时前
Python Copilot【代码辅助工具】 简介
开发语言·python·copilot
Blossom.1181 小时前
使用Python和Scikit-Learn实现机器学习模型调优
开发语言·人工智能·python·深度学习·目标检测·机器学习·scikit-learn
曹勖之1 小时前
基于ROS2,撰写python脚本,根据给定的舵-桨动力学模型实现动力学更新
开发语言·python·机器人·ros2
apocelipes1 小时前
Linux c 运行时获取动态库所在路径
linux·c语言·linux编程
豆沙沙包?2 小时前
2025年- H77-Lc185--45.跳跃游戏II(贪心)--Java版
java·开发语言·游戏
军训猫猫头2 小时前
96.如何使用C#实现串口发送? C#例子
开发语言·c#
liuyang-neu2 小时前
java内存模型JMM
java·开发语言
int型码农3 小时前
数据结构第八章(一) 插入排序
c语言·数据结构·算法·排序算法·希尔排序
我很好我还能学4 小时前
【面试篇 9】c++生成可执行文件的四个步骤、悬挂指针、define和const区别、c++定义和声明、将引用作为返回值的好处、类的四个缺省函数
开发语言·c++