菜单树的三种实现形式(递归,for, 队列)

菜单树在软件开发中经常用于展示层级结构的数据,例如网站导航菜单或文件系统。在实际开发中,我们常常需要考虑不同的数据结构和算法来实现这种层级关系的展示。本文将介绍菜单树的三种常见实现方式:递归、for循环和队列,帮助读者更好地理解和选择合适的方法。

准备

示例数据库

sql 复制代码
create table menu
(
    id        int auto_increment
        primary key,
    name      varchar(100) not null,
    parent_id int          null
);

create index parent_id
    on menu (parent_id);
复制代码

Mapper

java 复制代码
@Mapper
public interface MenuMapper extends BaseMapper<Menu> {
    @Select("SELECT id, name, parent_id FROM menu WHERE parent_id = #{parentId}")
    List<Menu> findMenusByParentId(@Param("parentId") Integer parentId);

}

Service

java 复制代码
public interface MenuService {
    List<Menu> findMenusByParentId(Integer parentId);
}

Impl

java 复制代码
@Service
public class MenuServiceImpl extends ServiceImpl<MenuMapper, Menu> implements MenuService {
    @Autowired
    private MenuMapper menuMapper;
    @Override
    public List<Menu> findMenusByParentId(Integer parentId) {
        return menuMapper.findMenusByParentId(parentId);
    }
}

1. 递归实现

java 复制代码
@RestController
@RequestMapping("/menus")
public class MenuController {

    @Autowired
    private MenuService menuService;

    // 返回根菜单列表及其子菜单
    @GetMapping("/tree")
    public List<Menu> getMenuTree(Integer parentId) {
        List<Menu> rootMenus = menuService.findMenusByParentId(parentId); // 获取顶级菜单
        buildMenuTree(rootMenus); // 构建树形结构
        return rootMenus;
    }

    // 递归方法,构建菜单树
    private void buildMenuTree(List<Menu> menus) {
        for (Menu menu : menus) {
            List<Menu> children = menuService.findMenusByParentId(menu.getId());
            if (!children.isEmpty()) {
                menu.setChildren(children); // 设置子菜单列表
                buildMenuTree(children); // 递归构建子树
            }
        }
    }
}

2.For实现

java 复制代码
@RestController
@RequestMapping("/treemenus")
public class MenuNotRecursionUseForController {

    @Resource
    private MenuService menuService;
    @GetMapping("/tree")
    public List<Menu> getMenuTree(Integer parentId) {
        List<Menu> rootMenus = menuService.findMenusByParentId(parentId); // 获取顶级菜单列表

        // 创建一个 Map 用于存放每个菜单的 ID 和对应的菜单对象
        Map<Integer, Menu> menuMap = new HashMap<>();
        for (Menu menu : rootMenus) {
            menu.setChildren(new ArrayList<>()); // 初始化子菜单列表
            menuMap.put(menu.getId(), menu); // 将菜单对象放入 map 中,以便后续快速访问
        }

        // 遍历第二层菜单,逐层构建树形结构
        for (Menu menu : rootMenus) {
            // 查询当前菜单的所有子菜单(第二层菜单)
            List<Menu> children = menuService.findMenusByParentId(menu.getId());
            for (Menu child : children) {
                // 将第二层菜单添加到父菜单的子菜单列表中
                Menu parentMenu = menuMap.get(child.getParentId());
                if (parentMenu != null) {
                    parentMenu.getChildren().add(child);

                    // 查询当前第二层菜单的所有子菜单(第三层菜单)
                    List<Menu> grandchildren = menuService.findMenusByParentId(child.getId());
                    if (child.getChildren() == null) {
                        child.setChildren(new ArrayList<>()); // 初始化第三层子菜单列表
                    }
                    for (Menu grandchild : grandchildren) {
                        // 将第三层菜单添加到当前第二层菜单的子菜单列表中
                        child.getChildren().add(grandchild);
                    }
                }
            }
        }

        // 返回构建好的根菜单列表
        return rootMenus;
    }


}

3. 队列实现

java 复制代码
@RestController
@RequestMapping("/treemenustwo")
public class MenuNotRecursionUseQueueController {
        @Autowired
        private MenuService menuService;

        @GetMapping("/tree")
        public List<Menu> getMenuTree(Integer parentId) {
            List<Menu> rootMenus = menuService.findMenusByParentId(parentId); // 获取顶级菜单列表

            // 使用队列来进行广度优先搜索
            Queue<Menu> queue = new LinkedList<>(rootMenus);

            while (!queue.isEmpty()) {
                Menu currentMenu = queue.poll(); // 出队当前菜单

                // 查询当前菜单的所有子菜单
                List<Menu> children = menuService.findMenusByParentId(currentMenu.getId());

                // 将子菜单加入当前菜单的 children 列表中
                currentMenu.setChildren(children);

                // 将子菜单加入队列,以便后续处理其子菜单
                queue.addAll(children);
            }

            return rootMenus; // 返回构建好的树形结构
        }

    }
相关推荐
静听山水11 分钟前
mysql语句执行过程
数据库·mysql
虽千万人 吾往矣30 分钟前
golang gorm
开发语言·数据库·后端·tcp/ip·golang
mariokkm1 小时前
Django一分钟:在Django中怎么存储树形结构的数据,DRF校验递归嵌套模型的替代方案
数据库·django·sqlite
Wang's Blog2 小时前
Redis: 集群环境搭建,集群状态检查,分析主从日志,查看集群信息
数据库·redis
容器( ु⁎ᴗ_ᴗ⁎)ु.。oO2 小时前
MySQL事务
数据库·mysql
cyt涛4 小时前
MyBatis 学习总结
数据库·sql·学习·mysql·mybatis·jdbc·lombok
Rookie也要加油4 小时前
01_SQLite
数据库·sqlite
liuxin334455664 小时前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
少女的迷鹿5 小时前
Paper:NSG(Navigating Spreading-out Graph)
数据库
看山还是山,看水还是。5 小时前
MySQL 管理
数据库·笔记·mysql·adb