数据结构知识点(二)

加载中... 浏览

12. 顺序存储和链式存储有什么区别?

顺序存储把数据放在连续的内存空间中,比如数组;链式存储的数据可以分散在不同的内存位置,然后通过指针连接起来。

  • 顺序存储最大的优势是随机访问快,可以通过下标直接找到元素;
  • 链式存储则更灵活,插入和删除节点时不需要大量移动其他元素

但链表并不是所有情况下都比数组好,因为链表虽然插入删除方便,但访问第 i 个元素需要从头开始遍历,时间复杂度是 O(n)

[!TIP] 实际选择要看需求:需要频繁随机访问就更适合数组,需要频繁插入删除可以考虑链表


13. 循环队列如何计算元素个数?

普通数组实现队列时,如果不断出队和入队,前面的位置可能被浪费掉,所以可以把数组首尾连接起来,形成循环队列

循环队列中,队头和队尾指针不断向后移动,到数组末尾之后再回到开头,通常通过取模实现。

如果采用"牺牲一个存储空间"的实现方式,容量为 N,那么元素个数可以通过:

(rear - front + N) % N

来计算。这里加 N 是为了避免 rear - front 出现负数。


14. 循环队列如何判断队空和队满?

循环队列中,通常使用 front 表示队头,rear 表示队尾。

在常见的"牺牲一个空间"的实现方式中:

  • 队空front == rear
  • 队满(rear + 1) % N == front

为什么要牺牲一个空间?因为如果不这样做,队空和队满时可能出现完全相同的指针状态,无法区分

[!TIP] 牺牲一个位置,就是人为留出一个状态用来区分"空"和"满"。


15. B树和B+树有什么区别?为什么数据库常用B+树?

B树和B+树都是多路平衡搜索树,主要用于解决数据量很大、无法全部放入内存时的高效查找问题。

最大的区别是:

  • B树的非叶子节点和叶子节点都可以存储数据;
  • B+树只有叶子节点存储真正的数据,非叶子节点主要存储索引;
  • B+树的叶子节点通常通过链表连接起来

数据库更常使用B+树,因为:

  • 数据库很多时候不仅要查一个数据,还要进行范围查询。B+树的叶子节点按照顺序连接起来,所以范围查询非常方便;
  • B+树的非叶子节点只存索引,可以放更多的索引项,从而降低树的高度,减少磁盘 IO

16. Prim、Kruskal、Dijkstra、Floyd 分别解决什么问题?

  • Prim 和 Kruskal 解决的是最小生成树问题,也就是在保证所有节点连通的情况下,选择一些边,使得总权重最小。Prim 是从某个节点开始,不断选择连接当前集合和外部节点的最小边;Kruskal 则是把所有边按照权重排序,然后不断选择最小的边,同时避免形成环。
  • Dijkstra 解决的是单源最短路径问题,也就是从一个起点出发,求它到其他节点的最短距离。
  • Floyd 解决的是多源最短路径问题,可以一次性求出任意两个节点之间的最短距离。

[!TIP] 可以直接记成:Prim/Kruskal → 最小生成树;Dijkstra → 一个点到其他点;Floyd → 任意两个点之间


17. 邻接表和邻接矩阵有什么区别?

邻接矩阵使用二维数组表示图。如果顶点有 V 个,就需要 V × V 的空间,所以空间复杂度通常是 O(V²)。它的优点是判断两个节点之间有没有边非常快,直接访问矩阵中的对应位置即可。

邻接表则是每个节点维护一个列表,里面存放和它相连的节点,所以空间复杂度通常是 O(V+E)

[!TIP] 稠密图,也就是边很多,可以考虑邻接矩阵;稀疏图,也就是边比较少,更适合邻接表。


18. 什么是 Top-K 问题?常用什么方法?

Top-K 就是从大量数据中找出最大的 K 个或者最小的 K 个元素

最简单的方法就是把所有数据排序,然后取前 K 个,但是如果数据量特别大,全部排序其实比较浪费。

比如有 100 万个数字,只需要找最大的 10 个数字,就没有必要把 100 万个数字全部排序。这时候可以维护一个大小为 10 的小顶堆

  • 堆中保存当前最大的 10 个数;
  • 新数据比堆顶大,就替换堆顶;
  • 最后堆中的 10 个元素就是最大的 10 个。

这样比全部排序更加高效。


19. 什么是数据结构?为什么需要数据结构?

数据结构就是组织和存储数据,并支持对数据进行高效操作的一种方式。

同样的数据,如果采用不同的数据结构,操作效率可能差别非常大:

  • 数组适合随机访问
  • 链表适合插入和删除
  • 栈适合后进先出的场景;
  • 队列适合先进先出的场景;
  • 哈希表适合快速查找
  • 树适合表示层次关系

[!TIP] 数据结构本质上就是研究:数据应该怎么组织,才能让我们更高效地使用它


20. 什么是平衡二叉树?有什么优势?

普通二叉搜索树虽然查找平均情况下比较快,但如果插入的数据本身接近有序,比如依次插入 1、2、3、4、5,它可能会退化成一条链,这时候查找效率就从原来的接近 O(log n) 下降到 O(n)

平衡二叉树就是通过限制树的高度,让左右子树尽量保持平衡,避免树退化。

[!TIP] 它的核心优势就是:控制树的高度,从而保证查找、插入、删除操作能够保持较好的效率


21. 什么是 AVL 树?它如何保持平衡?

AVL 树是一种比较严格的平衡二叉搜索树,它要求每个节点的左右子树高度差不能超过 1。这个高度差叫做平衡因子

当插入或者删除节点之后,如果某个节点的平衡因子超过允许范围,就说明树失衡了,需要通过旋转来恢复平衡。主要有四种情况:

  • LL:右旋;
  • RR:左旋;
  • LR:先左旋,再右旋;
  • RL:先右旋,再左旋。

[!TIP] AVL 树的核心就是:利用旋转控制树的高度,让二叉搜索树不要退化


22. 什么是拓扑排序?有什么应用?

拓扑排序用于有向无环图(DAG),它要求对于一条边 u → vu 必须排在 v 前面。

它实际上是在解决一种"先后依赖关系"。例如大学课程:高等数学 → 机器学习,那么学习机器学习之前必须先学习高等数学。拓扑排序就可以把这种依赖关系转换成一个合理的执行顺序。

常见实现方法有入度法DFS


23. 什么是并查集?有什么作用?

并查集是一种用来维护多个不相交集合的数据结构,主要有两个操作:

  • find:查找一个元素属于哪个集合;
  • union:把两个集合合并。

例如有很多节点,需要不断判断"节点 A 和节点 B 是否连通",就可以使用并查集。为了提高效率,通常会使用路径压缩按秩合并,使得大量操作下来效率非常高。

它常用于:

  • 判断连通性;
  • Kruskal 最小生成树;
  • 网络连接问题。

24. 如何判断一棵二叉树是否平衡?

可以递归计算每个节点的左右子树高度

对于一个节点:

  • 如果左子树高度和右子树高度相差超过 1,那么这棵树就不平衡;
  • 同时还要继续判断它的左右子树是否平衡。

比较高效的方法是采用自底向上的方式计算高度:如果某个子树已经不平衡,就直接返回特殊值,不需要继续计算。这样可以做到 O(n) 的时间复杂度。


25. 什么是平衡二叉树?

平衡二叉树主要是为了防止二叉搜索树退化成链表。它要求树中每个节点的左右子树高度保持在一定范围内,这样树的整体高度不会太高。

例如 AVL 树要求左右子树高度差不超过 1,而红黑树的平衡要求相对宽松一些。

[!TIP] 所以"平衡"的核心不是要求左右完全一样高,而是:让树的高度保持在一个合理范围内,避免查找效率退化


26. 二叉树中如何寻找最大值?

如果是普通二叉树,节点之间没有大小关系,所以不能像二叉搜索树那样直接判断应该去左边还是右边。

最简单的方法就是遍历整棵树,在遍历过程中维护一个 max,每访问一个节点就和当前最大值比较。因此需要访问所有节点,时间复杂度是 O(n),额外空间取决于使用递归还是队列等方式。

[!TIP] 如果题目明确说是二叉搜索树,那么情况就不一样了:二叉搜索树中右边的节点更大,可以直接沿着右子树寻找最大值

留言板

加载评论中...
【LeetCode HOT100】226. 翻转二叉树
数据结构知识点(一)
Valaxy v0.28.0-beta.1 驱动|主题-Yunv0.28.0-beta.1