Index / Java

Java 递归实例操作-查询层级菜单

原文:https://ichochy.com/posts/java/20210315.html

递归

程序调用自身的编程技巧称为递归( recursion)。递归做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的能力在于用有限的语句来定义对象的无限集合。一般来说,递归需要有边界条件、递归前进段和递归返回段。当边界条件不满足时,递归前进;当边界条件满足时,递归返回。

递归的运用

系统中总会有菜单和权限的操作,会出现无限层级的操作,就需要用到递归。运用其调用自身的特性,实现无限层级迭代,通过父子节点展示数据。

递归的实例操作

以查询所有菜单为例

数据结构

字段 名称
id ID
fatherId 父ID
name 名称
…… ……

数据实体

/*
 * File:Menus.java
 * User:iChochy
 * URL:https://ichochy.com
 * Copyright (c) 2021
 * Date:2021/03/16 14:12:16
 */

package com.ichochy.entity;

import java.util.List;

public class Menu {
    private int id;
    private int fatherId;
    private String name;
    private List<Menu> childs;
    //…………

}

数据查询

通过 fatherId 查询子菜单信息


    /**
     * 查询菜单信息-模拟方法
     * @param fatherId
     * @return
     */
    public  List<Menu> getMenuByFatherId(int fatherId) {
        int value = new Random().nextInt(fatherId);
        if (value % 2 != 0) {
            List<Menu> menus = new ArrayList<>(value);
            for (int i = 1; i <= value; i++) {
                Menu menu = new Menu();
                menu.setId(i);
                menu.setFatherId(fatherId);
                menu.setName("menu-" + fatherId+"-"+i);
                menus.add(menu);
            }
            return menus;
        }
        return Collections.EMPTY_LIST;
    }

没有建表查库,写个模拟方法

递归方法

/*
 * File:Recursion.java
 * User:iChochy
 * URL:https://ichochy.com
 * Copyright (c) 2021
 * Date:2021/03/16 14:07:16
 */

package com.ichochy.recursion;

import com.ichochy.entity.Menu;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class Recursion {

    /**
     * 获取菜单
     * @param fatherId
     * @return
     */
    public  List<Menu> getAllMenus(int fatherId) {
        List<Menu> menus = getMenuByFatherId(fatherId);
        for (Menu menu : menus) {
            fatherId = menu.getId();
            //自己调用自己
            List<Menu> childMenus = getAllMenus(fatherId);
            //跳出递归
            if (childMenus.isEmpty()) {
                continue;
            }
            menu.setChilds(childMenus);
        }
        return menus;
    }

构成递归需具备的条件:

  1. 子类问题与父类问题相同
  2. 不能无限制地调用自身,须有跳出出口,边界返回

递归数据

[
  {
    "id": 1,
    "fatherId": 15,
    "name": "menu-15-1"
  },
  {
    "id": 2,
    "fatherId": 15,
    "name": "menu-15-2",
    "childs": [
      {
        "id": 1,
        "fatherId": 2,
        "name": "menu-2-1"
      }
    ]
  },
  {
    "id": 3,
    "fatherId": 15,
    "name": "menu-15-3",
    "childs": [
      {
        "id": 1,
        "fatherId": 3,
        "name": "menu-3-1"
      }
    ]
  },
  {
    "id": 4,
    "fatherId": 15,
    "name": "menu-15-4",
    "childs": [
      {
        "id": 1,
        "fatherId": 4,
        "name": "menu-4-1"
      },
      {
        "id": 2,
        "fatherId": 4,
        "name": "menu-4-2",
        "childs": [
          {
            "id": 1,
            "fatherId": 2,
            "name": "menu-2-1"
          }
        ]
      },
      {
        "id": 3,
        "fatherId": 4,
        "name": "menu-4-3",
        "childs": [
          {
            "id": 1,
            "fatherId": 3,
            "name": "menu-3-1"
          }
        ]
      }
    ]
  }
]