稀疏表Sparse Table(最易懂,最详细讲解,c语言代码版本)

目录

一.前置内容(倍增思想)

二.稀疏表的定义

 三.稀疏表的建立(含C详解代码)

四.稀疏表的查询

 五.总结

一.前置内容(倍增思想)

  • 定义:每次通过倍增加速状态转移、预处理或查询(很多时候能把时间复杂度降到O(logN))

解释一下:任意整数均可以被表示成若干个2的次幂之和即二进制。倍增就是成倍增加,若问题的状态空间特备大,则一步步的递推算法复杂度太高,可以通过倍增的思想,只考虑2的整数次幂位置,快速缩小求解范围直到找到解。

实际应用:动态数组,稀疏表,后缀数组,快速幂等等很多问题的解决都是用的倍增思想。

举个栗子:比如在一颗树中查找一个数x,这是一颗父节点比子节点大的树

每次可以以2的次幂形式往上查找。

二.稀疏表的定义

稀疏表可以在O(1)时间在线查询【l,r】区间的最值问题。

定义F【i,j】i是区间的起始位置,区间长度为2^j

 

 可以得出递推公式

 

 三.稀疏表的建立(含C详解代码)

1.我们先考虑一下i和j的取值范围

若数组长度为n,最大区间长度,最大区间长度2^{k} \leqslant n< 2^{k+1}那么k是

 

比如:n = 16,k = 4。n = 20, k = 4

代码实现求解k

得出j的范围是【1,k】,i的范围是【1,n-2^j+1

 代码实现:时间复杂度O(nlogn)

 我举个栗子画个图直观感受下:
例如a[1...10] = {5,3,7,2,12,1,6,4,8,15}创立的稀疏表为

 例如:F[1][3]就是从1开始长度为8的区间最大值

四.稀疏表的查询

此时已经建立了稀疏表,假设查询【L,R】区间最值,则首先需要计算区间长度,区间长度为

r-l+1然后转化为2次幂的形式

 

 根据倍增思想,我们将查询区间分为两个查询区间,取两个区间的最值即可。

那该如何划分区间呢?

分别从L向后的2^k个数和从R向前的2^k个数

 代码实现:时间复杂度O(1)

 五.总结

稀疏表Sparse Table不支持在线修改,因为修改后要推翻原先已经建立的ST表。

RMQ问题就是区间最值查询(range max/min query)有多种解决办法,用线段树和ST解决都可以

区别如下:

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是C语言实现稀疏矩阵的三元组存储的示例: ```c #include <stdio.h> #include <stdlib.h> typedef struct { int row; int col; int value; } Triplet; typedef struct { int nrows; int ncols; int nelems; Triplet* data; } SparseMatrix; SparseMatrix* create_sparse(int nrows, int ncols, int* matrix) { SparseMatrix* sm = (SparseMatrix*)malloc(sizeof(SparseMatrix)); sm->nrows = nrows; sm->ncols = ncols; sm->nelems = 0; for (int i = 0; i < nrows * ncols; i++) { if (matrix[i] != 0) { sm->nelems++; } } sm->data = (Triplet*)malloc(sm->nelems * sizeof(Triplet)); int k = 0; for (int i = 0; i < nrows; i++) { for (int j = 0; j < ncols; j++) { if (matrix[i * ncols + j] != 0) { sm->data[k].row = i; sm->data[k].col = j; sm->data[k].value = matrix[i * ncols + j]; k++; } } } return sm; } void print_sparse(SparseMatrix* sm) { printf("Sparse Matrix (%d x %d):\n", sm->nrows, sm->ncols); for (int i = 0; i < sm->nelems; i++) { printf("(%d, %d, %d)\n", sm->data[i].row, sm->data[i].col, sm->data[i].value); } } void destroy_sparse(SparseMatrix* sm) { free(sm->data); free(sm); } int main() { int matrix[3][4] = { {1, 0, 0, 2}, {0, 3, 0, 0}, {0, 0, 4, 0} }; SparseMatrix* sm = create_sparse(3, 4, (int*)matrix); print_sparse(sm); destroy_sparse(sm); return 0; } ``` 其中,`SparseMatrix`结构体用于稀疏矩阵,包含四个属性:`nrows`示矩阵的行数,`ncols`示矩阵的列数,`nelems`示矩阵中非零元素的个数,`data`为一个三元组数组,存储矩阵中的非零元素。 `create_sparse`函数用于将一个二维数组示的稀疏矩阵转化为三元组。具体实现是遍历矩阵中的每个元素,如果该元素不为0,则将其行列坐标以及值存储到一个三元组中,最后将所有三元组存储到一个数组中并返回。 `print_sparse`函数用于打印稀疏矩阵的三元组。 `destroy_sparse`函数用于销毁稀疏矩阵的三元组。 在`main`函数中,我们定义一个二维数组示一个稀疏矩阵,然后调用`create_sparse`函数将其转化为三元组,并调用`print_sparse`函数打印结果,最后调用`destroy_sparse`函数销毁稀疏矩阵的三元组

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值