递归并集:它是如何真正发挥作用?(Recursive set union: how does it

2019-09-01 03:21发布

我目前正在对Coursera斯卡拉当然工作后,我的空闲时间,企图最后给一个尝试函数式编程。 我目前的工作在哪里,我们都应该为“计算”的包含一些对象两套工会的任务。 我有意忽略的细节,因为它不是什么我想在这里问真的很重要。 什么是相关的,但是,是在集被定义为二进制树,含有元素的每个节点,和两个子树。

既然如此; 的例子中union在演讲如下:

def union(other:BTSet) :BTSet = ((left union right) union other) incl element

问题1:坦率地说,即使在看了相关的常见问题等论坛主题,我还是不明白如何以及为什么此功能。 绝对没有任何“动作”在这里做工会执行除了会增加(在incl调用)在头节点的元素,它只是自称一遍又一遍。 我会很感激的一些解释...

问题2:该课程论坛包含了许多帖子,指出这个解决方案不是有效的一切,这是不够好。 眼看我不明白它是如何与我开始不明白为什么这还不够好。

请注意,我不以任何方式,询问分配解决方案扰流板。 我更愿意以“为等级做的工作”以上,但我根本不明白我应该在这里做。 我不相信在使用过程中提供的说明和指导,足以环绕函数式编程的怪癖你的头,所以我欢迎任何的意见/,解决怎么想的权利 ,而不是如何编写正确的答案。

Answer 1:

  A
 / \  union  D
B   C

((B union C) union D) incl A
  ^^^^^^^^^......................................assume it works

(  B             )
(    \   union D ) incl A
(     C          )

(((0 union C) union D) incl B) incl A
   ^^^^^^^^^.....................................just C

(((C union D) incl B) incl A
   ^^^^^^^^^.....................................expand

((((0 union 0) union D) incl C) incl B) incl A
    ^^^^^^^^^....................................just 0

(((0 union D) incl C) incl B) incl A
   ^^^^^^^^^.....................................just D

((D incl C) incl B) incl A
^^^^^^^^^^^^^^^^^^^^^^^^^^.......................all incl now

只是把它写出来一步一步来。 现在你看到工会降低了一堆应用到右手的说法含语句。



Answer 2:

我推测, incl插入一个元素现有的一组? 如果是这样,这就是所有的实际工作中发生的事情。

工会的定义是包括在任一输入集中的所有设定。 由于两套存储为二进制树,如果你把第一组与第二的分支工会,在任何可能的结果会丢失的唯一因素是在第二树的根节点元素,因此,如果你插入你有两个输入集合的并集该元素。

这只是从两个组,每个组元素插入一个新的一套开始是空的非常低效的方式。 据推测重复被丢弃incl ,所以结果是两个输入的结合。


也许这将有助于忽略的树结构的那一刻; 它不是必要的算法非常重要。 假设我们有抽象的数学套。 鉴于输入与未知元素设定,我们可以做两分事情的事情:

  • 元素添加到它(这什么也不做,如果元素已经存在)
  • 检查组是否非空,如果是这样,它分解成一个单一的元素,两个不相交的子集。

为了利用两套{1,2}和{2,3}的联合,我们开始通过分解所述第一组到元件1和子集{}和{2}。 我们递归采取的{},{2},并使用相同的工艺{2,3},然后插入1联合到结果。

在每个步骤中,问题是从一个联合操作减少到较小输入的两个联合操作; 标准分而治之算法。 当到达一个单集{X}和空集{}的并集,工会是平凡{X},然后将其返回备份链。

树形结构只是用来都允许的情况下分析/分解成更小的集合,并且使插入更有效。 同样可以使用其他数据结构,诸如被分成两半用于分解,并用插入由一个详尽检查唯一完成列表来完成。 要采取有效的联合需要一个算法,更聪明一点,并采取用于存储元件结构的优势。



Answer 3:

因此,基于以上所有的答复,我认为真正的主力是incl和调用的递归的方式union仅仅是通过集合所有元素去。

我想出了以下实现联盟,这是更好?

def union(other:BTSet) :BTSet = right union (left union (other incl element))


Answer 4:

  2
 / \  union  4
1   3

((1 union 3) union 4) incl 2
  ^^^^^^^^^......................................assume it works

(((E union E) union 3 incl 1) union 4) incl 2
   ^^^^^^^^^.....................................still E

(E union E) union 3 incl 1 = E union 3 incl 1 = 3 incl 1

以下子树应该是3 1

(  3             ) 
(    \   union D ) incl 2
(      1         )


(((1 union E) union 4) incl 3) incl 2
   ^^^^^^^^^.......................................expand

(((( (E union E) union E) incl 1) union 4) incl 3) incl 2
      ^^^^^^^^^^^^^^^^^^^^^^^^^^..................still 1

((1 union 4) incl 3) incl 2
   ^^^^^^^^......................................continue

((((E union E) union 4) incl 1) incl 3) incl 2
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^..........expand 1 union 4

((4 incl 1) incl 3) incl 2
  ^^^^^^^^^^^^^^^^^^^^^^^^^............Final union result 

由于@Rex克尔引出的步骤。 我代替与实际运行时的步骤,其可以得到的Scala的更清楚的描述在第二步骤union功能。



Answer 5:

除非你看看基本情况你可以不理解递归算法。 事实上,通常情况下,理解的关键在于首先了解基本情况。 由于没有显示基本情况(可能是因为你没有注意到有一个摆在首位)没有理解可能。



Answer 6:

我在做相同的课程,和上述实施union也变成是非常低效的。

我想出了以下不那么实用的解决方案,以创造二叉树集的结合,这是远远更有效率:

def union(that: BTSet): BTSet = {
  var result:BTSet = this
  that.foreach(element => result = result.incl(element))
  result
}


文章来源: Recursive set union: how does it work really?