Hello Algo 深度拆解:基于单链表实现队列(LinkedListQueue)——入队出队、O(1) 复杂度与逐行可视化

发布时间:2026/9/8 17:53:46
Hello Algo 深度拆解:基于单链表实现队列(LinkedListQueue)——入队出队、O(1) 复杂度与逐行可视化 Hello Algo 深度拆解基于单链表实现队列LinkedListQueue——入队出队、O(1) 复杂度与逐行可视化【免费下载链接】hello-algo《Hello 算法》动画图解、一键运行的数据结构与算法教程。支持简中、繁中、English、日本語提供 Python, Java, C, C, C#, JS, Go, Swift, Rust, Ruby, Kotlin, TS, Dart 等代码实现项目地址: https://gitcode.com/GitHub_Trending/he/hello-algo本篇以《Hello 算法》日语版 PythonTutor 可视化代码linkedlist_queue.md为骨架讲解如何用**单链表singly linked list**实现先入先出FIFO的队列结构。通过阅读本文你将掌握front/rear双指针的设计思想、push入队、pop出队、peek查看队首等核心操作的实现细节与边界处理并能对照仓库源码与实际运行输出完成一次从数据结构到代码的完整学习闭环。《Hello 算法》在文档中为「队列キュー / queue」一章的每段核心代码都配套了 PythonTutor 可视化入口。被指定的 linkedlist_queue.md 正是承载「基于链表的队列」这一小节的完整可运行程序与正文linkedlist_queue.py一一对应其内容本身即是一个可独立运行的LinkedListQueue类。本文将该可视化代码与仓库中的正式源码相互印证展开为一份可自学、可复现的技术笔记。先理清基础什么是队列为什么选择链表队列是一种遵循先入先出FIFO规则的线性数据结构如同日常排队新来的人只能站到队尾队伍最前面的人先离开。参照 queue.md队列的头部称为「队首front」尾部称为「队尾rear」在队尾添加元素叫入队enqueue / push删除队首元素叫出队dequeue / pop。核心操作与时间复杂度如下表方法名说明时间复杂度push()元素入队添加到队尾$O(1)$pop()队首元素出队$O(1)$peek()访问队首元素不删除$O(1)$size()获取队列长度$O(1)$is_empty()判断队列是否为空$O(1)$实现队列需要「一端添加、另一端删除」的容器链表的「头节点 / 尾节点」恰好可以分别扮演「队首 / 队尾」队尾只做追加每次入队只需修改尾指针_rear的next引用队首只做删除每次出队只需让头指针_front后移一个节点。由此入队与出队都绕开了数组「删除头元素需要整体前移、代价 $O(n)$」的问题得以稳定在 $O(1)$ 完成。整体结构LinkedListQueue类的字段设计被指定的可视化文档中程序由两部分组成一个内联的ListNode单链表节点类以及队列主体LinkedListQueue。仓库中对应的正式源码位于 linkedlist_queue.py中文注释版与 linkedlist_queue.py日文注释版两者的类结构与算法完全一致仅在注释语言上不同。节点类仅需持有「值」与「后继引用」两个成员与通用的链表节点工具类 list_node.py 定义一致class ListNode: 链表节点类 def __init__(self, val: int): self.val: int val # 节点值 self.next: ListNode | None None # 后继节点引用队列类在构造方法中维护三个成员对应 linkedlist_queue.pyclass LinkedListQueue: 基于链表实现的队列 def __init__(self): 构造方法 self._front: ListNode | None None # 头节点 front self._rear: ListNode | None None # 尾节点 rear self._size: int 0字段职责_front指向队首节点出队与查看队首都基于它_rear指向队尾节点入队基于它_size以计数方式记录长度。链表没有数组的len维护独立计数器能让size()与is_empty()都达到 $O(1)$避免每次遍历整条链。类型注解ListNode | None使用 Python 3.10 的联合类型语法PythonTutor 链接参数中的py311也表明该可视化程序面向 Python 3.11 环境运行如果你在本地复现请确保 Python ≥ 3.10。核心操作源码级剖析入队 push队尾追加push()的实现位于 linkedlist_queue.pydef push(self, num: int): 入队 # 在尾节点后添加 num node ListNode(num) # 如果队列为空则令头、尾节点都指向该节点 if self._front is None: self._front node self._rear node # 如果队列不为空则将该节点添加到尾节点后 else: self._rear.next node self._rear node self._size 1它包含了入队操作最容易忽略的空队列分支先创建新节点若_front is None队列为空说明_rear同样为空此时必须把头、尾指针同时指向新节点否则出队方将找不到这个唯一元素若队列非空只需把新节点挂到_rear.next上再更新_rear node最后_size 1。正因为维护了_rear尾指针追加操作无需从_front开始遍历整条链从而保证入队 $O(1)$——这正是链表队列相比「不维护尾指针」版本的关键优化。peek 与 pop队首读取与删除peek()负责查看队首但不删除L53-L57def peek(self) - int: 访问队首元素 if self.is_empty(): raise IndexError(队列为空) return self._front.val注意其中的防御性检查当队列为空时抛出IndexError(队列为空)日语版为IndexError(キューが空です)。与教科书式实现不同源码的is_empty()采用计数判定return self._size 0而 PythonTutor 中内联版本用not self._front判定——两者语义等价前者多消耗 $O(1)$ 空间换来自洽性后者更省空间这在两端实现里属于可接受的风格差异。pop()在peek()校验通过后完成真正的删除L45-L51def pop(self) - int: 出队 num self.peek() # 删除头节点 self._front self._front.next self._size - 1 return num出队的本质是让头指针越过旧队首节点self._front self._front.next。旧节点失去引用后被 Python 的垃圾回收自动释放因此这里无需像 C 语言那样手工free。而出队借助peek()先行检查保证了对空队列调用pop()时抛出的仍是语义清晰的IndexError而非晦涩的AttributeErrorNone.next。size 与 is_emptyO(1) 的辅助方法def size(self) - int: 获取队列的长度 return self._size def is_empty(self) - bool: 判断队列是否为空 return self._size 0两方法直接读写计数器时间复杂度均为 $O(1)$不遍历链表。to_list把队列转成列表以便观测可视化与打印场景需要「以队首到队尾的顺序」展示内容to_list()实现了这一转换L59-L66def to_list(self) - list[int]: 转化为列表用于打印 queue [] temp self._front while temp: queue.append(temp.val) temp temp.next return queue它是队列中唯一需要 $O(n)$ 遍历的方法但其目的仅是展示 / 序列化并非队列的语义操作因此不影响入队、出队的 $O(1)$ 承诺。可视化跟踪PythonTutor 页面与逐步执行该 linkedlist_queue.md 的作用是将上述LinkedListQueue程序含内联ListNode编码为一行 PythonTutor 渲染链接。PythonTutor 会逐行高亮执行并同步绘制节点与指针尤其适合观察_front与_rear在push不同分支中的指向变化pop后头指针前移、被移除节点失联释放的过程类型注解、计数器的值在每个指令步长下的即时状态。仓库中与之一一对应的中文可视化入口位于 linkedlist_queue.md同样的程序也被「可视化执行」折叠块??? pythontutor嵌入到 queue.md 的「基于链表的实现」小节中。若要在本地复现只需在仓库根目录下运行python codes/python/chapter_stack_and_queue/linkedlist_queue.py或运行日语版python ja/codes/python/chapter_stack_and_queue/linkedlist_queue.py。文件头部的sys.path.append(str(Path(__file__).parent.parent))会动态把父目录加入模块搜索路径以导入modules工具包中的ListNode见 list_node.py。完整驱动代码与预期输出源码末尾的 Driver CodeL69-L97依次演示了队列全生命周期Driver Code if __name__ __main__: # 初始化队列 queue LinkedListQueue() # 元素入队 queue.push(1) queue.push(3) queue.push(2) queue.push(5) queue.push(4) print(队列 queue , queue.to_list()) # 访问队首元素 peek: int queue.peek() print(队首元素 front , peek) # 元素出队 pop_front: int queue.pop() print(出队元素 pop , pop_front) print(出队后 queue , queue.to_list()) # 获取队列的长度 size: int queue.size() print(队列长度 size , size) # 判断队列是否为空 is_empty: bool queue.is_empty() print(队列是否为空 , is_empty)连续入队 1、3、2、5、4 后队列内容保持插入顺序[1, 3, 2, 5, 4]这正是 FIFO 的直观体现。预期输出如下队列 queue [1, 3, 2, 5, 4] 队首元素 front 1 出队元素 pop 1 出队后 queue [3, 2, 5, 4] 队列长度 size 4 队列是否为空 False边界情况与复杂度小结链表队列需要特别关注的三种边界场景都在源码中得到了对应处理场景触发操作处理方式空队列peek()/pop()抛出IndexError(队列为空)首次入队push()_front与_rear同时指向新节点队中仅剩一个元素时出队pop()_front指向None后队列自然回到空态时空复杂度总结push、pop、peek、size、is_empty均为 $O(1)$每个入队元素需要额外的节点对象开销总空间复杂度为 $O(n)$不计入队列数据本身的存储。跨语言与跨实现对照不止 Python同一实现逻辑在仓库中遍布所有主流语言便于横向对照指针 / 引用语义差异Clinkedlist_queue.c 使用LinkedListQueue结构体front、rear、queSize出队与析构时需显式free(tmp)释放节点与 Python 依赖 GC 形成鲜明对比Java / C / Go / Rust 等日语目录 ja/codes 的chapter_stack_and_queue下提供了同构实现。此外若不想引入节点内存开销、希望利用 CPU 缓存局部性可改用以环形数组实现的队列用front记录队首下标、size记录长度并以rear front size推算队尾通过取模运算让下标在数组末端后回绕到头部从而让基于数组的入队出队也达到 $O(1)$详见 queue.md 的「基于数组的实现」。数组方案的问题在于长度固定、需要动态扩容链表方案则天然可伸缩二者取舍与栈的实现对比结论一致。队列的典型应用场景订单处理系统下单请求进入队列系统按顺序逐个处理大促瞬时高并发时队列是削峰填谷、保证处理顺序的基础设施各类先到先得的等待队列打印机作业队列、餐饮取餐叫号队列等都依赖队列维持公平的处理次序。掌握链表队列的实现意味着你同时理解了「指针操作」、「FIFO 语义」与「$O(1)$ 边界操作」三者的结合点——这也是后续学习广度优先搜索BFS、消息队列等进阶主题时反复出现的基本功。【免费下载链接】hello-algo《Hello 算法》动画图解、一键运行的数据结构与算法教程。支持简中、繁中、English、日本語提供 Python, Java, C, C, C#, JS, Go, Swift, Rust, Ruby, Kotlin, TS, Dart 等代码实现项目地址: https://gitcode.com/GitHub_Trending/he/hello-algo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询