我的编程空间,编程开发者的网络收藏夹
学习永远不晚

golang 实现菜单树的生成方式

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

golang 实现菜单树的生成方式

golang 实现菜单树的生成,包括菜单节点的选中状态、半选中状态,菜单的搜索。

1 该包提供两个方法根接口

1.1 GenerateTree(nodes, selectedNodes []INode) (trees []Tree)

GenerateTree 自定义的结构体实现 INode 接口后调用此方法生成树结构。

1.2 FindRelationNode(nodes, allNodes []INode) (respNodes []INode)

FindRelationNode 在 allTree 中查询 nodes 中节点的所有父子节点 返回 respNodes(包含 nodes , 跟其所有父子节点)

1.3 接口 INode


// ConvertToINodeArray 其他的结构体想要生成菜单树,直接实现这个接口
type INode interface {
 // GetTitle 获取显示名字
 GetTitle() string
 // GetId获取id
 GetId() int
 // GetFatherId 获取父id
 GetFatherId() int
 // GetData 获取附加数据
 GetData() interface{}
 // IsRoot 判断当前节点是否是顶层根节点
 IsRoot() bool
}

2 使用


go get github.com/azhengyongqin/golang-tree-menu

2.1 定义自己的菜单结构体并且实现接口 INode


// 定义我们自己的菜单对象
type SystemMenu struct {
 Id       int    `json:"id"`        //id
 FatherId int    `json:"father_id"` //上级菜单id
 Name     string `json:"name"`      //菜单名
 Route    string `json:"route"`     //页面路径
 Icon     string `json:"icon"`      //图标路径
}
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 {
 // 这里通过FatherId等于0 或者 FatherId等于自身Id表示顶层根节点
 return s.FatherId == 0 || s.FatherId == s.Id
}

2.2 实现一个将自定义结构体SystemMenu 数组转换成 INode 数组的方法


type SystemMenus []SystemMenu
// ConvertToINodeArray 将当前数组转换成父类 INode 接口 数组
func (s SystemMenus) ConvertToINodeArray() (nodes []INode) {
 for _, v := range s {
  nodes = append(nodes, v)
 }
 return
}

3 测试效果

3.1 添加测试数据


 // 模拟获取数据库中所有菜单,在其它所有的查询中,也是首先将数据库中所有数据查询出来放到数组中,
 // 后面的遍历递归,都在这个 allMenu中进行,而不是在数据库中进行递归查询,减小数据库压力。
 allMenu := []SystemMenu{
  {Id: 1, FatherId: 0, Name: "系统总览", Route: "/systemOverview", Icon: "icon-system"},
  {Id: 2, FatherId: 0, Name: "系统配置", Route: "/systemConfig", Icon: "icon-config"},
  {Id: 3, FatherId: 1, Name: "资产", Route: "/asset", Icon: "icon-asset"},
  {Id: 4, FatherId: 1, Name: "动环", Route: "/pe", Icon: "icon-pe"},
  {Id: 5, FatherId: 2, Name: "菜单配置", Route: "/menuConfig", Icon: "icon-menu-config"},
  {Id: 6, FatherId: 3, Name: "设备", Route: "/device", Icon: "icon-device"},
  {Id: 7, FatherId: 3, Name: "机柜", Route: "/device", Icon: "icon-device"},
 }

3.2 生成完全树


// 生成完全树
resp := GenerateTree(SystemMenus.ConvertToINodeArray(allMenu), nil)
bytes, _ := json.MarshalIndent(resp, "", "\t")
fmt.Println(string(bytes))

[
  {
    "title": "系统总览",
    "leaf": false,
    "checked": false,
    "partial_selected": false,
    "children": [
      {
        "title": "资产",
        "leaf": false,
        "checked": false,
        "partial_selected": false,
        "children": [
          {
            "title": "设备",
            "leaf": true,
            "checked": false,
            "partial_selected": false,
            "children": null
          }, 
          {
            "title": "机柜",
            "leaf": true,
            "checked": false,
            "partial_selected": false,
            "children": null
          }
        ]
      }, 
      {
        "title": "动环",
        "leaf": true,
        "checked": false,
        "partial_selected": false,
        "children": null
      }
    ]
  }, 
  {
    "title": "系统配置",
    "leaf": false,
    "checked": false,
    "partial_selected": false,
    "children": [
      {
        "title": "菜单配置",
        "leaf": true,
        "checked": false,
        "partial_selected": false,
        "children": null
      }
    ]
  }
]

3.3 带选中状态和半选中状态的树


// 模拟选中 '资产' 菜单
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": "系统总览",
    "leaf": false,
    "checked": false,
    "partial_selected": true,
    "children": [
      {
        "title": "资产",
        "leaf": false,
        "checked": true,
        "partial_selected": false,
        "children": [
          {
            "title": "设备",
            "leaf": true,
            "checked": true,
            "partial_selected": false,
            "children": null
          }, 
          {
            "title": "机柜",
            "leaf": true,
            "checked": true,
            "partial_selected": false,
            "children": null
          }
        ]
      }, 
      {
        "title": "动环",
        "leaf": true,
        "checked": false,
        "partial_selected": false,
        "children": null
      }
    ]
  }, 
  {
    "title": "系统配置",
    "leaf": false,
    "checked": false,
    "partial_selected": false,
    "children": [
      {
        "title": "菜单配置",
        "leaf": true,
        "checked": false,
        "partial_selected": false,
        "children": null
      }
    ]
  }
]

3.4 模拟查询某个节点,然后生成树


// 模拟从数据库中查询出 '设备'
device := []SystemMenu{allMenu[5]}
// 查询 `设备` 的所有父节点
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": "系统总览",
    "leaf": false,
    "checked": false,
    "partial_selected": false,
    "children": [
      {
        "title": "资产",
        "leaf": false,
        "checked": false,
        "partial_selected": false,
        "children": [
          {
            "title": "设备",
            "leaf": true,
            "checked": false,
            "partial_selected": false,
            "children": null
          }
        ]
      }
    ]
  }
]

源码地址:https://github.com/azhengyongqin/golang-tree-menu

补充:golang实现prim算法,计算最小生成树

1、题目描述

给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。

求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

给定一张边带权的无向图G=(V, E),其中V表示图中点的集合,E表示图中边的集合,n=|V|,m=|E|。

由V中的全部n个顶点和E中n-1条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图G的最小生成树。

输入格式

第一行包含两个整数n和m。

接下来m行,每行包含三个整数u,v,w,表示点u和点v之间存在一条权值为w的边。

输出格式

共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。

2、数据

数据范围

1≤n≤500,

1≤m≤105,

图中涉及边的边权的绝对值均不超过10000。

输入样例:

4 5

1 2 1

1 3 2

1 4 3

2 3 2

3 4 4

输出样例:

6

数据图

1、初始所有点的距离为正无穷,就是代码中的0x3f3f3f3f等于1061109567

在这里插入图片描述

2、以第一个点为最初点,绿色表示选中,进入到最小生成树中

在这里插入图片描述

3、以第一个更新其他与之连通的点的距离

在这里插入图片描述

4、依次迭代 在这里插入图片描述

5、最后的最小生成树

在这里插入图片描述

3、朴素prim算法步骤时间复杂度O(n^2)

1、先初始化所有点距离为正无穷

2、迭代n次,依次用到集合的最小点更新剩余点距离

3、将已经确定的点加入到st集合中,st数组为一个bool类型

4、代码实现



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 存储最小生成树的大小即边的长度总和
   for i := 0; i < n; i++ {
      // 找到集合外距离最短的点
      t := -1
      for j := 1; j <= n; j++ {
         if !st[j] && (t == -1 || dist[t] > dist[j]) {
            t = j
         }
      }
      // 迭代结束,此时的t就是距离最小点
      // 情况一:图上的点不连通,不能组成最小生成树
      if i > 0 && dist[t] == INF {
         return INF
      } // 如果不是第一个点并且最小店的距离是正无穷,则表示图是不连通的
      if i > 0 {
         res += dist[t]
      } // 如果不是第一个点,这个t就表示当前点到集合某一个点的最小距离
      // 用最小距离点更新其他跟 "现阶段形成的生成树" 的最短距离,
      //注意更新的顺序,自环是不应该被加到最小生成树,所以,为了避免自环加入最小生成树,提前更新res
      for j := 1; j <= n; j++ {
         dist[j] = min(dist[j], g[t][j]) // 此步骤注意是dijkstra的区别,
      }
      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] // 无向图
   }
   t := prim()
   if t == INF {
      fmt.Println("impossible")
   } else {
      fmt.Println(t)
   }
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。如有错误或未考虑完全的地方,望不吝赐教。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

golang 实现菜单树的生成方式

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

JAVA递归生成树形菜单的实现方法是什么

今天小编给大家分享一下JAVA递归生成树形菜单的实现方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。  递归生成一个
2023-06-26

Android实现原生侧滑菜单的超简单方式

先来看看效果图当你点击菜单可以更改图标,例如点击happy,首页就会变一个笑脸,这个实现的过程超级简单 你需要使用ToolBar与DrawableLayout两个比较新的控件 首先要写三个xml布局文件,我这里的布局文件是使用了includ
2022-06-06

Vue实现生成二维码的简单方式

与后端生成二维码相比,前端生成二维码更具有灵活性,下面这篇文章主要给大家介绍了关于Vue实现生成二维码的简单方式,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-01-05

Android提高之多级树形菜单的实现方法

一般来说在Android里要实现树形菜单,都是用ExpandableList(也有高手自己继承ListView或者LinearLayout来做),但是ExpandableList一般只能实现2级树形菜单。本文所述实例也依然使用Expanda
2022-06-06

java实现遍历树形菜单的方法有哪些

这篇文章将为大家详细讲解有关java实现遍历树形菜单的方法有哪些,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体如下。OpenSessionView实现:package org.web;import j
2023-05-30

实现javascript菜单的方法

本篇内容介绍了“实现javascript菜单的方法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!javascript菜单的实现方法:首先将菜
2023-06-14

golang单例模式的实现方式有哪些

在Go语言中,单例模式可以通过以下几种方式来实现:懒汉式:懒汉式是指在第一次使用时才创建实例。在Go语言中,可以使用sync.Once来确保实例只被创建一次。package singletonimport "sync"type Singl
golang单例模式的实现方式有哪些
2024-02-29

Windows10安装Anaconda无法生成菜单的解决方法

最近我在安装Anaconda,总是在最后的时候报错 (没有保存照片)错误窗口的信息大概是这js样:Traceback (most recent call last): File “C:\Anaconda2\Lib_nsis.p
2023-05-22

Golang中单例模式的实现方式有哪些?

Golang中单例模式的实现方式有三种:懒汉模式、饿汉模式和双重检查模式。接下来将为您详细介绍这三种实现方式,并提供具体的代码示例。一、懒汉模式懒汉模式是指在第一次被调用时才创建单例实例,以下是一个懒汉模式的示例代码:package s
Golang中单例模式的实现方式有哪些?
2024-03-05

shell生成简单格式的xml实例

以下是shell代码: create_xml.sh#! /bin/bash #author: dengzhaoqun#date: 201202/14 outfile=outtabs=0 put(){echo '<'${*}'>' >> $o
2022-06-04

Android实现自定义的卫星式菜单(弧形菜单)详解

一、前言 Android 实现卫星式菜单也叫弧形菜单,主要要做的工作如下:1.动画的处理2.自定义ViewGroup来实现卫星式菜单View(1)自定义属性 a. 在attrs.xml中定义属性 b. 在布局中使用自
2022-06-06

Golang sync.Once实现单例模式的方法详解

Go 语言的 sync 包提供了一系列同步原语,其中 sync.Once 就是其中之一。本文将深入探讨 sync.Once 的实现原理和使用方法,帮助大家更好地理解和应用 sync.Once,需要的可以参考一下
2023-05-18

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录