【问题标题】:data structure to store piece-wise function存储分段函数的数据结构
【发布时间】:2018-11-16 20:33:40
【问题描述】:

我想实现一个函数:

f(x) = a0   -inf < x < b0
       a1    b0 <= x < b1
       a2    b1 <= x < b2
       ...
       an    bn-1 <= x < bn
       an+1  bn <= x < +inf

而不是简单的 if-else 实现。

def func(x):
    if x<b0: return a0
    elif x<b1: return a1
    .....

我有更好的数据结构来组织它吗?

另外,在给定两个序列 {an}、{bn} 的情况下,我如何编写一个返回优化后的“func(x)”的“元函数”。

【问题讨论】:

  • 你可以有一个定义为[bi,bj]的元组bi &lt; bj建立一个dict[tuple] = an的字典,它应该是O(1)只要字典是静态的并且在建立一次后没有改变.
  • Python 有一个interval 模块;尝试浏览器搜索。
  • @Prune 我更感兴趣的是数学/算法解决方案,而不是谷歌搜索包。

标签: database algorithm math data-structures


【解决方案1】:

如果n 很大,您希望减少if 语句的数量。在 Python 中,这可以通过将数据存储在字典中来完成:

fx = {b0: a0, b1: a1, b2: a2, ..., bn: an, math.inf: an+1}

对于给定的x 值,对字典的键值进行二分搜索。这为您提供了适当的键来使用,然后使用字典本身来获取相关值。如果您的语言不允许 inf 作为键,您可以将 an+1 的值与字典分开,也许将两者都保存在 2 元组中。

这会将最大测试数从 n 减少到 log2(n)

“元函数”在 Python 中很简单,因为函数是 Python 中的一等对象。您没有说明首选语言:如果您需要 Python 中的“元函数”示例,请告诉我。

【讨论】:

  • 为了进行二分搜索,需要对项目进行排序。字典键不一定是排序的,所以这可能是 OP 需要采取的步骤。鉴于此,我不知道字典在这里是否有好处;必须将 b 保存在排序列表中,也可以将 a 保存在并行列表中。
  • @RobertDodier 谢谢。如果我需要在不重建整个列表的情况下更改枢轴点怎么办。如果我可以使用任何“二叉树”技巧?
  • @RobertDodier:在 Python 3.6 及更高版本中,标准 Python 确实按照插入的顺序对键进行排序。在 Python 3.7 中,这是所有 Python 实现所需的标准。我认为这是理所当然的,不应该这样做——谢谢你的说明。你是对的,两个列表,其中一个排序,也可以很好地工作并且在某些方面更好,但这意味着将两个列表放入一个整体容器结构中,这将比我展示的字典更复杂。
【解决方案2】:

可以只存储 a 和 b 的数组。然后要查找一个值,您可以在b 数组中进行二进制搜索,以找到要在a 数组中返回的值的索引。

这实际上表现得非常好,但是当我不得不为这个词法分析包 (https://github.com/mtimmerm/dfalex) 实现状态机时,我想出了一种更快的方法,我认为这很酷。

您的函数表示将是一个按顺序存储在数组中的二叉树,就像我们通常对堆所做的那样:https://www.geeksforgeeks.org/array-representation-of-binary-heap/

树的根在array[0],任何array[i] 的左孩子在array[2i+1]array[i] 的右孩子在array[2i+2]。树的叶子依次是所有a(结果)值,每对相邻a值之间的内部节点是b(参数)值,您可以在该值处从一个值切换到另一个值。

数组中的堆树顺序确保所有a 值在末尾连续出现。

这种表示的好处是你可以使用这个函数来查找合适的值,这比二分查找更简单快捷:

def lookup(x, array, num_internal_nodes)
    i=0
    while (i < num_internal_nodes):
        i = i*2 + (1 if x<array[i] else 2)
    return array[i]

抱歉,如果我在 python 语法上犯了错误——这不是我熟悉的语言。

如果您需要构造一个只接受输入值的函数,那么您可以构建数组表示并调用一个像这样进行闭包的函数:

def makeF(array, num_internal_nodes):
    def f(x):
        return lookup(x, array, num_internal_nodes)
    return f

首先要构建函数的数组表示,只需制作一个适当大小的数组(num_internal_nodes*2+1),然后对树进行前序遍历,填写a(叶) 和b(内部)值按顺序排列。

【讨论】:

  • 我也在考虑类似的事情,但在我看来,找到包含给定输入的区间的比较次数相同(我的意思是与数组中的二进制搜索相同) .也许我忽略了一些东西。
  • @RobertDodier 的比较次数完全相同,但其他操作更少,缓存局部性更好
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多