45、数据结构与稀疏矩阵基础:二叉搜索树、堆与矩阵运算

数据结构与稀疏矩阵基础:二叉搜索树、堆与矩阵运算

1. 二叉搜索树(Binary Search Trees)

二叉搜索树(BST)是一种重要的数据结构,对于同一组元素,可以构建出不同形态的 BST。不同的 BST 在搜索元素所需的时间上存在差异,这种差异可以通过树的高度来量化。

树中节点的高度定义为该节点到根节点的唯一路径长度。例如,在某 BST 中,标签为 27 的节点高度可能为 1,而在另一个 BST 中,该节点高度可能为 4。BST 的高度则定义为其所有节点高度的最大值。

搜索操作 bfs_search() 的时间复杂度为 $O(h)$,其中 $h$ 是 BST 的高度。如果 BST 的高度为 $O(log N)$($N$ 为 BST 中的元素数量),则称该 BST 是平衡的。在平衡 BST 中,访问、插入、删除和搜索操作的平均时间复杂度为 $O(log N)$。平衡 BST 非常适合存储需要频繁访问和更新的数据,并且在许多图算法中都有应用。

2. 二叉堆(Binary Heaps)

在许多应用中,需要快速找出一组元素中的最大值或最小值。例如,在 Dijkstra 算法中,每次都需要从未访问节点中选择距离源节点最近的节点。如果将未访问节点存储在数组中,每次搜索最小距离元素需要扫描整个数组,时间复杂度为 $O(N)$;若将数组按距离升序排序,每次更新距离后都需要重新排序,时间复杂度为 $O(N log N)$,这比在未排序数组上的线性搜索更糟糕。

二叉堆是解决此类问题的有效数据结构,它可以保证以 $O(1)$ 的时间复杂度访问和提取集合中的最小(或最大)元素,并以 $O(log N)$ 的操作来更新数据结构。如果一个二叉堆能在常数时间内访问集合中的最大(最小)元素,则称其为最大堆(Max-Heap)或最小堆(Min-Heap)。

2.1 最大堆(Binary Max-Heap)的性质
  • 每个节点都关联一个数值键,键不一定唯一。
  • 树有且仅有一个根节点。
  • 除根节点外,每个节点都有一个父节点,即离根节点更近的邻居。
  • 每个节点最多有两个子节点,分别称为左子节点和右子节点。
  • 树是完全的,即除最后一层外,所有层都被完全填充,最后一层从左到右填充。
  • 最大堆性质:任何节点的键都大于或等于其所有子节点的键。

最小堆的定义与最大堆类似,只是最大堆性质变为任何节点的键小于或等于其所有子节点的键。

例如,给定三个具有相同元素集合的树,只有满足上述所有性质的树才是最大堆。

2.2 堆的操作

二叉堆通常支持以下两种基本操作:
- heap_extract() :移除堆的根节点,并重新排列元素以确保剩余结构仍然是堆。
- heap_insert() :向堆中插入一个新元素。

可以使用数组来实现堆,具体规则如下:
- 数组中位置 $i$ 的节点的左子节点位于位置 $2 × i + 1$。
- 数组中位置 $i$ 的节点的右子节点位于位置 $2 × i + 2$。
- 数组中位置 $i$ 的节点的父节点位于位置 $\lfloor(i - 1)/2\rfloor$。

以下是 heap_extract() sift_down() 的伪代码:

Algorithm 5 heap_extract()
Input: H, N
Output: H, N, max_H
1: max_H ← H[0]
2: H[0] ← H[N - 1]
3: N ← N - 1
4: sift_down(H, N, 0)
5: return max_H

Algorithm 6 sift_down()
Input: H, N, current
Output: H (with max-heap property respected)
1: largest ← current
2: left ← 2 × current + 1
3: right ← 2 × current + 2
4: if left < N and H[left] > H[largest] then
5:     largest ← left
6: end if
7: if right < N and H[right] > H[largest] then
8:     largest ← right
9: end if
10: if largest ≠ current then
11:     swap (H[current], H[largest])
12:     sift_down(H, N, largest)
13:     return
14: end if

以下是 heap_insert() sift_up() 的伪代码:

Algorithm 7 heap_insert()
Input: H, N, new_key
Output: N, H (with new_key added and max-heap property respected)
1: N ← N + 1
2: H[N - 1] ← new_key
3: sift_up(H, N, N)
4: return H

Algorithm 8 sift_up()
Input: H, N, current
Output: H (with max-heap property respected)
1: parent ← ⌊(current - 1)/2⌋
2: while H[parent] < H[current] do
3:     swap(H[parent], H[current])
4:     current ← parent
5:     parent ← ⌊(current - 1)/2⌋
6: end while
7: return H

heap_extract() 操作的流程如下:
1. 读取堆的最大值(存储在数组的第一个位置)并将其放入返回变量 max_H
2. 将数组的最后一个元素移到第一个位置。
3. 调用 sift_down() 函数来恢复最大堆性质。

heap_insert() 操作的流程如下:
1. 增加堆的元素数量。
2. 将新元素插入到堆的最后一个位置。
3. 调用 sift_up() 函数来确保新元素找到合适的位置,以满足最大堆性质。

heap_extract() heap_insert() 的时间复杂度均为 $O(log N)$。

3. 稀疏矩阵(Sparse Matrices)

矩阵是一种常见的数学结构,一个 $m×n$ 的矩阵 $A$ 是由 $m$ 行 $n$ 列的实数组成的表格,矩阵元素用 $a_{ij}$ 表示。矩阵的加法、数乘和乘法运算有特定的定义。矩阵的转置是通过交换行和列得到的,如果一个矩阵等于其转置,则称该矩阵为对称矩阵。

在处理与图相关的矩阵(如邻接矩阵和拉普拉斯矩阵)时,由于现实世界网络中的矩阵通常是稀疏的,即矩阵的非零元素数量 $M$ 远小于 $N^2$($N$ 为矩阵的阶数),因此需要使用特殊的表示方法来提高存储和运算效率。

3.1 ij - 形式(ij - Form)

$N × N$ 矩阵 $A$ 的 ij - 形式使用三个长度为 $M$(矩阵非零元素数量)的向量 $i$、$j$ 和 $s$。向量 $i$ 和 $j$ 分别存储矩阵非零元素的行和列索引,向量 $s$ 存储这些非零元素的值。如果 $A$ 是加权图的邻接矩阵,向量 $s$ 存储边的权重。

通过这些基础的数据结构和矩阵运算知识,我们可以更高效地处理各种算法问题,尤其是在图论和网络分析领域。二叉搜索树和二叉堆为我们提供了高效的数据存储和检索方法,而稀疏矩阵的表示则有助于优化矩阵运算的性能。在实际应用中,我们可以根据具体需求选择合适的数据结构和算法,以提高程序的效率和性能。

下面是一个简单的 mermaid 流程图,展示 heap_extract() 的操作流程:

graph TD;
    A[开始] --> B[读取最大值];
    B --> C[将最后元素移到首位];
    C --> D[调用 sift_down()];
    D --> E[结束];

同时,我们可以用表格总结二叉堆的操作复杂度:
| 操作 | 时间复杂度 |
| ---- | ---- |
| heap_extract() | $O(log N)$ |
| heap_insert() | $O(log N)$ |
| 查找最大值(最大堆) | $O(1)$ |
| 查找最小值(最小堆) | $O(1)$ |

数据结构与稀疏矩阵基础:二叉搜索树、堆与矩阵运算

4. 压缩行存储格式(Compressed Row Storage Format)

除了 ij - 形式,压缩行存储(CRS)格式也是一种常用的稀疏矩阵表示方法。在 CRS 格式中,需要三个数组: row_ptr col_idx values

  • row_ptr :长度为 $m + 1$,其中 $m$ 是矩阵的行数。 row_ptr[i] 表示第 $i$ 行的非零元素在 col_idx values 数组中的起始位置。
  • col_idx :存储所有非零元素的列索引。
  • values :存储所有非零元素的值。

例如,对于一个 $3\times3$ 的稀疏矩阵:
[
A =
\begin{bmatrix}
1 & 0 & 2 \
0 & 3 & 0 \
4 & 0 & 5
\end{bmatrix}
]
其 CRS 格式表示如下:
- row_ptr = [0, 2, 3, 5]
- col_idx = [0, 2, 1, 0, 2]
- values = [1, 2, 3, 4, 5]

通过 row_ptr 数组,我们可以方便地定位每一行的非零元素。例如,第 1 行的非零元素从 col_idx[row_ptr[0]] col_idx[row_ptr[1] - 1] ,即 col_idx[0] col_idx[1] ,对应列索引为 0 和 2,值分别为 values[0] values[1] ,即 1 和 2。

4.1 从 ij - 形式转换到 CRS 格式

将矩阵从 ij - 形式转换到 CRS 格式的步骤如下:
1. 初始化 row_ptr 数组, row_ptr[0] = 0
2. 遍历 i 向量(ij - 形式中的行索引向量),统计每一行的非零元素数量。
3. 根据每一行的非零元素数量,计算 row_ptr 数组的后续元素。
4. 初始化 col_idx values 数组。
5. 再次遍历 i j s 向量,将列索引和元素值分别存储到 col_idx values 数组中。

以下是一个简单的 Python 代码示例,展示如何进行转换:

def ij_to_crs(i, j, s, m):
    row_ptr = [0] * (m + 1)
    for idx in i:
        row_ptr[idx + 1] += 1
    for k in range(1, m + 1):
        row_ptr[k] += row_ptr[k - 1]
    col_idx = [0] * len(i)
    values = [0] * len(i)
    for idx in range(len(i)):
        row = i[idx]
        pos = row_ptr[row]
        col_idx[pos] = j[idx]
        values[pos] = s[idx]
        row_ptr[row] += 1
    # 恢复 row_ptr 的原始值
    for k in range(m, 0, -1):
        row_ptr[k] = row_ptr[k - 1]
    row_ptr[0] = 0
    return row_ptr, col_idx, values
4.2 从 CRS 格式转换到 ij - 形式

将矩阵从 CRS 格式转换到 ij - 形式的步骤如下:
1. 初始化 i j s 向量。
2. 遍历 row_ptr 数组,对于每一行,根据 row_ptr 数组确定该行非零元素的范围。
3. 在该范围内,将行索引、列索引和元素值分别添加到 i j s 向量中。

以下是一个简单的 Python 代码示例,展示如何进行转换:

def crs_to_ij(row_ptr, col_idx, values, m):
    i = []
    j = []
    s = []
    for row in range(m):
        start = row_ptr[row]
        end = row_ptr[row + 1]
        for pos in range(start, end):
            i.append(row)
            j.append(col_idx[pos])
            s.append(values[pos])
    return i, j, s
5. 稀疏矩阵的矩阵 - 向量乘法

稀疏矩阵的一个重要应用是矩阵 - 向量乘法。对于一个 $m\times n$ 的矩阵 $A$ 和一个 $n$ 维向量 $x$,矩阵 - 向量乘法 $y = Ax$ 的结果是一个 $m$ 维向量 $y$。

在稀疏矩阵的情况下,使用 ij - 形式或 CRS 格式可以更高效地执行矩阵 - 向量乘法。

5.1 使用 ij - 形式进行矩阵 - 向量乘法

使用 ij - 形式进行矩阵 - 向量乘法的步骤如下:
1. 初始化结果向量 $y$ 为零向量。
2. 遍历 i j s 向量。
3. 对于每一个非零元素 $a_{ij}$(存储在 s 向量中,行索引为 i ,列索引为 j ),将 $a_{ij}x_j$ 累加到 $y_i$ 中。

以下是一个简单的 Python 代码示例:

def sparse_matrix_vector_multiply_ij(i, j, s, x, m):
    y = [0] * m
    for idx in range(len(i)):
        row = i[idx]
        col = j[idx]
        value = s[idx]
        y[row] += value * x[col]
    return y
5.2 使用 CRS 格式进行矩阵 - 向量乘法

使用 CRS 格式进行矩阵 - 向量乘法的步骤如下:
1. 初始化结果向量 $y$ 为零向量。
2. 遍历每一行。
3. 对于每一行,根据 row_ptr 数组确定该行非零元素的范围。
4. 在该范围内,将非零元素与向量 $x$ 对应元素的乘积累加到 $y$ 的相应行中。

以下是一个简单的 Python 代码示例:

def sparse_matrix_vector_multiply_crs(row_ptr, col_idx, values, x, m):
    y = [0] * m
    for row in range(m):
        start = row_ptr[row]
        end = row_ptr[row + 1]
        for pos in range(start, end):
            col = col_idx[pos]
            value = values[pos]
            y[row] += value * x[col]
    return y
6. 总结与应用场景

通过上述内容,我们了解了二叉搜索树、二叉堆和稀疏矩阵的相关知识。这些数据结构和算法在不同的场景中有着重要的应用。

  • 二叉搜索树 :适用于需要频繁进行插入、删除和搜索操作的场景,尤其是当数据需要有序存储时。平衡二叉搜索树在处理大规模数据时能保证较好的时间复杂度。
  • 二叉堆 :在需要快速找到最大值或最小值的场景中表现出色,如 Dijkstra 算法、优先队列等。堆操作的时间复杂度较低,能有效提高算法效率。
  • 稀疏矩阵 :在处理大规模稀疏矩阵时,ij - 形式和 CRS 格式能显著减少存储空间,并提高矩阵运算的效率。在图论、机器学习等领域,稀疏矩阵的应用非常广泛。

下面是一个 mermaid 流程图,展示稀疏矩阵从 ij - 形式到 CRS 格式的转换流程:

graph TD;
    A[开始] --> B[初始化 row_ptr];
    B --> C[统计每行非零元素数量];
    C --> D[计算 row_ptr 后续元素];
    D --> E[初始化 col_idx 和 values];
    E --> F[遍历 i, j, s 向量];
    F --> G[填充 col_idx 和 values];
    G --> H[恢复 row_ptr 原始值];
    H --> I[结束];

同时,我们可以用表格总结稀疏矩阵不同表示方法的特点:
| 表示方法 | 优点 | 缺点 | 适用场景 |
| ---- | ---- | ---- | ---- |
| ij - 形式 | 简单直观,易于实现 | 存储效率相对较低 | 小规模稀疏矩阵或需要快速构建矩阵的场景 |
| 压缩行存储格式 | 存储效率高,适合矩阵 - 向量乘法 | 构建过程相对复杂 | 大规模稀疏矩阵和需要频繁进行矩阵 - 向量乘法的场景 |

综上所述,掌握这些数据结构和算法对于解决实际问题,特别是在图论、网络分析和机器学习等领域,具有重要的意义。我们可以根据具体的应用场景选择合适的数据结构和算法,以达到最佳的性能和效率。

内容概要:本文为《科技类企业品牌传播白皮书》,系统阐述了新闻媒体发稿、自媒体博主种草短视频矩阵覆盖三大核心传播策略,并结合“传声港”平台的AI工具资源整合能力,提出适配科技企业的品牌传播解决方案。文章深入分析科技企业传播的特殊性,包括受众圈层化、技术复杂性传播通俗性的矛盾、产品生命周期影响及2024-2025年传播新趋势,强调从“技术输出”向“价值引领”的战略升级。针对三种传播方式,分别从适用场景、操作流程、效果评估、成本效益、风险防控等方面提供详尽指南,并通过平台AI能力实现资源智能匹配、内容精准投放全链路效果追踪,最终构建“信任—种草—曝光”三位一体的传播闭环。; 适合人群:科技类企业品牌市场负责人、公关传播从业者、数字营销管理者及初创科技公司创始人;具备一定品牌传播基础,关注效果可量化AI工具赋能的专业人士。; 使用场景及目标:①制定科技产品全生命周期的品牌传播策略;②优化媒体发稿、KOL合作短视频运营的资源配置ROI;③借助AI平台实现传播内容的精准触达、效果监测风险控制;④提升品牌在技术可信度、用户信任市场影响力方面的综合竞争力。; 阅读建议:建议结合传声港平台的实际工具模块(如AI选媒、达人匹配、数据驾驶舱)进行对照阅读,重点关注各阶段的标准化流程数据指标基准,将理论策略平台实操深度融合,推动品牌传播从经验驱动转向数据工具双驱动。
【3D应力敏感度分析拓扑优化】【基于p-范数全局应力衡量的3D敏感度分析】基于伴随方法的有限元分析和p-范数应力敏感度分析(Matlab代码实现)内容概要:本文档围绕“基于p-范数全局应力衡量的3D应力敏感度分析”展开,介绍了一种结合伴随方法有限元分析的拓扑优化技术,重点实现了3D结构在应力约束下的敏感度分析。文中详细阐述了p-范数应力聚合方法的理论基础及其在避免局部应力过高的优势,并通过Matlab代码实现完整的数值仿真流程,涵盖有限元建模、灵敏度计算、优化迭代等关键环节,适用于复杂三维结构的轻量化高强度设计。; 适合人群:具备有限元分析基础、拓扑优化背景及Matlab编程能力的研究生、科研人员或从事结构设计的工程技术人员,尤其适合致力于力学仿真优化算法开发的专业人士; 使用场景及目标:①应用于航空航天、机械制造、土木工程等领域中对结构强度和重量有高要求的设计优化;②帮助读者深入理解伴随法在应力约束优化中的应用,掌握p-范数法处理全局应力约束的技术细节;③为科研复现、论文写作及工程项目提供可运行的Matlab代码参考算法验证平台; 阅读建议:建议读者结合文中提到的优化算法原理Matlab代码同步调试,重点关注敏感度推导有限元实现的衔接部分,同时推荐使用提供的网盘资源获取完整代码测试案例,以提升学习效率实践效果。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值