package main

import (

"encoding/json"

"fmt"

"os"

"path/filepath"

"sort"

)

func main() {

rootpath := "D:\\projects"

root := FileNode{"projects", rootpath, []*FileNode{}}

fileInfo, _ := os.Lstat(rootpath)

walk(rootpath, fileInfo, &root)

data, _ := json.Marshal(root)

fmt.Printf("%s", data)

}

type FileNode struct {

Name string `json:"name"`

Path string `json:"path"`

FileNodes []*FileNode `json:"children"`

}

func walk(path string, info os.FileInfo, node *FileNode) {

// 列出当前目录下的所有目录、文件

files := listFiles(path)

// 遍历这些文件

for _, filename := range files {

// 拼接全路径

fpath := filepath.Join(path, filename)

// 构造文件结构

fio, _ := os.Lstat(fpath)

// 将当前文件作为子节点添加到目录下

child := FileNode{filename, fpath, []*FileNode{}}

node.FileNodes = append(node.FileNodes, &child)

// 如果遍历的当前文件是个目录,则进入该目录进行递归

if fio.IsDir() {

walk(fpath, fio, &child)

}

}

return

}

func listFiles(dirname string) []string {

f, _ := os.Open(dirname)

names, _ := f.Readdirnames(-1)

f.Close()

sort.Strings(names)

return names

}

利用自我内部循环——也就是无限递归——避免之前用那种比较傻的方式:4级菜单就用4个struct嵌套。并循环for也是4层。

if fio.IsDir() {

walk(fpath, fio, &child)

}

实现无限级struct嵌套,转成json,供treeview使用,即无限级树状菜单。

好吧我忘了提一个很dirty的方法。

如果你的树深度是可预期的话,有个超简单的数据结构。你需要3个字段来表达这个树:

id,本节点的primary key

parent_id,其值为父节点的primary key

key,忘了学名叫啥了,你可以称为线索

level,表示当前节点到根节点的距离

其中,key字段的值为:从跟节点到父节点的primary key,中间用任意非数字符号分割。

例如以下树状结构

├── a

│   ├── d

│   │   ├── p

│   │   ├── q

│   │   └── r

│   ├── e

│   └── f

├── b

│   ├── x

│   ├── y

│   └── z

├── c

对应的数据库表值为:

| id | value | parent_id | key | level |

| 1 | a | 0 | "-" | 1 |

| 2 | b | 0 | "-" | 1 |

| 3 | c | 0 | "-" | 2 |

| 4 | d | 1 | "1-" | 2 |

| 5 | e | 1 | "1-" | 2 |

| 6 | f | 1 | "1-" | 2 |

| 7 | x | 2 | "2-" | 2 |

| 8 | y | 2 | "2-" | 2 |

| 9 | z | 2 | "2-" | 2 |

| 10 | p | 4 | "1-4-" | 3 |

| 11 | q | 4 | "1-4-" | 3 |

| 12 | r | 4 | "1-4-" | 3 |

于是,在给定一个节点d的时候,

查找d的所有子孙节点:select * from table_name where key

like "${d.key}-${d.id}-%"

查找某个节点的所有子节点:select * from table_name where key

like "${d.key}-${d.id}-%" and level=${d.level}+1

这个设计,结构非常简单。key和level是辅助字段,维护这两个字段成本很低,即使全部重建要比MPT简单多了。

yegle2.5k 声望

yegle的数据错了吧?根节点的 key应该是""

吧。查找d的所有子孙节点应该是 select * from table_name where key like "${d.key}${d.id}-%" 查找子节点应该是: select * from table_name where key like "${d.key}${d.id}-%" and level=${d.level}+1

2014年06月28日

+1

的确,应该按照@Rory_Ye 说的才对。否则,一级节点无法查看自己的子孙节点。

faker · 6月3日

我刚去看了Modified Preorder Tree,我有疑问的是如果我添加一个字节点,那么数据库的表不是都得改?这个树和线段树类似啊。

当我没说,原来是数据库,我以为是 java web,哈哈

查询的时候用的是like,会高效吗?

有疑问加站长微信联系(非本文作者)