双向链表是一种比单向链表更为灵活的数据结构,与单向链表相比可以有更多的应用场景,本文讨论双向链表的基本概念及实现方法,并着重介绍使用GLib的GList实现单向链表的方法及步骤,本文给出了多个实际范例源代码,旨在帮助学习基于GLib编程的读者较快地掌握GList的使用方法,本文程序在 ubuntu 20.04 下编译测试完成,gcc 版本号 9.4.0;本文适合初学者阅读。
1 双向链表及其实现
-
在文章《单向链表以及如何使用GLib中的GSList实现单向链表》中,介绍了单向链表以及基于 GLib 实现单向链表的方法,建议阅读本文前先阅读这篇文章;
-
在文章《使用GLib进行C语言编程的实例》中,简单介绍了 GLib,建议阅读本文前先阅读这篇文章;
-
双向链表(Doubly Linked List)是一种链式数据结构,每个节点包含三个主要部分:
- 数据部分:存储节点的数据
- 前向指针:指向链表中的下一个节点
- 后向指针:指向链表中的上一个节点
-
可以看出,和单向链表相比较,双向链表多了一个指向前一个节点的指针
-
双向链表的基本特性
- 双向性:与单向链表不同,双向链表允许从两个方向遍历,可以从头节点向尾节点遍历,也可以从尾节点向头节点遍历;
- 动态大小:双向链表的大小可以动态增长或缩小,不需要提前定义大小;
- 节点插入和删除:在双向链表中,插入和删除节点操作相对简单,因为每个节点都有指向前后节点的指针;
-
双向链表的节点结构:
struct Node { int data; // 数据部分 struct Node *next; // 指向下一个节点的指针 struct Node *prev; // 指向前一个节点的指针 };
-
双向链表的基本操作
- 插入节点:可以在链表的开头、结尾或任意位置插入节点;
- 删除节点:可以删除链表中的任意节点,操作相对简单,因每个节点都知道其前一个和后一个节点;
- 遍历链表:可以从头到尾遍历链表(正向遍历)或从尾到头遍历链表(反向遍历);
-
与单向链表相比,双向链表有以下特点:
- 由于数据结构中增加了后向指针,使链表可以双向遍历,而单向链表仅能单向遍历;
- 通过后向指针可以直接访问前一个节点,与单向链表相比,可以简化节点删除操作的复杂度;
- 在插入节点时,比单向链表更快捷更灵活;
- 与单向链表相比,由于增加了后向指针,内存开销增加;
- 与单向链表相比,双向链表需要操作两个指针,其操作和维护的复杂度要高一些;
-
总的来说,双向链表比单向链表更加灵活,适用场景也要多一些。;
-
下面程序是一个简单的双向链表的 C 语言标准库实现,dllist-c.c(点击文件名下载源程序)
-
编译:
gcc -Wall -g dllist-c.c -o dllist-c
-
运行:
./dllist-c
-
该程序实现了双向链表的插入、删除以及正向遍历;
-
该程序首先建立一个双向链表,并在链表中加入 4 个节点,数据分别为:1、2、3、5,然后显示整个链表;
-
在第 3 个节点(数据为 3,索引号为 2)的后面插入节点,数据为 4,然后显示整个链表;
-
将第 3 个节点(数据为 3,索引号为 2)删除,然后显示整个链表;
-
最后释放整个链表;
-
运行截图:
2 GLib 中双向链表结构 GList
- GLib API version 2.0 手册 (点击查看手册)
- GLib API 手册中 GList 部分 (点击查看手册)
- 在 GLib 中,双向链表是通过 GList 结构体实现的,GList 是