我是否需要采取明确的操作来促进与持久数据结构的共享?

2024-05-20

我来自命令式背景,正在尝试实现一个简单的不相交集(“并集查找”)数据结构,以获得在 Haskell 中创建和修改(持久)数据结构的一些练习。目标是有一个简单的实现,但我也关心效率,我的问题与此相关。

首先,我创建了一个按等级并集的不相交集森林实现,并首先为“点”定义数据类型:

data Point = Point
  { _value  :: Int
  , _parent :: Maybe Point
  , _rank   :: Int
  } deriving Show

不相交的集合森林是IntMap with Int → Point映射:

type DSForest = IntMap Point

empty :: DSForest
empty = I.empty

单例集只是其值的映射x到一个有价值的点x,没有父级且等级为 1:

makeSet :: DSForest -> Int -> DSForest
makeSet dsf x = I.insert x (Point x Nothing 0) dsf

现在,有趣的部分——union。此操作将通过将另一个点设置为其父点来修改一个点(并且在某些情况下更改其排名)。在这种情况下Points的等级不同,Point只是“更新”(创建一个新点)以使其父点指向另一个点。在它们相等的情况下,一个新的Point创建后其等级增加一:

union :: DSForest -> Int -> Int -> DSForest
union dsf x y | x == y = dsf 
union dsf x y = 
   if _value x' == _value y'
      then dsf 
      else case compare (_rank x') (_rank y') of
                  GT -> I.insert (_value y') y'{ _parent = Just x' } dsf 
                  LT -> I.insert (_value x') x'{ _parent = Just y' } dsf 
                            -- 1) increase x's rank by one:
                  EQ -> let x''  = x'{ _rank = _rank x' + 1 } 
                            -- 2) update the value for x's rank to point to the new x:
                            dsf' = I.insert (_value x'') x'' dsf 
                            -- 3) then update y to have the new x as its parent:
                         in I.insert (_value y') y'{ _parent = Just x'' } dsf'
  where x' = dsf ! findSet dsf x
        y' = dsf ! findSet dsf y

现在,回答我真正的问题,如果EQ在这种情况下,我改为执行以下操作:

EQ -> let dsf' = I.insert (_value x') x'{ _rank = _rank x' + 1} dsf 
       in I.insert (_value y') y'{ _parent = Just x'{ _rank = _rank x' + 1 }} dsf'

IE。首先插入一个新的Point x随着等级的提高,然后有y'的父母是新的Point x随着等级的提升,这是否意味着它们不再指向同一个Point在记忆中?(这还重要吗?在使用/创建持久数据结构时我应该担心这些事情吗?)

为了完整起见,这里是findSet:

findSet :: DSForest -> Int -> Int
findSet dsf' x' = case _parent (dsf' ! x') of
                     Just (Point v _ _)  -> findSet dsf' v
                     Nothing             -> x'

(也欢迎对此代码的效率和设计提出一般性评论。)


这是否意味着它们不再指向内存中的同一个点?

我认为您不应该关心这一点,因为这只是不可变值的运行时系统(又名 Haskell 的 RTS)的实现细节。

至于其他建议,我想说的是让这个功能findSet返回Point本身而不是键,因为这会消除在union.

findSet :: DSForest -> Int -> Point
findSet dsf' x' = case _parent pt of
                     Just (Point v _ _)  -> findSet dsf' v
                     Nothing             -> pt
                  where
                      pt = (dsf' ! x')

进行适当的更改union功能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

我是否需要采取明确的操作来促进与持久数据结构的共享? 的相关文章

  • NumPy“记录数组”或“结构化数组”或“recarray”

    NumPy 结构化数组 记录数组 和 记录数组 之间有什么区别 如果有的话 The NumPy 文档 http docs scipy org doc numpy user basics rec html暗示前两个是相同的 如果是 那么该对象
  • 如何在 blaze-html 中渲染 blaze-svg 标记

    我想将使用 blaze svg 生成的 svg 图直接包含在使用 blaze html 生成的 html 中 两者都基于 blaze markup 所以我希望它很容易 diagram1 Svg diagram1 try1 Html try1
  • Haskell,范围缩小到无步骤[重复]

    这个问题在这里已经有答案了 为什么在 Haskell 中工作范围不能降低到没有步骤 7 1 gt 但只工作这个 7 6 1 gt 7 6 5 4 3 2 1 Haskell 无法知道您想要执行 1 除非您给出提示 在某些情况下 您可能需要一
  • 不同 hs 文件中的函数分离时堆栈空间溢出

    我有一个巨大的 haskell 文件 它编译和运行没有任何问题 我想将一些函数和类型定义放在通用 hs 文件中的单独模块中 然后将其导入我的主模块中 虽然主程序编译时没有任何错误 它还编译导入的模块 但当我尝试运行它时 出现堆栈空间溢出 I
  • 如何防止 Nil 将容器恢复为其默认值?

    我正在实现一个简单的链表并表示没有下一个节点的事实 我正在使用该值Nil 问题是当分配给容器时 Nil将尝试将容器恢复为其默认值 这意味着我需要使用容器的默认值或Any确定是否已到达链表的末尾 不过 我还是想用Nil 如果只是为了其明确的意
  • 如何向 Scotty 中间件添加基本身份验证?

    我目前正在制作 Scotty API 但找不到任何 basicAuth 实现的示例 Wai Middleware HttpAuth 具体来说 我想将基本身份验证标头 用户 通行证 添加到我的某些端点 即以 admin 开头的端点 我已经设置
  • 我的 Bitset 的大小是多少?

    我想存储System currentTimeInMillis以尽可能小的空间存储在内存中 因为我必须将数百万个它们存储在内存中 我把它转换为binaryString这给了我41 bits 这是我的程序 public class BitSet
  • 读取结构体定义的二进制文件

    有人可以指出我如何读取由 C 结构体定义的二进制文件的正确方向吗 它的结构内部有一些 define 这让我觉得它会让事情变得复杂 结构看起来像这样 尽管它比这更大 更复杂 struct Format unsigned long str to
  • 有效地合并两个数组 - 一个已排序,另一个未排序

    我正在解决一个问题 该问题有一个由 n 个元素组成的排序数组 后跟一个未排序的长度数组 O logn O 平方 n 如何最有效地对整个列表进行排序 在上述两种情况下我应该使用哪种排序 由于将单个元素插入数组并保持其排序是O n 你不可能变得
  • 对元组列表进行排序的函数 - Haskell

    抱歉 这个简单的问题只是我对 haskell 非常陌生 我正在尝试编写一个函数 order 它将对另一个函数 Frequency 生成的元组列表进行排序 频率计算列表中不同元素的数量 a给出一个这样的结果 比如 gt 频率 aabbbccc
  • 我应该使用什么递归方案来重复有效的操作,直到其结果符合某些标准?

    也就是说 我要问的是一个循环 effectful Int gt IO Int effectful n do putStrLn Effect show n return n condition 3 final Int gt IO final
  • 修订:算法和数据结构

    我需要通过修订来构建和处理数据的想法 例如 我有一个对象数据库 例如汽车 每个对象都有许多属性 这些属性可以是任意的 因此没有一个固定的模式来描述这些对象 这些对象可能保存为键值对 现在我需要更改对象的属性 我不想完全重写它 我希望能够返回
  • 解析 PHOAS 表达式

    我想我理解 PHOAS 参数化高阶抽象语法 我明白了如何漂亮地打印一个表达式 参见http www reddit com r haskell comments 1mo59h phoas for free by edward kmett cc
  • 什么是阴谋地狱?

    在阅读有关 阴谋地狱 的内容时 我有点困惑 因为这个词的含义太多了 我猜最初 Cabal Hell 指的是钻石依赖问题 该问题是通过限制构建计划在每个构建计划中只有任何包的单个版本来解决的 一个包的两个不同版本不能存在于单个构建计划中 正如
  • 嵌套在其他 monad 中的 IO 操作未执行

    我有一个 foobar IO ParseResult String String ParseResult 是一个在这里定义的 monad https hackage haskell org package haskell src exts
  • 将名称绑定到值与将值分配给变量

    阅读 Bartosz Milewski 的文章完整的 https www fpcomplete com school starting with haskell basics of haskell 3 pure functions lazi
  • Haskell 类型定义,=> 等

    我正在使用 Learn You a Haskell 来学习 Haskell 第 54 页上有一个 像这样执行 take Num i Ord i gt i gt a gt a take n n lt 0 take take n x xs x
  • 如何处理或避免BlockedIndefinitelyOnSTM异常?

    我花了很多时间来解决我正在处理的应用程序中遇到的问题 该应用程序是一个 Web 应用程序 使用 scotty 公开 REST 端点 它使用一个TVar保持其更新的状态STM a由前端层触发的动作 由于该应用程序基于事件溯源原则 因此业务层生
  • Haskell 中的多态函数作为参数

    我有一个带有两个构造函数的 ADT 一个包裹着一个Double和一个包裹着Integer 我想创建一个函数 它采用一元函数Numtypeclass 并返回一个函数 该函数将该一元函数应用于我的 ADT 的内容 我试过这个 data X Y
  • 在 Haskell 中创建 100 万个线程需要多长时间?

    据我了解 Haskell 有绿色线程 但它们的重量有多轻 是否可以创建100万个线程 或者 100 000 个线程需要多长时间 from here http www reddit com r programming comments a4n

随机推荐