golang 實(shí)現(xiàn)菜單樹的生成方式
golang 實(shí)現(xiàn)菜單樹的生成,包括菜單節(jié)點(diǎn)的選中狀態(tài)、半選中狀態(tài),菜單的搜索。
1 該包提供兩個(gè)方法根接口
1.1 GenerateTree(nodes, selectedNodes []INode) (trees []Tree)
GenerateTree 自定義的結(jié)構(gòu)體實(shí)現(xiàn) INode 接口后調(diào)用此方法生成樹結(jié)構(gòu)。
1.2 FindRelationNode(nodes, allNodes []INode) (respNodes []INode)
FindRelationNode 在 allTree 中查詢 nodes 中節(jié)點(diǎn)的所有父子節(jié)點(diǎn) 返回 respNodes(包含 nodes , 跟其所有父子節(jié)點(diǎn))
1.3 接口 INode
// ConvertToINodeArray 其他的結(jié)構(gòu)體想要生成菜單樹,直接實(shí)現(xiàn)這個(gè)接口 type INode interface { // GetTitle 獲取顯示名字 GetTitle() string // GetId獲取id GetId() int // GetFatherId 獲取父id GetFatherId() int // GetData 獲取附加數(shù)據(jù) GetData() interface{} // IsRoot 判斷當(dāng)前節(jié)點(diǎn)是否是頂層根節(jié)點(diǎn) IsRoot() bool }
2 使用
go get github.com/azhengyongqin/golang-tree-menu
2.1 定義自己的菜單結(jié)構(gòu)體并且實(shí)現(xiàn)接口 INode
// 定義我們自己的菜單對(duì)象 type SystemMenu struct { Id int `json:"id"` //id FatherId int `json:"father_id"` //上級(jí)菜單id Name string `json:"name"` //菜單名 Route string `json:"route"` //頁(yè)面路徑 Icon string `json:"icon"` //圖標(biāo)路徑 } func (s SystemMenu) GetTitle() string { return s.Name } func (s SystemMenu) GetId() int { return s.Id } func (s SystemMenu) GetFatherId() int { return s.FatherId } func (s SystemMenu) GetData() interface{} { return s } func (s SystemMenu) IsRoot() bool { // 這里通過(guò)FatherId等于0 或者 FatherId等于自身Id表示頂層根節(jié)點(diǎn) return s.FatherId == 0 || s.FatherId == s.Id }
2.2 實(shí)現(xiàn)一個(gè)將自定義結(jié)構(gòu)體SystemMenu 數(shù)組轉(zhuǎn)換成 INode 數(shù)組的方法
type SystemMenus []SystemMenu // ConvertToINodeArray 將當(dāng)前數(shù)組轉(zhuǎn)換成父類 INode 接口 數(shù)組 func (s SystemMenus) ConvertToINodeArray() (nodes []INode) { for _, v := range s { nodes = append(nodes, v) } return }
3 測(cè)試效果
3.1 添加測(cè)試數(shù)據(jù)
// 模擬獲取數(shù)據(jù)庫(kù)中所有菜單,在其它所有的查詢中,也是首先將數(shù)據(jù)庫(kù)中所有數(shù)據(jù)查詢出來(lái)放到數(shù)組中, // 后面的遍歷遞歸,都在這個(gè) allMenu中進(jìn)行,而不是在數(shù)據(jù)庫(kù)中進(jìn)行遞歸查詢,減小數(shù)據(jù)庫(kù)壓力。 allMenu := []SystemMenu{ {Id: 1, FatherId: 0, Name: "系統(tǒng)總覽", Route: "/systemOverview", Icon: "icon-system"}, {Id: 2, FatherId: 0, Name: "系統(tǒng)配置", Route: "/systemConfig", Icon: "icon-config"}, {Id: 3, FatherId: 1, Name: "資產(chǎn)", Route: "/asset", Icon: "icon-asset"}, {Id: 4, FatherId: 1, Name: "動(dòng)環(huán)", Route: "/pe", Icon: "icon-pe"}, {Id: 5, FatherId: 2, Name: "菜單配置", Route: "/menuConfig", Icon: "icon-menu-config"}, {Id: 6, FatherId: 3, Name: "設(shè)備", Route: "/device", Icon: "icon-device"}, {Id: 7, FatherId: 3, Name: "機(jī)柜", Route: "/device", Icon: "icon-device"}, }
3.2 生成完全樹
// 生成完全樹 resp := GenerateTree(SystemMenus.ConvertToINodeArray(allMenu), nil) bytes, _ := json.MarshalIndent(resp, "", "\t") fmt.Println(string(bytes))
[ { "title": "系統(tǒng)總覽", "leaf": false, "checked": false, "partial_selected": false, "children": [ { "title": "資產(chǎn)", "leaf": false, "checked": false, "partial_selected": false, "children": [ { "title": "設(shè)備", "leaf": true, "checked": false, "partial_selected": false, "children": null }, { "title": "機(jī)柜", "leaf": true, "checked": false, "partial_selected": false, "children": null } ] }, { "title": "動(dòng)環(huán)", "leaf": true, "checked": false, "partial_selected": false, "children": null } ] }, { "title": "系統(tǒng)配置", "leaf": false, "checked": false, "partial_selected": false, "children": [ { "title": "菜單配置", "leaf": true, "checked": false, "partial_selected": false, "children": null } ] } ]
3.3 帶選中狀態(tài)和半選中狀態(tài)的樹
// 模擬選中 '資產(chǎn)' 菜單 selectedNode := []SystemMenu{allMenu[2]} resp = GenerateTree(SystemMenus.ConvertToINodeArray(allMenu), SystemMenus.ConvertToINodeArray(selectedNode)) bytes, _ = json.Marshal(resp) fmt.Println(string(pretty.Color(pretty.PrettyOptions(bytes, pretty.DefaultOptions), nil)))
[ { "title": "系統(tǒng)總覽", "leaf": false, "checked": false, "partial_selected": true, "children": [ { "title": "資產(chǎn)", "leaf": false, "checked": true, "partial_selected": false, "children": [ { "title": "設(shè)備", "leaf": true, "checked": true, "partial_selected": false, "children": null }, { "title": "機(jī)柜", "leaf": true, "checked": true, "partial_selected": false, "children": null } ] }, { "title": "動(dòng)環(huán)", "leaf": true, "checked": false, "partial_selected": false, "children": null } ] }, { "title": "系統(tǒng)配置", "leaf": false, "checked": false, "partial_selected": false, "children": [ { "title": "菜單配置", "leaf": true, "checked": false, "partial_selected": false, "children": null } ] } ]
3.4 模擬查詢某個(gè)節(jié)點(diǎn),然后生成樹
// 模擬從數(shù)據(jù)庫(kù)中查詢出 '設(shè)備' device := []SystemMenu{allMenu[5]} // 查詢 `設(shè)備` 的所有父節(jié)點(diǎn) respNodes := FindRelationNode(SystemMenus.ConvertToINodeArray(device), SystemMenus.ConvertToINodeArray(allMenu)) resp = GenerateTree(respNodes, nil) bytes, _ = json.Marshal(resp) fmt.Println(string(pretty.Color(pretty.PrettyOptions(bytes, pretty.DefaultOptions), nil)))
[ { "title": "系統(tǒng)總覽", "leaf": false, "checked": false, "partial_selected": false, "children": [ { "title": "資產(chǎn)", "leaf": false, "checked": false, "partial_selected": false, "children": [ { "title": "設(shè)備", "leaf": true, "checked": false, "partial_selected": false, "children": null } ] } ] } ]
源碼地址:https://github.com/azhengyongqin/golang-tree-menu
補(bǔ)充:golang實(shí)現(xiàn)prim算法,計(jì)算最小生成樹
1、題目描述
給定一個(gè)n個(gè)點(diǎn)m條邊的無(wú)向圖,圖中可能存在重邊和自環(huán),邊權(quán)可能為負(fù)數(shù)。
求最小生成樹的樹邊權(quán)重之和,如果最小生成樹不存在則輸出impossible。
給定一張邊帶權(quán)的無(wú)向圖G=(V, E),其中V表示圖中點(diǎn)的集合,E表示圖中邊的集合,n=|V|,m=|E|。
由V中的全部n個(gè)頂點(diǎn)和E中n-1條邊構(gòu)成的無(wú)向連通子圖被稱為G的一棵生成樹,其中邊的權(quán)值之和最小的生成樹被稱為無(wú)向圖G的最小生成樹。
輸入格式
第一行包含兩個(gè)整數(shù)n和m。
接下來(lái)m行,每行包含三個(gè)整數(shù)u,v,w,表示點(diǎn)u和點(diǎn)v之間存在一條權(quán)值為w的邊。
輸出格式
共一行,若存在最小生成樹,則輸出一個(gè)整數(shù),表示最小生成樹的樹邊權(quán)重之和,如果最小生成樹不存在則輸出impossible。
2、數(shù)據(jù)
數(shù)據(jù)范圍
1≤n≤500,
1≤m≤105,
圖中涉及邊的邊權(quán)的絕對(duì)值均不超過(guò)10000。
輸入樣例:
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
輸出樣例:
6
數(shù)據(jù)圖
1、初始所有點(diǎn)的距離為正無(wú)窮,就是代碼中的0x3f3f3f3f等于1061109567
2、以第一個(gè)點(diǎn)為最初點(diǎn),綠色表示選中,進(jìn)入到最小生成樹中
3、以第一個(gè)更新其他與之連通的點(diǎn)的距離
4、依次迭代
5、最后的最小生成樹
3、樸素prim算法步驟時(shí)間復(fù)雜度O(n^2)
1、先初始化所有點(diǎn)距離為正無(wú)窮
2、迭代n次,依次用到集合的最小點(diǎn)更新剩余點(diǎn)距離
3、將已經(jīng)確定的點(diǎn)加入到st集合中,st數(shù)組為一個(gè)bool類型
4、代碼實(shí)現(xiàn)
/* 該圖是稠密圖,使用鄰接矩陣 */ package main import ( "bufio" "fmt" "os" "strconv" "strings" ) const ( N = 510 INF = 0x3f3f3f3f ) var ( n, m int dist [N]int g [N][N]int st [N]bool ) func readLine(r *bufio.Reader) []int { s, _ := r.ReadString('\n') ss := strings.Fields(s) res := make([]int, len(ss)) for i, v := range ss { res[i], _ = strconv.Atoi(v) } return res } func prim() int { // 初始化距離集合 dist for i := 0; i < N; i++ { dist[i] = 0x3f3f3f3f } // 迭代n次 res := 0 //res 存儲(chǔ)最小生成樹的大小即邊的長(zhǎng)度總和 for i := 0; i < n; i++ { // 找到集合外距離最短的點(diǎn) t := -1 for j := 1; j <= n; j++ { if !st[j] && (t == -1 || dist[t] > dist[j]) { t = j } } // 迭代結(jié)束,此時(shí)的t就是距離最小點(diǎn) // 情況一:圖上的點(diǎn)不連通,不能組成最小生成樹 if i > 0 && dist[t] == INF { return INF } // 如果不是第一個(gè)點(diǎn)并且最小店的距離是正無(wú)窮,則表示圖是不連通的 if i > 0 { res += dist[t] } // 如果不是第一個(gè)點(diǎn),這個(gè)t就表示當(dāng)前點(diǎn)到集合某一個(gè)點(diǎn)的最小距離 // 用最小距離點(diǎn)更新其他跟 "現(xiàn)階段形成的生成樹" 的最短距離, //注意更新的順序,自環(huán)是不應(yīng)該被加到最小生成樹,所以,為了避免自環(huán)加入最小生成樹,提前更新res for j := 1; j <= n; j++ { dist[j] = min(dist[j], g[t][j]) // 此步驟注意是dijkstra的區(qū)別, } st[t] = true } return res } func min(a, b int) int { if a >= b { return b } else { return a } } func main() { r := bufio.NewReader(os.Stdin) input := readLine(r) n, m = input[0], input[1] //fmt.Scanf("%d%d\n", &n, &m) // 初始化距離 for i := 0; i < N; i++ { for j := 0; j < N; j++ { if i == j { g[i][j] = 0 } else { g[i][j] = 0x3f3f3f3f } } } // for m > 0 { m-- in := readLine(r) a, b, c := in[0], in[1], in[2] //輸入 g[a][b] = min(g[a][b], c) g[b][a] = g[a][b] // 無(wú)向圖 } t := prim() if t == INF { fmt.Println("impossible") } else { fmt.Println(t) } }
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
GoLang基礎(chǔ)學(xué)習(xí)之go?test測(cè)試
相信每位編程開發(fā)者們應(yīng)該都知道,Golang作為一門標(biāo)榜工程化的語(yǔ)言,提供了非常簡(jiǎn)便、實(shí)用的編寫單元測(cè)試的能力,下面這篇文章主要給大家介紹了關(guān)于GoLang基礎(chǔ)學(xué)習(xí)之go?test測(cè)試的相關(guān)資料,需要的朋友可以參考下2022-08-08Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀
這篇文章主要為大家介紹了Golang標(biāo)準(zhǔn)庫(kù)unsafe源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08Go語(yǔ)言基礎(chǔ)切片的創(chuàng)建及初始化示例詳解
這篇文章主要為大家介紹了Go語(yǔ)言基礎(chǔ)切片的創(chuàng)建及初始化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2021-11-11go語(yǔ)言中Timer和Ticker兩種計(jì)時(shí)器的使用
go語(yǔ)言中有Timer和Ticker這樣的兩種計(jì)時(shí)器,兩種計(jì)時(shí)器分別實(shí)現(xiàn)了不同的計(jì)時(shí)功能,本文主要介紹了go語(yǔ)言中Timer和Ticker兩種計(jì)時(shí)器的使用,感興趣的可以了解一下2024-08-08