![](/img/trans.png)
[英]What container type provides better (average) performance than std::map?
[英]Trim a Multiway Tree - what is a better solution?
我想知道是否有人可以为以下问题提供更简化的解决方案或对我的代码进行改进。
假设我们有一棵树,其分支的深度达到“ d”,并且我们想要修剪这棵树,这样我们就可以在深度d保留“ n”个分支,然后在深度d-1保留另一个n分支; 然后在d-2处又有n个分支,等等。
在我的解决方案中,我需要借助dictionary
来跟踪分支的数量,并ref
可变深度来跟踪并降低深度级别
知道一个更简单,更优雅的解决方案,或改善我所拥有的任何提示/技巧将非常有兴趣
数据结构
type MultiTree = | MNode of int * list<MultiTree>
测试树
let Mtree2 = MNode (0,
[MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])]);
MNode (1,[MNode (2,[MNode (3,[])])])])
修剪树功能
let trimTree noLosses depth t=
let mlimit = ref depth
let dict = Dictionary()
let fn k =
match dict.TryGetValue(k) with
| true, l -> dict.[k] <- l + 1
|_ -> dict.Add(k,1)
if dict.[k] >= noLosses then mlimit := !mlimit - 1 else mlimit := !mlimit
let rec loop d t =
match t with
| MNode(i,sub) when d > !mlimit ->
fn !mlimit
MNode(i, List.map (loop (d+1)) [])
| MNode(i,sub) -> MNode(i, List.map (loop (d+1)) sub)
loop 1 t
let Mtree2trimmed = Mtree2 |> trimTree 3 2
结果
使用Thomas P的“ printTree”函数,可以很好地实现可视化
let printt tree =
let rec loop depth (MNode(n, sub)) =
printfn "%s %A" depth n
for s in sub do loop (depth + " ") s
loop "" tree
输出-
printt Mtree2
0
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
1
2
3
输出-
printt Mtree2trimmed
0
1
2
1
2
1
2
1
1
1
因此,如果您已经做到了这一点-有什么建议吗?
干杯!
这个问题称为mapreduce 。 基本方法如下:
让我们用补充值标记每个分支:
depth
( 0
=最上面的分支) sequential
(对于每个子树,从0
开始) 为了实现这一点,我更改了树的定义,使其具有通用性:
type MultiTree<'T> = | MNode of 'T * list<MultiTree<'T>>
现在:
let rec mapper depth sequential = function
| MNode(value, sub) ->
MNode( (depth, sequential, value),
(sub |> List.mapi (fun i value -> mapper (depth+1) i value))
)
let tree1 = MNode (0,
[MNode (1,[MNode (2,[])]);
MNode (3,[]);])
printfn "Original data"
tree1 |> printt
printfn "Mapped data"
tree1 |> mapper 0 0 |> printt
结果将是:
Original data
0
1
2
3
Mapped data
(0, 0, 0)
(1, 0, 1)
(2, 0, 2)
(1, 1, 3)
现在,在标记数据后,我们可以应用所需的任何过滤器。 这是三个示例,外加一棵更大的树来演示所有可能性:
// Take only first n branches at every level
let rec filter1 n = function
// first subtrees pass (up to "noLosses" count)
| MNode( (depth, sequential, value), sub)
when sequential < n
-> Some(MNode(value, List.choose (filter1 n) sub))
// the rest are skipped
| _ -> None
// Take "d" levels of branches unchanged, at higher levels take only second branch
let rec filter2 d = function
| MNode( (depth, sequential, value), sub)
when depth < d // lower depth - pass
|| sequential = 1 // at higher levels, take only the second branch (=1)
-> Some(MNode(value, List.choose (filter2 d) sub))
// the rest are skipped
| _ -> None
// Take only first n branches at every level;
// "n" is a list to identify maximal element at each level
let rec filter3 ns ts =
match ns, ts with
// Empty "noLosse" list -> no value
| [], _ -> None
// if the sequential order of Tree branch is less than
// the corresponding value in "ns" list, let the value pass the filter
| nsHead :: nsTail, MNode((_, sequential, value), sub)
when sequential < nsHead -> Some(MNode(value, List.choose (filter3 nsTail) sub))
// the rest are skipped
| _, _ -> None
printfn "Original data"
tree2 |> printt
printfn "Filter1 applied"
tree2 |> mapper 0 0 |> filter1 2 |> Option.iter printt
printfn "Filter2 applied"
tree2 |> mapper 0 0 |> filter2 2 |> Option.iter printt
printfn "Filter3 applied"
tree2 |> mapper 0 0 |> filter3 [4; 4; 2] |> Option.iter printt
注意,我们需要Option.iter
因为过滤器可能返回None
值。
输出:
Original data
1
11
111
1111
1112
1113
12
121
1211
122
1221
1222
1223
123
124
13
131
1211
14
141
1411
15
151
1511
16
161
1611
Filter1 applied
1
11
111
1111
1112
12
121
1211
122
1221
1222
Filter2 applied
1
11
12
122
1222
13
14
15
16
Filter3 applied
1
11
111
12
121
122
13
131
14
141
需要注意的是,这种方法并未针对性能进行优化。 其主要思想是展示如何将任务分解为一系列较小的任务,以便实际过滤实际上是一个简单的匹配情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.