手撕deque源码,解密双端队列的设计艺术

本文详细剖析了Python标准库中的deque(双端队列)实现,探讨了deque如何通过链表结构和内存块优化两端插入删除的性能。deque的内部结构包括block链表节点,每个节点能存储多个元素,减少了链表指针的开销。通过源码分析,展示了deque对象的创建、添加和移除元素的过程,揭示了deque高效操作的秘密。
摘要由CSDN通过智能技术生成

我们已经学习了 list 对象的内部结构,知道它底层是用动态数组实现的。在 list 头部进行插入或删除,都要挪动其后的所有数据,性能非常差!因此,我们不能将 list 对象作为队列使用。

好在 Python 标准库提供了另一种对象—— deque ,很好地补全了 list 的短板。deque 是一种类似 list 的线性表,但它在两端插入删除数据的时间复杂度都是  ,因而可以作为队列来使用。

from collections import deque

# 创建一个deque对象作为队列
q = deque()

# 数据入队:将其插到末尾
q.append(data)

# 数据出队:从头部弹出
data = q.popleft()

您可能会问了,deque 到底跟 list 有何不同?为何两端都能同时支持  的插入删除呢?

内部结构

这其中的秘密还得到源码中寻找。Python标准库位于源码中的 Lib 目录,collections 模块源码位于 Lib/collections 目录,模块入口文件为 Lib/collections/__init__.py 。打开 __init__.py 可以看到这段代码( 29~34 行):

try:
    from _collections import deque
except ImportError:
    pass
else:
    _collections_abc.MutableSequence.register(deque)

由此可见,deque 是在另一个模块 _collections 中实现的。我们在 Lib 中并没有找到 _collections模块,它很有可能是一个用 C 语言实现的模块。滋补小铺我们回到 Modules 目录看一看,果然找到了 Modules/_collectionsmodule.c 。

这个源码文件就是 deque 实现之所在,不难找到 deque 对象底层结构体定义( 71~96 行):

typedef struct BLOCK {
    struct BLOCK *leftlink;
    PyObject *data[BLOCKLEN];
    struct BLOCK *rightlink;
} block;

typedef struct {
    PyObject_VAR_HEAD
    block *leftblock;
    block *rightblock;
    Py_ssize_t leftindex;       /* 0 <= leftindex < BLOCKLEN */
    Py_ssize_t rightindex;      /* 0 <= rightindex < BLOCKLEN */
    size_t state;               /* incremented whenever the indices move */
    Py_ssize_t maxlen;          /* maxlen is -1 for unbounded deques */
    PyObject *weakreflist;
} dequeobject;

这里的源码以 Python 3.7.4 版本为例,不同版本可能略有差异。

dequeobject 结构体便是 deque 实例对象的底层肉身,可以看到 deque 将自己保存的元素组织成链表结构,难怪在两端增删元素都很快!跟普通链表节点只保存一个元素不同,deque 的链表节点可以保存很多元素。

block 结构体就是 deque 内部的链表节点,顾名思义,它是一个内存块。block 结构体非常简单,只有 3 个字段:

  • leftlink ,左向指针,指向左边(更接近头部)的内存块;

  • rightlink ,右向指针,指向右边(更接近尾部)的内存块;

  • data ,对象指针数组,deque 中的元素就保存在这里;

内存块 block 由 leftlink 和 rightlink 字段串联,组成一个双向链表。block 内存块中的 data 数组,长度由 BLOCKLEN 宏定义决定( 第 21 行 ):

#define
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值