C语言中带头双向循环链表基本操作的实现详解

C语言中带头双向循环链表基本操作的实现详解

什么是带头双向循环链表

带头双向循环链表是一种常见的数据结构,在实际开发中也经常会用到。带头双向循环链表可以看作是一种特殊的链表,相对于普通链表,它具有以下特点:

  1. 它有一个头结点,头结点不存储数据,它的作用是指向链表中的第一个节点。

  2. 每个节点都有一个前驱指针prev和一个后继指针next,用于指向前一个节点和后一个节点。

  3. 最后一个节点的后继指针指向头结点,第一个节点的前驱指针也指向头结点,从而形成一个循环链表。

带头双向循环链表的结构如下:

typedef struct DNode {
    int data;
    struct DNode *prev;
    struct DNode *next;
} DNode, *DLinkList;

typedef struct DNodeWithHead {
    int length; //存储链表的长度
    struct DNode *header;
} DList, *DLinkedList;

基本操作及其实现

1. 初始化链表

初始化带头双向循环链表,需要为链表分配内存空间,并且将头结点的prev和next都指向自身。

DLinkedList init() {
    DLinkedList list = (DLinkedList)malloc(sizeof(DList));
    list->length = 0;
    list->header = (DNode *)malloc(sizeof(DNode));
    list->header->prev = list->header;
    list->header->next = list->header;

    return list;
}

2. 插入节点

向带头双向循环链表中插入节点,需要先判断插入的位置是否合法,然后才能进行插入操作。这里以在指定位置p后插入一个新节点为例。

int insert(DLinkedList list, int p, int data) {
    if (p < 1 || p > list->length + 1) {
        return 0; //插入位置不合法
    }

    DNode *node = (DNode *)malloc(sizeof(DNode));
    node->data = data;

    DNode *pre = list->header; //pre指向头节点
    while (p-- > 1) {
        pre = pre->next; //pre指向要插入位置的前一个节点
    }

    node->next = pre->next; //新节点的后继指向插入位置的后一个节点
    pre->next->prev = node; //插入位置的后一个节点的前驱指向新节点
    pre->next = node; //插入位置的前一个节点的后继指向新节点
    node->prev = pre; //新节点的前驱指向插入位置的前一个节点

    list->length++; //链表长度加一
    return 1;
}

3. 删除节点

在带头双向循环链表中删除节点,需要先判断删除的位置是否合法,然后才能进行删除操作。这里以删除指定位置p上的节点为例。

int deleteNode(DLinkedList list, int p) {
    if (p < 1 || p > list->length) {
        return 0; //删除位置不合法
    }

    DNode *pre = list->header; //pre指向头节点
    while (p-- > 1) {
        pre = pre->next; //pre指向要删除的节点的前一个节点
    }

    DNode *del = pre->next; //del指向要删除的节点
    pre->next = del->next; //删除节点的前驱指向删除节点的后继
    del->next->prev = pre; //删除节点的后继指向删除节点的前驱
    free(del); //释放要删除的节点的内存

    list->length--; //链表长度减一
    return 1;
}

示例

下面给出两个例子来说明带头双向循环链表的使用。

示例1:循环队列

带头双向循环链表可以用来实现循环队列。在循环队列中,队列的队尾指针需要满足环形的特性,因此我们可以借助带头双向循环链表的结构来实现循环队列。以下是循环队列的代码实现:

typedef struct {
    DLinkedList list; //带头双向循环链表
    int rear; //队尾指针
} Queue, *QueuePtr;

QueuePtr initQueue() {
    QueuePtr queue = (QueuePtr)malloc(sizeof(Queue));
    queue->list = init();
    queue->rear = 0;
    return queue;
}

int isEmpty(QueuePtr queue) {
    return queue->list->length == 0;
}

int enqueue(QueuePtr queue, int data) {
    if (insert(queue->list, queue->list->length + 1, data)) {
        queue->rear = (queue->rear + 1) % queue->list->length; //更新队尾指针
        return 1;
    }

    return 0;
}

int dequeue(QueuePtr queue) {
    if (isEmpty(queue)) {
        return 0;
    }

    int data = queue->list->header->next->data;
    deleteNode(queue->list, 1);
    queue->rear--; //更新队尾指针
    return data;
}

示例2:LRU缓存

LRU(Least Recently Used)是一种缓存淘汰算法,其原理是根据数据最后一次被访问的时间来决定何时从缓存中淘汰数据。带头双向循环链表可以用来实现LRU缓存,我们可以将链表的头部作为最近访问的数据,尾部作为最久未访问的数据。以下是LRU缓存的代码实现:

typedef struct {
    DLinkedList list; //带头双向循环链表
    int capacity; //缓存大小
} LRUCache, *LRUCachePtr;

LRUCachePtr initCache(int capacity) {
    LRUCachePtr cache = (LRUCachePtr)malloc(sizeof(LRUCache));
    cache->list = init();
    cache->capacity = capacity;
    return cache;
}

int get(LRUCachePtr cache, int key) {
    DNode *node = cache->list->header->next;
    while (node != cache->list->header) {
        if (node->data == key) {
            deleteNode(cache->list, getPos(cache->list, key));
            insert(cache->list, 1, key); //将访问的数据移动到链表头部
            return key;
        }

        node = node->next;
    }

    return -1; //如果缓存中不存在该数据,则返回-1
}

int put(LRUCachePtr cache, int key) {
    int pos = getPos(cache->list, key);
    if (pos > 0) { //如果缓存中已经存在该数据,则将其移动到链表头部
        deleteNode(cache->list, pos);
        insert(cache->list, 1, key);
        return key;
    }

    if (cache->list->length >= cache->capacity) { //如果缓存已满,则淘汰最久未被访问的数据
        deleteNode(cache->list, cache->list->length);
    }

    insert(cache->list, 1, key);
    return key;
}

总结

带头双向循环链表是一种常用的数据结构,在实际开发中也经常会用到。本文详细讲解了带头双向循环链表的基本操作及其实现,并通过两个示例简单介绍了带头双向循环链表的应用。希望本文能够对大家理解带头双向循环链表的使用和原理有所帮助。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言中带头双向循环链表基本操作的实现详解 - Python技术站

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

相关文章

  • hash值破解工具(findmyhash与hash-identifier破解hash值)

    hash值破解工具(findmyhash与hash-identifier破解hash值) 哈希值是一种加密技术,用于将任意长度的数据转换为固定长度的数据。哈希值通常于验证数据的完整性和安全性。在本攻略中,我们将介两个常用的哈希值破解工具:findhash 和 hash-identifier,并提供两个示例说明。 findmyhash findmyhash 是…

    other 2023年5月6日
    00
  • Java递归寻路实现,你真的理解了吗

    Java递归寻路实现,你真的理解了吗 什么是递归寻路 递归寻路是指在迷宫等场景下,从起点开始,不断地试探路径并标记已经探测的路径,直到找到终点或是所有可达路径都已探测过的过程。 实现思路 在 Java 中,可以通过递归函数来实现寻路的过程。具体来说,我们可以编写下面这个函数 findPath: public static boolean findPath(i…

    other 2023年6月27日
    00
  • ping 127.0.0.1和ping本地ip分别测试什么?

    ping 127.0.0.1和ping本地ip分别测试什么? 在计算机网络中,ping命令用于测试网络连接是否正常。ping 127.0.0.1和ping本地IP是两种常见的测试方式,本文将为您提供一份完整攻略,介绍ping命令的基本用法和这两种测试方式的区别。 概念介绍 ping命令 ping命令是一个常用的网络工具,用于测试网络连接是否正常。ping命令…

    other 2023年5月5日
    00
  • matlab中拼接字符串的三种方法

    关于MATLAB:拼接字符串的三种方法 在MATLAB中,我们经常需要拼接字符串。本攻略将详细介绍MATLAB中拼接字符串的三种方法,并提供两个示例。 方法1:使用字符串数组 我们使用字符串数组来拼接字符串。以下是具体步骤: 创建一个字符串数组。 使用字符串数组的join方法拼接字符串。 以下是一个示例: str = ["Hello", …

    other 2023年5月9日
    00
  • Win10应用程序无法正常启动提示错误0xc000007b解决方法

    问题描述: 在使用Win10系统时,有时会出现应用程序无法正常启动的情况,提示错误代码为0xc000007b。这可能会让用户感到非常苦恼,因为发生这种情况时,无法使用相关的应用程序。 问题的原因: 通常,应用程序无法正常启动的原因是由于系统丢失或损坏了一些必要的系统文件,或是电脑缺少一些必要的运行库文件。另外,有些应用程序可能是32位程序,而运行在64位系统…

    other 2023年6月25日
    00
  • win10 Build 9865怎么更新升级? win10 9865下载更新教程

    Win10 Build 9865 更新升级攻略 1. 检查更新 首先,我们需要检查是否有可用的更新。请按照以下步骤进行操作: 打开“设置”应用程序。你可以通过点击任务栏上的“开始”按钮,然后点击“设置”图标来打开它。 在“设置”窗口中,点击“更新和安全”选项。 在左侧导航栏中,选择“Windows 更新”。 在右侧窗格中,点击“检查更新”按钮。 示例说明:如…

    other 2023年8月3日
    00
  • Microsoft VBScript 编译器错误 错误 ‘800a03e9’ 内存不够的解决方法

    首先,这个错误表示VBScript编译器尝试运行时没有足够的可用内存。下面是完整的解决方法: 1. 参数优化 这个错误通常是由脚本中使用了太多的变量或数组所致。可以通过优化一下参数来尝试解决这个问题。例如: ‘ 确认输入参数是否正确 if Wscript.Arguments.Count < 2 then Wscript.Echo "Usage…

    other 2023年6月26日
    00
  • vmware虚拟机安装centos7图文教程

    VMware虚拟机安装CentOS 7图文教程 如果你想在自己的电脑上体验安装Linux系统的乐趣,但又不想对电脑进行操作,那么使用虚拟机是最佳选择。本文将详细介绍如何使用VMware虚拟机安装CentOS 7系统。 步骤一:安装VMware Workstation 首先你需要安装VMware Workstation虚拟机软件,官方网站提供了Windows和…

    其他 2023年3月28日
    00
合作推广
合作推广
分享本页
返回顶部