数据结构1

广义表

二叉树的基本特性

旋转二叉树

构造霍夫曼树(最优)

步骤:

  1. 初始化
    • 给定一组权值(通常是字符的频率),每个权值视为一个叶子节点。
    • 将所有权值按照大小顺序放入一个最小堆(或优先队列),确保可以每次取出最小的权值。
  2. 构造过程
    • 循环构建 :重复以下过程,直到堆中只剩下一个节点:
      1. 从堆中取出两个最小的节点(这两个节点具有最小的权值)。
      2. 创建一个新的节点,其权值是这两个节点的权值之和。这个新节点成为父节点,连接两个最小节点(作为它的左右子节点)。
      3. 将新节点插回堆中。
  3. 终止
    • 当堆中只剩一个节点时,说明霍夫曼树已经构造完毕。这个节点就是树的根节点。

线索二叉树

平衡二叉树

邻接矩阵

邻接表

图的遍历

拓扑排序

最小生成树

普利姆算法

普利姆算法 (Prim's Algorithm)是求解最小生成树(MST, Minimum Spanning Tree)的一种贪心算法。最小生成树是图中包含所有顶点且边权和最小的生成树。普利姆算法通过逐步扩展生成树来构造最小生成树,每次选择一条最小的边,连接树中的顶点与图中未连接的顶点。

普利姆算法的步骤:

  1. 初始化
    • 从图中任选一个顶点作为起始点(称为生成树的初始顶点)。
    • 设定一个标记集合,用来标记已加入生成树的顶点。
    • 初始化一个数组(或优先队列),用于记录从已加入生成树的顶点到其他顶点的最短边(权值最小的边)。
  2. 构建过程
    • 重复以下步骤直到所有顶点都加入生成树:
      1. 从标记集合外的顶点中,选择一条权值最小的边,将该边对应的顶点加入生成树。
      2. 更新与新加入顶点相连的边的权值,确保下次选择时会选取最小的边。
  3. 终止
    • 当所有顶点都被加入生成树时,算法终止。

示例:普利姆算法

假设有如下带权图:

复制代码

A

/ \

2 3

/ \

B-------C

1

图的邻接矩阵表示如下:

复制代码

A B C

A 0 2 3

B 2 0 1

C 3 1 0

步骤1:初始化
  • 选择顶点 A 作为起始顶点,生成树包含顶点 A
  • 初始化一个数组记录从顶点 A 出发到其他顶点的最小边,边的权值为:
    • A -> B 权值为 2
    • A -> C 权值为 3
步骤2:构建生成树
  1. A 开始,选择权值最小的边 A -> B,将顶点 B 加入生成树,生成树现在包含顶点 AB

    更新边权:

    • B 出发的边为 B -> C,权值为 1。

    此时最小边为 B -> C

  2. 选择边 B -> C,将顶点 C 加入生成树,生成树现在包含顶点 ABC

    此时所有顶点都已被加入生成树,算法结束。

步骤3:结果

最终的最小生成树边为:

  • A -> B 权值 2
  • B -> C 权值 1

最小生成树的总权值为 2 + 1 = 3

总结:

普利姆算法通过贪心策略逐步扩展生成树,每次选择当前生成树与未加入顶点之间的最小边。其时间复杂度通常为 O(E log V),其中 E 为图中的边数,V 为顶点数。对于稠密图(边数较多),普利姆算法比克鲁斯卡尔算法(Kruskal's Algorithm)更有效。

克鲁斯卡尔算法

克鲁斯卡尔算法 (Kruskal's Algorithm)是解决最小生成树(MST, Minimum Spanning Tree)问题的另一种经典贪心算法。它的核心思想是将图中的所有边按权重排序,然后逐步选择权重最小的边,确保不会形成环,最终形成一棵最小生成树。

克鲁斯卡尔算法的步骤:

  1. 初始化
    • 将图中的所有边按照权值升序排列。
    • 初始化每个顶点所在的集合(可以用并查集(Union-Find)来管理)。
    • 生成一个空的最小生成树。
  2. 构建过程
    • 遍历所有边,选择权值最小的边,判断它的两个端点是否属于同一个集合:
      1. 如果它们属于不同的集合,将这条边加入最小生成树,并合并这两个集合。
      2. 如果它们已经在同一个集合中,说明加入这条边会形成环,跳过这条边。
  3. 终止
    • 当最小生成树包含 V-1 条边(V 是图中的顶点数)时,算法结束。

示例:克鲁斯卡尔算法

假设有如下带权图:

复制代码

A

/ \

2 3

/ \

B-------C

1

图的邻接矩阵表示如下:

复制代码

A B C

A 0 2 3

B 2 0 1

C 3 1 0

步骤1:初始化
  • 将所有边按权值升序排列:
    • B -> C 权值 1
    • A -> B 权值 2
    • A -> C 权值 3
步骤2:构建生成树
  1. 选择边 B -> C(权值 1)
    • BC 还不在同一个集合中,加入生成树,合并集合。
  2. 选择边 A -> B(权值 2)
    • AB 也不在同一个集合中,加入生成树,合并集合。
  3. 选择边 A -> C(权值 3)
    • AC 已经在同一个集合中,加入这条边会形成环,所以跳过。
步骤3:结果

最小生成树的边为:

  • B -> C 权值 1
  • A -> B 权值 2

最小生成树的总权值为 1 + 2 = 3

并查集(Union-Find)

克鲁斯卡尔算法依赖于并查集(Union-Find)来有效地管理和合并不同的集合。并查集是一种用于处理集合合并和查询问题的数据结构,支持两个主要操作:

  • Find:查找元素所在的集合。
  • Union:合并两个集合。

并查集的优化:

  • 路径压缩:在查找操作中,将查询路径上的所有节点直接连接到根节点,降低树的高度,从而加速后续的查询操作。
  • 按秩合并:在合并两个集合时,总是将较小的树合并到较大的树上,避免树的高度过大。

总结:

克鲁斯卡尔算法通过贪心策略,从图中选择权值最小的边并确保不形成环,直到构建出最小生成树。它的时间复杂度是 O(E log E),其中 E 是图中的边数。对于稀疏图(边数较少),克鲁斯卡尔算法通常比普利姆算法更加高效。

相关推荐
淡海水10 小时前
08-03-不可变-ImmutableDictionary-TKey-TValue-与ImmutableHashSet-T-持久化哈希树
数据结构·算法·c#·哈希算法·dictionary·immutable
Nil20813 小时前
leetcode 78子集
数据结构·算法·leetcode
喜欢吃燃面14 小时前
深入 C++ STL:从 unordered_set与unordered_map到底层哈希表的原理与实现
数据结构·c++·散列表
en.en..14 小时前
Linux fork() 工作原理
数据结构·算法
不会就选b16 小时前
数据结构之树&&二叉树(二)
数据结构·算法
小刘在重生~18 小时前
Java 集合|Collection、List、ArrayList、LinkedList、泛型、Collections 工具类
java·数据结构·list
我不会起名字32219 小时前
一天一道算法题(29):单调栈
java·数据结构·python·算法·leetcode·golang·单调栈
苦瓜小生19 小时前
【前端】【力扣与手撕】十天带你刷完前端算法与手撕,全是最简单好记的最优解法!day4
前端·数据结构·算法·leetcode·面试
少司府20 小时前
C++进阶:智能指针
开发语言·数据结构·c++·b树·算法·c·智能指针
LuminousCPP21 小时前
数据结构-排序(一):基础排序算法横向对比|冒泡、插入、希尔、堆与双向选择,详解二分 / Knuth 增量
c语言·数据结构·笔记·算法·排序算法