C语言数据结构之双向循环链表的实例

C语言数据结构之双向循环链表的实例

什么是双向循环链表?

双向循环链表是一种链式存储结构。每个节点都包含两个指针域,分别指向前一个节点和后一个节点,形成一个环形结构。双向循环链表可以实现正向和反向遍历,插入和删除节点的时间复杂度为$O(1)$。

双向循环链表的结构体定义

typedef struct Node
{
    ElemType data;
    struct Node *prev;
    struct Node *next;
} Node, *ListNode;

Node表示链表中的一个节点,ElemType为节点中存储的元素的类型。prev和next分别表示指向前一个节点和后一个节点的指针。

双向循环链表的初始化

ListNode initList()
{
    ListNode head = (ListNode)malloc(sizeof(Node));
    head->prev = head->next = head;
    return head;
}

initList()函数用于初始化双向循环链表,在头节点位置分配一个节点空间后,将前驱指针和后继指针都指向头节点,表示链表为空。

双向循环链表的插入

插入在链表头部

void insertHead(ListNode head, ElemType elem)
{
    ListNode node = (ListNode)malloc(sizeof(Node));
    node->data = elem;
    node->next = head->next;
    node->prev = head;
    head->next->prev = node;
    head->next = node;
}

insertHead()函数用于在链表头部插入一个元素。新建一个节点,将节点值赋为elem,将节点的next指向头节点的next,节点的prev指向头节点,然后将头节点的next和头节点的next的prev都指向新节点。

插入在链表尾部

void insertTail(ListNode head, ElemType elem)
{
    ListNode node = (ListNode)malloc(sizeof(Node));
    node->data = elem;
    node->prev = head->prev;
    node->next = head;
    head->prev->next = node;
    head->prev = node;
}

insertTail()函数用于在链表尾部插入一个元素。新建一个节点,将节点值赋为elem,将节点的prev指向头节点的prev,节点的next指向头节点,然后将头节点的prev和头节点的prev的next都指向新节点。

双向循环链表的删除

void deleteNode(ListNode head, ElemType elem)
{
    ListNode cur = head->next;
    while (cur != head)
    {
        if (cur->data == elem)
        {
            cur->prev->next = cur->next;
            cur->next->prev = cur->prev;
            free(cur);
            return;
        }
        cur = cur->next;
    }
}

deleteNode()函数用于删除数据域为elem的节点,遍历链表找到要删除的节点,将这个节点的前一个节点的next指针指向这个节点的后一个节点,同时将这个节点的后一个节点的prev指针指向这个节点的前一个节点。最后释放这个节点的空间。

示例说明

示例一

初始化一个双向循环链表,插入5个元素,分别为1,2,3,4,5。然后从头节点开始遍历链表,输出每个节点的值。

int main()
{
    ListNode list = initList();
    for (int i = 1; i <= 5; i++)
    {
        insertTail(list, i);
    }
    ListNode cur = list->next;
    while (cur != list)
    {
        printf("%d ", cur->data);
        cur = cur->next;
    }
    printf("\n");
    return 0;
}

输出结果为:1 2 3 4 5

示例二

初始化一个双向循环链表,插入5个元素,分别为1,2,3,4,5。然后删除数据域为3的节点之后,从头节点开始遍历链表,输出每个节点的值。

int main()
{
    ListNode list = initList();
    for (int i = 1; i <= 5; i++)
    {
        insertTail(list, i);
    }
    deleteNode(list, 3);
    ListNode cur = list->next;
    while (cur != list)
    {
        printf("%d ", cur->data);
        cur = cur->next;
    }
    printf("\n");
    return 0;
}

输出结果为:1 2 4 5

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言数据结构之双向循环链表的实例 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • 深入了解Java中的类加载机制

    深入了解Java中的类加载机制 1. Java类加载机制概述 Java类加载机制是Java虚拟机(JVM)的一个重要组成部分,负责将.class文件中的字节码加载到JVM内存中,并转换为可执行的Java对象。对于大多数Java开发者来说,类的加载工作是完全透明的,甚至不需要知道Java中的类加载机制的存在。但是,了解Java的类加载机制对于理解Java应用程…

    other 2023年6月20日
    00
  • 【笔记向】package.jsonmain作用

    当然,我很乐意为您提供有关“package.json中main字段的作用”的完整攻略。以下是详细的步骤和两个示例: 1 package.json中main字段的作用 在Node.js应用程序中,package.json文件是一个重要的文件,它包含了应用程序的元数据和依赖项。其中,main字段是package.json文件中的一个重要字段,它指定了应用程序的入…

    other 2023年5月6日
    00
  • 什么是操作系统

    什么是操作系统? 操作系统(Operating System,简称 OS)是一种控制计算机硬件和软件资源的程序集合,它是计算机系统中最基本的系统软件。操作系统提供了操作计算机所必须的各种服务,如用户管理、内存管理、文件管理、进程管理、设备管理等等。 操作系统的功能 按照常见的分类方式,操作系统具有以下主要功能: 进程管理:进程是计算机中正在执行的程序实例,在…

    其他 2023年4月16日
    00
  • QT实现多文件拖拽获取路径的方法

    下面我详细讲解一下“QT实现多文件拖拽获取路径的方法”的完整攻略。 一、背景知识 在 QT 中,拖拽操作主要涉及到以下两个事件: dragEnterEvent(QDragEnterEvent *event):当拖入一个物品时触发该事件。 dropEvent(QDropEvent *event):当放下一个物品时触发该事件。 在 dragEnterEvent …

    other 2023年6月26日
    00
  • MySQL更新存放JSON的字段、\“ 转义成 “的问题描述

    MySQL中可以使用UPDATE语句更新存放JSON的字段。JSON是一种轻量级的数据交换格式,常常用于表示复杂的数据结构。当我们需要更新JSON字段中的值时,可以使用MySQL提供的一些内置函数来实现。 在更新JSON字段时,有时候需要使用到双引号。而MySQL中默认的转义字符是反斜杠(\),所以需要使用双反斜杠(\)来转义双引号。 下面是一个具体的示例,…

    other 2023年6月25日
    00
  • C++类成员构造函数和析构函数顺序示例详细讲解

    C++中类成员的构造函数和析构函数顺序是一个重要的问题。理解正确的顺序可以避免代码出现意外的问题。在这里,我们会详细讲解C++类成员构造函数和析构函数顺序的相关知识。 构造函数和析构函数的顺序 C++中类成员的构造函数和析构函数的顺序如下: 首先,会调用基类的构造函数(如果有的话)。 然后,会调用成员变量的构造函数(按照它们在类中的声明顺序调用)。 最后,调…

    other 2023年6月26日
    00
  • C#将时间转成文件名使用方法

    C#中将时间转成文件名可以通过以下方法实现: 使用DateTime.Now.ToString()方法将当前时间转成字符串。 string fileName = DateTime.Now.ToString("yyyyMMddHHmmssfff"); 通过此方式可以将当前时间转成年月日时分秒毫秒的格式,例如20210712133456005,…

    other 2023年6月26日
    00
  • Flutter有无状态类与State及生命周期详细介绍

    下面是关于Flutter的无状态类与有状态类及其生命周期方法的详细介绍及示例: Flutter有状态类和无状态类 Flutter中的类可以分为有状态和无状态两种。有状态的类可以通过修改自身的状态来动态改变其外观和行为,而无状态类则不具有这种能力。通常情况下,我们会在页面中使用有状态的类,而在内容单一或无需动态变化的组件中使用无状态的类。 无状态类 无状态类是…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部