首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在golang中扁平化递归数据结构的有效方法

在golang中扁平化递归数据结构的有效方法
EN

Stack Overflow用户
提问于 2017-08-18 19:43:55
回答 3查看 2.1K关注 0票数 4

我有一个递归数据结构,它可以包含几种不同类型的数据:

代码语言:javascript
复制
type Data interface{
 // Some methods
}
type Pair struct { // implements Data
  fst Data
  snd Data
}
type Number float64 // implements Data

现在我想把一个Pair链展平成一个[]Data。但是,不应展平fst字段中的Data,只应展平snd中的数据。例如:

代码语言:javascript
复制
chain := Pair{Number(1.0), Pair{Number(2.0), Pair{Number(3.0), nil}}}
chain2 := Pair{Pair{Number(1.0), Number(4.0)}, Pair{Number(2.0), Pair{Number(3.0), nil}}}

变成:

代码语言:javascript
复制
data := []Data{Number(1.0), Number(2.0), Number(3.0)}
data2 := []Data{Pair{Number(1.0), Number(4.0)}, Number(2.0), Number(3.0)}

我天真的方法是:

代码语言:javascript
复制
var data []Data
chain := Pair{Number(1.0), Pair{Number(2.0), Pair{Number(3.0), nil}}}

for chain != nil {
    data = append(data, chain.fst)
    chain = chain.snd
}

有没有一种更有效的方法可以将像变量chain中的数据结构扁平化到[]Data数组中?

EN

回答 3

Stack Overflow用户

发布于 2017-08-18 19:46:51

您可以使用递归函数。在向下的过程中,在底部添加对的数量,分配数组,在返回的过程中,从后到前填充数组。

如果需要支持任意树,可以向Data添加一个size方法,然后执行另一次树遍历以实际填充数组。

票数 2
EN

Stack Overflow用户

发布于 2017-08-19 01:45:49

嗯,你的天真方法对嵌套在fst中的Pair不起作用。如果你有chain := Pair{Pair{Number(1.0), Number(2.0)}, Number{3.0}},它就会变成[]Data{Pair{Number(1.0), Number(2.0)}, Number{3.0}}。这是一个固有的递归问题,所以为什么不这样实现它呢?

我建议在您的接口中添加一个flatten()方法。Pairs可以递归地嵌套自己,而Numbers只是返回它们的值。

下面是一个完整的工作示例,其中包含了一些最少的测试:

代码语言:javascript
复制
package main

import "fmt"

type Data interface {
    flatten() []Data
}

type Pair struct {
    fst Data
    snd Data
}

type Number float64

func (p Pair) flatten() []Data {
    res := []Data{}
    if p.fst != nil {
        res = append(res, p.fst.flatten()...)
    }
    if p.snd != nil {
        res = append(res, p.snd.flatten()...)
    }
    return res
}

func (n Number) flatten() []Data {
    return []Data{n}
}

func main() {
    tests := []Data{
        Pair{Number(1.0), Pair{Number(2.0), Pair{Number(3.0), nil}}},
        Pair{Pair{Number(1.0), Number(2.0)}, Number(3.0)},
        Pair{Pair{Pair{Number(1.0), Number(2.0)}, Pair{Number(3.0), Number(4.0)}}, Pair{Pair{Number(5.0), Number(6.0)}, Number(7.0)}},
        Number(1.0),
    }
    for _, t := range tests {
        fmt.Printf("Original: %v\n", t)
        fmt.Printf("Flattened: %v\n", t.flatten())
    }
}

(这假设顶级输入Data永远不是nil)。

代码打印如下:

代码语言:javascript
复制
Original: {1 {2 {3 <nil>}}}
Flattened: [1 2 3]
Original: {{1 2} 3}
Flattened: [1 2 3]
Original: {{{1 2} {3 4}} {{5 6} 7}}
Flattened: [1 2 3 4 5 6 7]
Original: 1
Flattened: [1]
票数 0
EN

Stack Overflow用户

发布于 2017-08-19 19:27:10

正如所建议的,编写一个递归函数最适合这个问题。但也可以编写一个非递归版本(IMHO递归版本会更清楚):

代码语言:javascript
复制
func flatten(d Data) []Data {
    var res []Data

    stack := []Data{d}

    for {
        if len(stack) == 0 {
            break
        }
        switch x := stack[len(stack)-1].(type) {
        case Pair:
            stack[len(stack)-1] = x.snd
            stack = append(stack, x.fst)
        case Number:
            res = append(res, x)
            stack = stack[:len(stack)-1]
        default:
            if x == nil {
                stack = stack[:len(stack)-1]
            } else {
                panic("INVALID TYPE")
            }
        }
    }

    return res
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/45755873

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档