Golang中的递归数据结构解析与应用
Golang中的递归数据结构解析与应用 我正在尝试弄清楚如何从扁平结构构建树形结构。 我有以下代码:
package main
import "fmt"
//DataFlat 节点
type DataFlat struct {
IDGeoRegion int
IDParent int
Description string
}
func main() {
dFlatlist := []DataFlat{}
dFlat := DataFlat{IDGeoRegion: 1, IDParent: 0, Description: "Organisation"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 2, IDParent: 1, Description: "Office"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 3, IDParent: 2, Description: "Office Zürich"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 4, IDParent: 2, Description: "Office Brazil"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 5, IDParent: 1, Description: "Storage"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 6, IDParent: 5, Description: "Storge Zürich"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 7, IDParent: 5, Description: "Storge Brazil"}
dFlatlist = append(dFlatlist, dFlat)
fmt.Println(dFlatlist)
//结果: [{1 0 Organisation} {2 1 Office} {3 2 Office Zürich} {4 2 Office Brazil} {5 1 Storage} {6 5 Storge Zürich} {7 5 Storge Brazil}]
}
现在我需要一个递归函数来处理 dFlatList 并将其构建为具有以下格式的树形结构:
type GeoTree struct {
IDGeoRegion int
IDParent int
Description string
Children []*GeoTree
}
任何帮助或建议都将不胜感激。
谢谢
更多关于Golang中的递归数据结构解析与应用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
你好 Shubh,
你的解决方案完美地解决了问题,这正是我一直在寻找的。
非常感谢!
更多关于Golang中的递归数据结构解析与应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
我在if条件处添加了一条注释。你可以创建一个队列,用于存储那些父节点不在映射中的平面节点,然后在for循环之后遍历该队列,并再次执行相同的操作。
分两步构建 GeoTree。第一步,扫描 dataFlat 并通过将 GeoTree 元素以其 ID 作为键存储在映射中来实例化所有元素。在此步骤中,忽略 parentID。第二步,重新扫描 dataFlat,在映射中找到对应的 GeoTree 元素,并将其添加为对应父元素的子元素。
我按照Shubh的建议,为那些父节点不在映射中的节点创建了一个队列,然后对这个队列进行循环处理。
这个方法可行,我可以这样使用它。再次感谢您的帮助!
我很喜欢Christoph的建议,那听起来是个好方法。我需要研究一下,看看能否自己解决这个问题。
我尝试了使用基于映射的方法来创建一棵树。如果我的理解正确,对于子节点来说,IDParent 将是其父节点的 IDGeoRegion。
func (g GeoTree) print() {
var list []GeoTree
list = append(list, g)
i := 0
for {
element := list[i]
fmt.Println(element)
for _, value := range element.Children {
list = append(list, *value)
}
i++
if i == len(list) {
break
}
}
}
func addNode(d DataFlat) (g GeoTree) {
g.IDGeoRegion = d.IDGeoRegion
g.IDParent = d.IDParent
g.Description = d.Description
return
}
在主函数内部添加以下代码:
root := addNode(dFlatlist[0])
m := map[int]*GeoTree{}
m[root.IDGeoRegion] = &root
for i := 1; i < len(dFlatlist); i++ {
if m[dFlatlist[i].IDParent] == nil {
fmt.Println("parent does not exist", dFlatlist[i].IDGeoRegion) // 我们可以创建一个队列来存储这些扁平数据,而不是直接打印,然后在此循环之后,重新遍历这个队列并再次尝试添加。
} else {
node := addNode(dFlatlist[i])
m[dFlatlist[i].IDParent].Children = append(m[dFlatlist[i].IDParent].Children, &node)
m[dFlatlist[i].IDGeoRegion] = &node
}
}
root.print()
起初,这个方法看起来对我有效,但我遇到了一个问题。上述解决方案似乎要求扁平数据列表的顺序是正确的,但在我的情况下,我不能确定这一点。
如果我构建的扁平列表是无序的,例如,在“Storage”之前插入了“Storage Zürich and Storage Brazil”,那么该解决方案将无法工作。
当唯一能保证的是列表中的第一个条目是根元素,但之后的条目未排序时,是否仍有办法实现这个功能?
以下是由于 dFlatlist 顺序问题而无法正常工作的代码:
package main
import "fmt"
//DataFlat node
type DataFlat struct {
IDGeoRegion int `json:"idgeoregion" db:"IdGeoRegion"`
IDParent int `json:"idparent" db:"IdParent"`
Description string `json:"description" db:"Description"`
}
//GeoTree tree
type GeoTree struct {
IDGeoRegion int `json:"idgeoregion" db:"IdGeoRegion"`
IDParent int `json:"idparent" db:"IdParent"`
Description string `json:"description" db:"Description"`
Children []*GeoTree
}
func main() {
dFlatlist := []DataFlat{}
dFlat := DataFlat{IDGeoRegion: 1, IDParent: 0, Description: "Organisation"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 6, IDParent: 5, Description: "Storge Zürich"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 7, IDParent: 5, Description: "Storge Brazil"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 2, IDParent: 1, Description: "Office"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 3, IDParent: 2, Description: "Office Zürich"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 4, IDParent: 2, Description: "Office Brazil"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 5, IDParent: 1, Description: "Storage"}
dFlatlist = append(dFlatlist, dFlat)
//fmt.Println(dFlatlist)
//Result: [{1 0 Organisation} {2 1 Office} {3 2 Office Zürich} {4 2 Office Brazil} {5 1 Storage} {6 5 Storge Zürich} {7 5 Storge Brazil}]
root := addNode(dFlatlist[0])
m := map[int]*GeoTree{}
m[root.IDGeoRegion] = &root
for i := 1; i < len(dFlatlist); i++ {
if m[dFlatlist[i].IDParent] == nil {
fmt.Println("parent does not exist", dFlatlist[i].IDGeoRegion)
} else {
node := addNode(dFlatlist[i])
m[dFlatlist[i].IDParent].Children = append(m[dFlatlist[i].IDParent].Children, &node)
m[dFlatlist[i].IDGeoRegion] = &node
}
}
root.print()
}
func (g GeoTree) print() {
var list []GeoTree
list = append(list, g)
i := 0
for {
element := list[i]
fmt.Println(element)
for _, value := range element.Children {
list = append(list, *value)
}
i++
if i == len(list) {
break
}
}
}
func addNode(d DataFlat) (g GeoTree) {
g.IDGeoRegion = d.IDGeoRegion
g.IDParent = d.IDParent
g.Description = d.Description
return
}
以下是一个从扁平结构构建树形结构的递归实现:
package main
import "fmt"
// DataFlat 扁平节点
type DataFlat struct {
IDGeoRegion int
IDParent int
Description string
}
// GeoTree 树形节点
type GeoTree struct {
IDGeoRegion int
IDParent int
Description string
Children []*GeoTree
}
// BuildTree 构建树形结构的递归函数
func BuildTree(flatData []DataFlat, parentID int) []*GeoTree {
var tree []*GeoTree
for _, item := range flatData {
if item.IDParent == parentID {
node := &GeoTree{
IDGeoRegion: item.IDGeoRegion,
IDParent: item.IDParent,
Description: item.Description,
Children: BuildTree(flatData, item.IDGeoRegion),
}
tree = append(tree, node)
}
}
return tree
}
// PrintTree 递归打印树形结构
func PrintTree(tree []*GeoTree, level int) {
for _, node := range tree {
indent := ""
for i := 0; i < level; i++ {
indent += " "
}
fmt.Printf("%s%d: %s\n", indent, node.IDGeoRegion, node.Description)
if len(node.Children) > 0 {
PrintTree(node.Children, level+1)
}
}
}
func main() {
dFlatlist := []DataFlat{}
dFlat := DataFlat{IDGeoRegion: 1, IDParent: 0, Description: "Organisation"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 2, IDParent: 1, Description: "Office"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 3, IDParent: 2, Description: "Office Zürich"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 4, IDParent: 2, Description: "Office Brazil"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 5, IDParent: 1, Description: "Storage"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 6, IDParent: 5, Description: "Storge Zürich"}
dFlatlist = append(dFlatlist, dFlat)
dFlat = DataFlat{IDGeoRegion: 7, IDParent: 5, Description: "Storge Brazil"}
dFlatlist = append(dFlatlist, dFlat)
// 构建树形结构
tree := BuildTree(dFlatlist, 0)
// 打印树形结构
fmt.Println("树形结构:")
PrintTree(tree, 0)
// 访问特定节点
fmt.Println("\n根节点及其子节点:")
for _, root := range tree {
fmt.Printf("根节点: %s (ID: %d)\n", root.Description, root.IDGeoRegion)
for _, child := range root.Children {
fmt.Printf(" 子节点: %s (ID: %d)\n", child.Description, child.IDGeoRegion)
}
}
}
输出结果:
树形结构:
1: Organisation
2: Office
3: Office Zürich
4: Office Brazil
5: Storage
6: Storge Zürich
7: Storge Brazil
根节点及其子节点:
根节点: Organisation (ID: 1)
子节点: Office (ID: 2)
子节点: Storage (ID: 5)
如果需要更高效的实现,可以使用映射来减少递归搜索:
// BuildTreeEfficient 使用映射构建树形结构
func BuildTreeEfficient(flatData []DataFlat) []*GeoTree {
// 创建映射:ID -> 节点
nodeMap := make(map[int]*GeoTree)
// 创建所有节点
for _, item := range flatData {
nodeMap[item.IDGeoRegion] = &GeoTree{
IDGeoRegion: item.IDGeoRegion,
IDParent: item.IDParent,
Description: item.Description,
Children: []*GeoTree{},
}
}
// 构建树形结构
var roots []*GeoTree
for _, node := range nodeMap {
if node.IDParent == 0 {
roots = append(roots, node)
} else {
if parent, exists := nodeMap[node.IDParent]; exists {
parent.Children = append(parent.Children, node)
}
}
}
return roots
}
这个实现的时间复杂度为O(n),比纯递归实现更高效。

