C语言循环链表的原理与使用操作

C语言循环链表是一种基于链表数据结构的可循环访问的存储方式。与线性表相比,链表能够优化数据的插入和删除操作的效率,并且支持动态的内存分配。而循环链表则定义了表头尾相接,最后一个节点指向第一个节点的链表。下面将详细讲解循环链表的原理、使用操作及其实现过程,以及两个示例进行说明。

原理

循环链表是由多个节点组成的链式结构,每个节点包含自身的数据和指向下一个节点的指针。其最后一个节点的指针指向第一个节点,形成了一个环形结构。这种结构具有更好的复用性和高效性,可以被广泛地应用于各个领域的数据结构。

实现步骤

  1. 定义链表节点结构体

    c
    typedef struct node {
    int data;
    struct node* next;
    } Node;

  2. 插入节点

    首先需要定义一个指向链表头的指针,开始时为空。

    c
    Node* head = NULL;

    要插入一个节点,需要先找到要插入的位置,在循环链表中,插入节点的方式与单链表和双链表相同。

    ```c
    void insert(Node head, int data, int pos) {
    Node
    new_node = (Node
    )malloc(sizeof(Node));
    new_node->data = data;
    new_node->next = NULL;

    if (*head == NULL) { // 链表为空,直接插入
        *head = new_node;
        (*head)->next = *head;
        return;
    }
    
    if (pos == 0) { // 插入头部
        new_node->next = (*head)->next;
        (*head)->next = new_node;
        int temp = (*head)->data;
        (*head)->data = new_node->data;
        new_node->data = temp;
        return;
    }
    
    Node* current = (*head);
    for (int i = 1; i < pos; i++) {
        current = current->next;
    }
    
    new_node->next = current->next;
    current->next = new_node;
    

    }
    ```

  3. 删除节点

    与插入节点类似,删除节点也需要找到要删除的位置。因为需要删除的是链表节点,而链表的节点是通过指针实现的,因此需要记录上一个节点的指针。

    ```c
    void delete (Node* head, int pos) {
    if (
    head == NULL) { // 链表为空,什么也不做
    return;
    }

    Node* current = (*head);
    Node* previous = NULL;
    
    if (pos == 0) { // 删除头部节点
        while (current->next != *head) {
            current = current->next;
        }
        Node* node_to_delete = *head;
        current->next = (*head)->next;
        *head = (*head)->next;
        free(node_to_delete);
        return;
    }
    
    for (int i = 1; i <= pos; i++) {
        previous = current;
        current = current->next;
    
        if (current == *head && i != pos) { // 节点不存在
            return;
        }
    }
    
    previous->next = current->next;
    free(current);
    

    }
    ```

  4. 遍历链表

    循环链表的遍历有一个特殊之处,因为循环链表的尾部是指向头部的,因此需要对链表头特殊处理。

    ```c
    void display(Node* head) {
    if (head == NULL) { // 链表为空
    printf("List is empty.\n");
    return;
    }

    Node* current = head;
    do {
        printf("%d ", current->data);
        current = current->next;
    } while (current != head);
    printf("\n");
    

    }
    ```

示例1

下面的示例描述了如何创建一个循环链表,并将数据插入到链表中。

int main() {
    Node* head = NULL;
    int choice, data, position;
    printf("Welcome to the circular linked list implementation.\n");
    while (1) {
        printf("Enter 1 to insert a node\n");
        printf("Enter 2 to delete a node\n");
        printf("Enter 3 to display the list\n");
        printf("Enter 4 to exit\n");
        scanf("%d", &choice);
        switch (choice) {
            case 1:
                printf("Enter the data:");
                scanf("%d", &data);
                printf("Enter the position:");
                scanf("%d", &position);
                insert(&head, data, position);
                break;
            case 2:
                printf("Enter the position:");
                scanf("%d", &position);
                delete (&head, position);
                break;
            case 3:
                display(head);
                break;
            case 4:
                printf("Bye!\n");
                return 0;
            default:
                printf("Invalid choice! Please try again.\n");
        }
        printf("\n");
    }
}

示例2

下面是一个示例,使用循环链表实现一个循环队列。

#define MAX_QUEUE_SIZE 10

typedef struct queue {
    int items[MAX_QUEUE_SIZE];
    int front;
    int rear;
} Queue;

Queue* create_queue();
void enqueue(Queue* queue, int item);
int dequeue(Queue* queue);
void display(Queue* queue);

int main() {
    Queue* queue = create_queue();
    int choice, item;
    printf("Welcome to the circular queue implementation.\n");
    while (1) {
        printf("Enter 1 to enqueue an item\n");
        printf("Enter 2 to dequeue an item\n");
        printf("Enter 3 to display the queue\n");
        printf("Enter 4 to exit\n");
        scanf("%d", &choice);
        switch (choice) {
            case 1:
                printf("Enter the item:");
                scanf("%d", &item);
                enqueue(queue, item);
                break;
            case 2:
                item = dequeue(queue);
                if (item != -1) {
                    printf("Dequeued item is %d\n", item);
                }
                break;
            case 3:
                display(queue);
                break;
            case 4:
                printf("Bye!\n");
                return 0;
            default:
                printf("Invalid choice! Please try again.\n");
        }
        printf("\n");
    }
}

Queue* create_queue() {
    Queue* queue = (Queue*)malloc(sizeof(Queue));
    queue->front = -1;
    queue->rear = -1;
    return queue;
}

void enqueue(Queue* queue, int item) {
    if ((queue->rear + 1) % MAX_QUEUE_SIZE == queue->front) { // 队列满
        printf("Queue is full.\n");
        return;
    }
    if (queue->front == -1) { // 队列为空
        queue->front = 0;
        queue->rear = 0;
    } else {
        queue->rear = (queue->rear + 1) % MAX_QUEUE_SIZE;
    }
    queue->items[queue->rear] = item;
}

int dequeue(Queue* queue) {
    if (queue->front == -1) { // 队列为空
        printf("Queue is empty.\n");
        return -1;
    }
    int item = queue->items[queue->front];
    if (queue->front == queue->rear) { // 队列中只有一个元素
        queue->front = -1;
        queue->rear = -1;
    } else {
        queue->front = (queue->front + 1) % MAX_QUEUE_SIZE;
    }
    return item;
}

void display(Queue* queue) {
    if (queue->front == -1) { // 队列为空
        printf("Queue is empty.\n");
        return;
    }
    int i;
    for (i = queue->front; i != queue->rear; i = (i + 1) % MAX_QUEUE_SIZE) {
        printf("%d ", queue->items[i]);
    }
    printf("%d ", queue->items[i]);
    printf("\n");
}

以上两个示例详细说明了循环链表的原理、使用操作和实现过程,希望能对读者有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言循环链表的原理与使用操作 - Python技术站

(0)
上一篇 2023年5月24日
下一篇 2023年5月24日

相关文章

  • 如何理解C++指针常量和常量指针

    下面给你详细讲解如何理解C++指针常量和常量指针。 1. 指针常量 1.1 概念介绍 指针常量是指一个指针被定义为常量(值不能被改变),而指针所指向的变量的值可以变化。在定义指针常量时,必须把指针初始化为某个地址。 1.2 示例说明 以下是一个指针常量的示例: #include <iostream> using namespace std; in…

    C 2023年5月23日
    00
  • 将Emacs打造成强大的Python代码编辑工具

    当你选择使用 Emacs 作为 Python 的编辑器时,你会拥有一个非常强大的工具,Emacs 配合一些插件和定制的设置,可以满足你对 Python 编辑器的所有需求。 下面是将 Emacs 打造成强大的 Python 代码编辑工具的攻略: 安装 Python 模式 首先,你需要安装一个称为“Python 模式”的软件包。该软件包提供了一些有用的功能,如代…

    C 2023年5月23日
    00
  • jsoup 框架的使用小结

    下面来详细讲解一下“jsoup 框架的使用小结”的完整攻略。 什么是jsoup框架 jsoup是一个Java的HTML解析器,可直接解析某个URL地址、HTML文本内容。它提供了类似于JQuery的CSS选择器,用于从HTML解析出DOM,也可用于HTML的提取和转换。 jsoup框架的安装和使用步骤 安装方式 直接从官网下载jar包:https://jso…

    C 2023年5月23日
    00
  • C语言实现纸牌24点小游戏

    C语言实现纸牌24点小游戏 简介 纸牌24点是一种常见的解谜游戏,在该游戏中,玩家需要选取若干个数值不同的纸牌,通过不断组合计算,使其总和等于24。该游戏是一款简单却又富有乐趣的解谜游戏,特别适合喜欢数学和逻辑思维的人群。 本文将演示如何使用C语言实现纸牌24点小游戏。读者需具备C语言基础和基本的编程能力。 实现方法 在C语言中,可以使用递归的方法来实现该游…

    C 2023年5月22日
    00
  • 硬件工程师培训教程(六)

    硬件工程师培训教程(六)是一篇针对硬件工程师培训的教程,主要介绍了硬件的电路设计、PCB设计、样板制作和调试等方面的知识。 以下是该教程的完整攻略: 硬件工程师培训教程(六)- 完整攻略 1. 电路设计 电路设计是硬件工程师的核心任务之一,它涉及到电路原理图的绘制、元件的选用和电路参数计算等方面。在进行电路设计时,应该注意以下几点: 选择合适的元件:根据电路…

    C 2023年5月23日
    00
  • C 程序 查找数组元素的总和

    C程序 查找数组元素的总和 简介 本程序通过输入一个包含n个数的整型数组,求出数组中所有元素的总和。 使用攻略 编译环境 本程序使用C语言编写,建议使用gcc编译器,在Linux环境下执行。 输入数组 程序使用scanf函数从标准输入中读入数组元素,用户需输入n个整型数值,以空格或换行符分隔。 示例输入: 5 1 2 3 4 5 程序设计 本程序使用for循…

    C 2023年5月9日
    00
  • C++中vector的用法实例解析

    C++中vector的用法实例解析 什么是vector vector是C++ STL(Standard Template Library)中的一个容器,它是一个动态数组,可以自动扩展空间,并提供随机访问和快速尾部插入/删除等操作。vector内部存储的元素在内存中是连续存储的,因此可以通过数组下标直接访问元素,效率非常高。 vector的基本用法 创建一个v…

    C 2023年5月22日
    00
  • C语言字符串声明

    C语言字符串可以理解为是由若干个字符(char)组成的数组,它以null字节为结尾。在C语言中,声明字符串变量需要特殊的语法,下面是一份讲解C语言字符串声明的完整使用攻略。 声明字符串变量 在C语言中,声明字符串变量需要使用char类型以及一对双引号(“”). 这里有几个重点需要注意: 字符串中的每一个字符都分配了存储空间。 字符串末尾会自动添加一个null…

    C 2023年5月9日
    00
合作推广
合作推广
分享本页
返回顶部