本文概述了算法问题解决中使用的基本数据结构。我们将重点介绍线性数据结构和非线性数据结构,包括它们的实现、操作和实际应用。本页涵盖了构成存储库中更复杂算法和解决方案基础的核心数据结构。
有关更高级的图特定结构和算法的信息,请参阅图。
数据结构可以逻辑上分为线性或非线性。线性结构包括数组、栈、队列和链表,而非线性结构包括树和图。
需要注意的是,线性或非线性的逻辑分类不一定反映这些结构在内存中的存储方式——它纯粹是一种逻辑区别。例如,我们可以使用数组来存储二叉树。
来源:thinkings/basic-data-structure.md7-11
数组是最简单的数据结构,它允许以常数时间O(1)进行索引访问来存储元素集合。许多其他数据结构都是基于或使用数组实现的。
数组支持以下基本操作:
在仓库中,数组被广泛用于涉及以下问题:
来源:thinkings/basic-data-structure.md13-17 problems/26.remove-duplicates-from-sorted-array.md61-72 problems/283.move-zeroes.md36-43
队列是一种受限的序列,元素只能在队尾添加(入队),从队头移除(出队),遵循先进先出(FIFO)原则。
实际应用:HTTP请求处理以及解决HTTP/1.1与HTTP/2中的队头阻塞问题
在HTTP/1.1中,请求被排队并且必须等待之前的响应(队头阻塞),而HTTP/2使用多路复用以允许同时进行请求和响应。
来源:thinkings/basic-data-structure.md70-114
栈是一种受限的序列,元素只能从顶部添加和移除,遵循后进先出(LIFO)原则。
栈广泛应用于:
一个实际例子是JavaScript的执行栈
仓库中的例子:实现一个支持push、pop、top操作,并能在常数时间内获取最小元素的最小栈。
来源:thinkings/basic-data-structure.md128-176 problems/155.min-stack.md41-79
链表是一种线性数据结构,其中元素存储在节点中,每个节点包含数据和指向下一个节点的引用。
基本操作:
链表用于实现其他数据结构,如栈、队列,以及需要高效插入和删除操作的场景。
React实现中的一个实际应用是Fiber架构
React Fiber使用链表结构来使工作可以暂停和恢复,从而允许对UI更新进行优先级排序。
来源:thinkings/basic-data-structure.md182-243 problems/203.remove-linked-list-elements.md28-39
非线性数据结构用于数据元素之间存在层级或网络关系而非顺序关系的场景。它们在表示复杂关系和支持动态操作方面特别高效。
来源:thinkings/basic-data-structure.md246-250
树是具有根节点和子节点的层次结构。它们用于表示层次关系、组织数据以进行高效搜索等。
树的关键属性:
树的遍历方法:
来源:thinkings/basic-data-structure.md252-271 thinkings/binary-tree-traversal.md24-44
二叉树是一种树,其中每个节点最多有两个子节点,分别称为左子节点和右子节点。
二叉树的特殊类型:
二叉树遍历的实现可以是:
来源:thinkings/basic-data-structure.md277-305 thinkings/binary-tree-traversal.md5-23
堆是一种特殊的基于树的数据结构,满足堆属性。它通常用于实现优先队列。
堆的属性:
基本操作:
堆用于:
来源:thinkings/basic-data-structure.md307-324
二叉搜索树(BST)是一种二叉树,具有以下属性:
BST操作:
BST的一个关键特性是,中序遍历会生成一个排序后的值序列。
BST用于:
来源:thinkings/basic-data-structure.md330-353
平衡二叉树是保持对数高度的二叉树,以确保无论插入顺序如何,操作都具有O(log n)的时间复杂度。
常见的平衡二叉树类型:
这些树使用旋转操作在插入和删除后维持平衡。
来源:thinkings/basic-data-structure.md356-382
Trie,也称为前缀树,是一种树状数据结构,用于存储字符串集合,其中共享前缀由共享路径表示。
Trie的属性:
Trie用于:
ImmutableJS库使用类似Trie的结构来实现其高效的数据共享。
来源:thinkings/basic-data-structure.md384-408
下表总结了不同数据结构上操作的时间和空间复杂度:
| 数据结构 | 访问 | 搜索 | 插入 | 删除 | Space键 |
|---|---|---|---|---|---|
| 数组 | O(1) | O(n) | O(n) | O(n) | O(n) |
| 栈 | O(n) | O(n) | O(1) | O(1) | O(n) |
| 队列 | O(n) | O(n) | O(1) | O(1) | O(n) |
| 链表 | O(n) | O(n) | O(1)* | O(1)* | O(n) |
| 二叉树 | O(n) | O(n) | O(n) | O(n) | O(n) |
| BST | O(log n)** | O(log n)** | O(log n)** | O(log n)** | O(n) |
| 堆 | O(1)*** | O(n) | O(log n) | O(log n) | O(n) |
| Trie树 | O(m) | O(m) | O(m) | O(m) | O(n*m) |
* 假设位置已知。如果需要搜索,复杂度变为O(n)。
** 平均情况。对于不平衡树,最坏情况是O(n)。
*** 仅用于查找最小/最大元素。
m = Trie操作中键/字符串的长度
此比较有助于根据应用程序中最常执行的操作来选择适当的数据结构。
来源:基于所有引用文件中的信息进行分析。
本仓库展示了这些数据结构在解决算法问题中的各种实际应用:
数组的双指针技巧
栈的应用
二叉树操作
哈希表的使用
链表操作
这些例子展示了掌握这些基本数据结构对于高效解决各种算法问题至关重要。
来源:本节中引用的所有问题文件。