- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我有点不好意思承认这一点,但我似乎被一个简单的编程问题难住了。我正在构建一个决策树实现,并且一直在使用递归来获取标记样本列表,递归地将列表分成两半,然后将其变成一棵树。
不幸的是,使用深树时,我遇到了堆栈溢出错误(哈!),所以我的第一个想法是使用延续将其转换为尾递归。不幸的是,Scala 不支持这种 TCO,因此唯一的解决方案是使用蹦床。蹦床似乎有点低效,我希望有一些简单的基于堆栈的命令式解决方案来解决这个问题,但我很难找到它。
递归版本看起来有点像(简化):
private def trainTree(samples: Seq[Sample], usedFeatures: Set[Int]): DTree = {
if (shouldStop(samples)) {
DTLeaf(makeProportions(samples))
} else {
val featureIdx = getSplittingFeature(samples, usedFeatures)
val (statsWithFeature, statsWithoutFeature) = samples.partition(hasFeature(featureIdx, _))
DTBranch(
trainTree(statsWithFeature, usedFeatures + featureIdx),
trainTree(statsWithoutFeature, usedFeatures + featureIdx),
featureIdx)
}
}
private def trainTreeNoMaxDepth(startingSamples: Seq[Sample], startingMaxDepth: Int): DTree = {
// Use arraybuffer as dense mutable int-indexed map - no IndexOutOfBoundsException, just expand to fit
type DenseIntMap[T] = ArrayBuffer[T]
def updateIntMap[@specialized T](ab: DenseIntMap[T], idx: Int, item: T, dfault: T = null.asInstanceOf[T]) = {
if (ab.length <= idx) {ab.insertAll(ab.length, Iterable.fill(idx - ab.length + 1)(dfault)) }
ab.update(idx, item)
}
var currentChildId = 0 // get childIdx or create one if it's not there already
def child(childMap: DenseIntMap[Int], heapIdx: Int) =
if (childMap.length > heapIdx && childMap(heapIdx) != -1) childMap(heapIdx)
else {currentChildId += 1; updateIntMap(childMap, heapIdx, currentChildId, -1); currentChildId }
// go down
val leftChildren, rightChildren = new DenseIntMap[Int]() // heapIdx -> childHeapIdx
val todo = Stack((startingSamples, Set.empty[Int], startingMaxDepth, 0)) // samples, usedFeatures, maxDepth, heapIdx
val branches = new Stack[(Int, Int)]() // heapIdx, featureIdx
val nodes = new DenseIntMap[DTree]() // heapIdx -> node
while (!todo.isEmpty) {
val (samples, usedFeatures, maxDepth, heapIdx) = todo.pop()
if (shouldStop(samples) || maxDepth == 0) {
updateIntMap(nodes, heapIdx, DTLeaf(makeProportions(samples)))
} else {
val featureIdx = getSplittingFeature(samples, usedFeatures)
val (statsWithFeature, statsWithoutFeature) = samples.partition(hasFeature(featureIdx, _))
todo.push((statsWithFeature, usedFeatures + featureIdx, maxDepth - 1, child(leftChildren, heapIdx)))
todo.push((statsWithoutFeature, usedFeatures + featureIdx, maxDepth - 1, child(rightChildren, heapIdx)))
branches.push((heapIdx, featureIdx))
}
}
// go up
while (!branches.isEmpty) {
val (heapIdx, featureIdx) = branches.pop()
updateIntMap(nodes, heapIdx, DTBranch(nodes(child(leftChildren, heapIdx)), nodes(child(rightChildren, heapIdx)), featureIdx))
}
nodes(0)
}
最佳答案
只需将二叉树存储在一个数组中,如 Wikipedia 所述: 对于节点 i
,左 child 进入2*i+1
和右边的 child 在 2*i+2
.在执行“向下”操作时,您保留了一组待办事项,这些待办事项仍然需要拆分才能到达一片叶子。一旦你只有叶子,向上(在数组中从右到左)构建决策节点:
更新:一个清理过的版本,它也支持存储在分支中的特性(类型参数 B),并且功能更强大/完全纯粹,并且支持带有 ron 建议的 map 的稀疏树。
更新 2-3:经济地使用节点 id 的 namespace 并抽象 id 的类型以允许大树。从 Stream 中获取节点 ID。
sealed trait DTree[A, B]
case class DTLeaf[A, B](a: A, b: B) extends DTree[A, B]
case class DTBranch[A, B](left: DTree[A, B], right: DTree[A, B], b: B) extends DTree[A, B]
def mktree[A, B, Id](a: A, b: B, split: (A, B) => Option[(A, A, B)], ids: Stream[Id]) = {
@tailrec
def goDown(todo: Seq[(A, B, Id)], branches: Seq[(Id, B, Id, Id)], leafs: Map[Id, DTree[A, B]], ids: Stream[Id]): (Seq[(Id, B, Id, Id)], Map[Id, DTree[A, B]]) =
todo match {
case Nil => (branches, leafs)
case (a, b, id) :: rest =>
split(a, b) match {
case None =>
goDown(rest, branches, leafs + (id -> DTLeaf(a, b)), ids)
case Some((left, right, b2)) =>
val leftId #:: rightId #:: idRest = ids
goDown((right, b2, rightId) +: (left, b2, leftId) +: rest, (id, b2, leftId, rightId) +: branches, leafs, idRest)
}
}
@tailrec
def goUp[A, B](branches: Seq[(Id, B, Id, Id)], nodes: Map[Id, DTree[A, B]]): Map[Id, DTree[A, B]] =
branches match {
case Nil => nodes
case (id, b, leftId, rightId) :: rest =>
goUp(rest, nodes + (id -> DTBranch(nodes(leftId), nodes(rightId), b)))
}
val rootId #:: restIds = ids
val (branches, leafs) = goDown(Seq((a, b, rootId)), Seq(), Map(), restIds)
goUp(branches, leafs)(rootId)
}
// try it out
def split(xs: Seq[Int], b: Int) =
if (xs.size > 1) {
val (left, right) = xs.splitAt(xs.size / 2)
Some((left, right, b + 1))
} else {
None
}
val tree = mktree(0 to 1000, 0, split _, Stream.from(0))
println(tree)
关于scala - 使用 while 循环 + 堆栈编码递归树创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10678510/
出于好奇 - 我知道有 LAMP - Linux、Apache、MySQL 和 PHP。但是还有哪些其他 Web 堆栈替代方案的缩写呢?像 LAMR - Linux、Apache、MySQL Ruby
我有以下代码。 var stackMapIn = []; var stackMapOut = []; var stackBack = []; stackMapOut.push("m1"); $scop
我遇到了导致我的堆栈无法恢复的情况,我别无选择,只能将其删除。使用完全相同的模板,我继续创建了另一个同名的堆栈。 The following resource(s) failed to create:
这是我第一次查看 Node 堆栈,自从我学习使用 Ruby on Rails 进行 Web 开发以来,我对一些基本的东西有点困惑。我了解 Rails 目录是什么样的。 demo/ ..../app .
本文实例讲述了C语言使用深度优先搜索算法解决迷宫问题。分享给大家供大家参考,具体如下: 深度优先搜索 伪代码 (Pseudocode)如下: ?
我正在按照指南 here ,它告诉我: The stack setup will download the compiler if necessary in an isolatedlocation (
同时 trying to debug a different question ,我安装了一个似乎与我安装的其他一些软件包冲突的软件包。 我跑了 $ stack install regex-pcre-
我花了几个小时创建了一个方法,该方法将从堆栈 s1 中获取 null 元素,并将它们放入 s2 中。然后该类应该打印堆栈。方法如下 import net.datastructures.ArraySta
我有一个类Floor,它有一个Stack block ,但我不知道如何初始化它。我曾尝试过这样的: public class Floor { private Stack stack;
我知道这个问题已经问过很多次了,但搜索一个小时后我仍然遇到问题。 我想使用一个 lifo 堆栈,它可以存储最大数量的元素。达到最大数量后,首先删除该元素并将其替换为新元素,这样在第一次弹出时我可以获取
我需要编写一个方法,压缩以执行以下操作; 目标compress方法是从栈s1中移除所有null元素。剩余(非空)元素应按其初始顺序保留在 s1 上。辅助堆栈 s2 应用作s1 中元素的临时存储。在该方
我正在尝试验证以下代码发生的顺序。 function square(n) { return n * n; } setTimeout(function(){ console.log("H
我需要一个字符数组,其中包含基于特定文件夹中文件数量的动态数量的字符数组。我能够通过初始化 char (*FullPathNames)[MAX_FILENAME_AND_PATHNAME_LENGTH
我正在编写一些日志逻辑并想要进行一些缩进。了解是否存在任何函数调用或某个函数是否已完成的最简单方法是查看堆栈/帧的当前地址。让我们假设堆栈颠倒增长。然后,如果 log() 调用中的堆栈地址小于前一次调
所以内存分段在x86-64中被放弃了,但是当我们使用汇编时,我们可以在代码中指定.code和.data段/段,并且还有堆栈指针寄存器。 还有堆栈段、数据段和代码段寄存器。 代码/数据/堆栈的划分是如何
void main() { int x = 5; // stack-allocated Console.WriteLine(x); } 我知道 x 是堆栈分配的。但是关于 x 的堆栈中
这是我关于 SO 的第一个问题。这可能是一个愚蠢的问题,但到目前为止我还没弄明白。 考虑下面的程序 Reader.java: public class Reader { public
java中有没有一种快速的方法来获取嵌套/递归级别? 我正在编写一个函数来创建组及其成员的列表。成员也可以是团体。我们最终可能会得到一组循环的组/成员。 我想在某个任意级别停止。 我知道我可以将变量保
考虑以下代码: struct A{...}; A a[100]; A* pa = new A[100]; delete[] pa; a/pa 元素的销毁顺序是由标准定义的还是实现定义的(对于第二种情况
我在下面有一些代码。此代码是一个基本的压入/弹出堆栈类,我将其创建为模板以允许某人压入/弹出堆栈。我有一个家庭作业,我现在要做的是创建一个具有多个值的堆栈。 所以我希望能够创建一个基本上可以发送三个整
我是一名优秀的程序员,十分优秀!