C语言超详细讲解双向带头循环链表

C语言双向带头循环链表

基本概念

带头双向循环链表是指在双向循环链表的基础上,在头节点前面添加一个头结点。这个头结点不存储任何数据,只是为了方便对链表进行操作。循环链表则是在单向或双向链表的基础上,使链表的头节点与尾节点相连,形成一个环。

综合这两种链表,就构成了“双向带头循环链表”这种数据结构。双向带头循环链表是一种灵活性较高的数据结构,支持前插、后插、前删、后删等多种操作。

链表节点结构

在本文实现的双向带头循环链表中,链表节点包含了数据和指向前驱节点和后继节点的指针。

typedef int datatype;                          // 假设链表储存的数据类型为int
typedef struct node {
    datatype data;                             // 数据域
    struct node *prior, *next;                  // 指向前驱节点和后继节点的指针
} ListNode, *PListNode;                        // 将ListNode定义为结构体类型,PListNode定义为指向结构体ListNode的指针类型

初始化链表

初始化操作初始化链表,创建头节点,让头节点的前驱节点和后继节点都指向自身。

PListNode initList() {
    PListNode head = (PListNode)malloc(sizeof(ListNode));    // 分配一个头节点,并使head指向它
    head->prior = head->next = head;
    return head;
}

插入节点

链表的插入操作一般分为前插和后插,分别表示将节点插入到当前位置的前面或后面。

后插

后插操作是指在当前节点后面插入一个新节点。具体步骤如下:

  1. 创建一个新的节点,将新节点的前驱节点指向当前节点,将新节点的后继节点指向当前节点的后继节点。
  2. 将当前节点的后继节点的前驱节点指向新节点,将当前节点的后继节点指向新节点。
void insertAfter(PListNode pos, datatype value) {
    PListNode new_node = (PListNode)malloc(sizeof(ListNode));    // 创建新节点
    new_node->data = value;
    new_node->next = pos->next;
    new_node->prior = pos;
    pos->next->prior = new_node;
    pos->next = new_node;
}

前插

前插操作是指在当前节点前面插入一个新节点。具体步骤如下:

  1. 创建一个新的节点,将新节点的前驱节点指向当前节点的前驱节点,将新节点的后继节点指向当前节点。
  2. 将当前节点的前驱节点的后继节点指向新节点,将当前节点的前驱节点指向新节点。
void insertBefore(PListNode pos, datatype value) {
    PListNode new_node = (PListNode)malloc(sizeof(ListNode));    // 创建新节点
    new_node->data = value;
    new_node->next = pos;
    new_node->prior = pos->prior;
    pos->prior->next = new_node;
    pos->prior = new_node;
}

删除节点

链表的删除操作一般分为前删和后删,分别表示将当前位置的前驱节点或后继节点删除。

后删

后删操作是指删除当前节点的后继节点。具体步骤如下:

  1. 将当前节点的后继节点的后继节点的前驱节点指向当前节点。
  2. 将当前节点的后继节点的前驱节点指向空,将当前节点的后继指针指向后继节点的后继节点。
  3. 释放后继节点。
void deleteAfter(PListNode pos) {
    PListNode to_delete = pos->next;
    pos->next = to_delete->next;
    to_delete->next->prior = pos;
    to_delete->prior = NULL;
    to_delete->next = NULL;
    free(to_delete);
}

前删

前删操作是指删除当前节点的前驱节点。具体步骤如下:

  1. 将当前节点的前驱节点的前驱节点的后继节点指向当前节点。
  2. 将当前节点的前驱节点的后继节点指向空,将当前节点的前驱指针指向前驱节点的前驱节点。
  3. 释放前驱节点。
void deleteBefore(PListNode pos) {
    PListNode to_delete = pos->prior;
    pos->prior = to_delete->prior;
    to_delete->prior->next = pos;
    to_delete->prior = NULL;
    to_delete->next = NULL;
    free(to_delete);
}

示例说明

示例1

以下是一个将数列 {1, 2, 3, 4} 存入链表中的例子

int main() {
    PListNode head = initList();
    for (int i = 1; i <= 4; i++) {
        insertAfter(head, i);
    }

    PListNode ptr = head->next;

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

    return 0;
}

输出结果为:

1 2 3 4

示例2

以下是一个在指定位置插入一个节点的例子

int main() {
    PListNode head = initList();
    for (int i = 1; i <= 4; i++) {
        insertAfter(head, i);
    }

    insertBefore(head->next->next, 5);

    PListNode ptr = head->next;

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

    return 0;
}

输出结果为:

1 2 5 3 4

总结

双向带头循环链表是一种优秀的数据结构,通过正确的应用,可以使程序更简洁、易于理解和效率更高。在实际编程中,应根据需求选择合适的数据结构进行使用。

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

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

相关文章

  • 数据结构之线性表

    Linear_list 类型定义 一个线性表是n个数据元素的有限序列,线性表中的元素个数n定义为线性表的长度,n=0时成为空表;抽象数据类型: InitList(&L) //构造空线性表L DestroyList(&L) //销毁线性表L ClearList(&L) //将L重置为空表 ListEmpty(L) //若L为空表返回TR…

    算法与数据结构 2023年4月25日
    00
  • Java数据结构之单链表的实现与面试题汇总

    Java数据结构之单链表的实现与面试题汇总 一、前言 单链表是数据结构中最基础的数据结构之一,也是在面试时经常会考察的一个知识点。本文将详细介绍单链表的实现过程,并对常见的单链表面试题进行总结,帮助大家深入了解单链表的原理和应用。 二、单链表的实现 单链表是由一些列节点构成的,每个节点包括一个数据和一个指向下一个节点的指针。下面我们将实现一个简单的单链表,并…

    数据结构 2023年5月17日
    00
  • 自学1

    Problem1 明明的随机数 ## 题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了 N 个 1 到 1000 之间的随机整数 (N <= 100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应着不同的学生的学号。然后再把这些数从小到大排序,按照排好的顺序去找同学做调查。请你协助明明完成“…

    算法与数据结构 2023年4月24日
    00
  • 详解Pytorch中的tensor数据结构

    详解Pytorch中的Tensor数据结构 在Pytorch中,Tensor是一种重要的数据结构,它是一个多维数组(类似于NumPy的ndarray),并且支持GPU加速操作。在本文中,我们将详细介绍Pytorch中的Tensor数据结构,包括如何创建、初始化、检索和修改Tensor对象。 创建Tensor对象 创建Tensor对象的方法有很多种。以下是一些…

    数据结构 2023年5月17日
    00
  • 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解

    解析从源码分析常见的基于Array的数据结构动态扩容机制的详解 什么是动态扩容机制 动态扩容机制是指,当一个数据结构达到其容量限制时,自动增加容量大小以继续存储新的数据。在动态扩容时,需要考虑到时间和空间的平衡,因为扩容需要分配新的内存空间,在处理大量数据时,需要尽可能减少空间浪费和分配内存的时间消耗。 基于Array的数据结构 Array是一种连续存储的数…

    数据结构 2023年5月17日
    00
  • JavaScript数据结构Number

    JavaScript数据结构Number 简介 JavaScript中的Number是一种表示数字的数据类型,包括整数和浮点数。Number类型的值是不可变的。 数字类型(Number)的创建 数字类型可以通过直接赋值的方式创建,如: let num = 10; // 整数 let floatNum = 3.14; // 浮点数 另外,JavaScript还…

    数据结构 2023年5月17日
    00
  • 图计算引擎分析–GridGraph

    作者:京东科技 李永萍 GridGraph:Large-Scale Graph Processing on a Single Machine Using 2-Level Hierarchical Partitioning 图计算框架 图计算系统按照计算方式划分可分为:单机内存图处理系统,单机核外图处理系统,分布式内存图处理系统,分布式核外图处理系统。本文将详…

    算法与数据结构 2023年4月20日
    00
  • Java数据结构之堆(优先队列)详解

    Java数据结构之堆(优先队列)详解 概述 堆是一种基于树的数据结构,它可以用来解决很多问题,例如排序、优先队列等。在堆中,每个节点的值都小于或等于它的子节点的值。堆分为两种类型:最大堆和最小堆。在最大堆中,根节点的值最大;而在最小堆中,根节点的值最小。 堆的操作主要有以下两种: 插入:将一个元素插入到堆中,需要维护堆的性质,即节点的值小于或等于子节点的值。…

    数据结构 2023年5月17日
    00
合作推广
合作推广
分享本页
返回顶部