在golang中展平递归数据结构的有效方法

时间:2017-08-18 11:43:55

标签: arrays go data-structures

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

type Data interface{
 // Some methods
}
type Pair struct { // implements Data
  fst Data
  snd Data
}
type Number float64 // implements Data

现在我想将Pair链变为[]Data。但是,Data字段中的fst不应该展平,只应将snd中的数据展平。例如:

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}}}

变为:

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)}

我天真的做法是:

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数组?

3 个答案:

答案 0 :(得分:1)

您可以使用递归功能。在向下的路上,添加对的数量,在底部,分配数组,并在返回的路上,从后到前填充数组。

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

答案 1 :(得分:0)

嗯,你的幼稚方法不适用Pair嵌套在fst内的chain := Pair{Pair{Number(1.0), Number(2.0)}, Number{3.0}}。如果您有[]Data{Pair{Number(1.0), Number(2.0)}, Number{3.0}},则最终为flatten()。这是一个固有的递归问题,为什么不这样实现呢?

我建议在您的界面中添加Pair方法。 Number可以递归地嵌套自己,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永远不会是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]

代码打印:

{{1}}

答案 2 :(得分:0)

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

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
}