基于递归算法,树形结构数据下业务场景,封装解决方法

一、递归算法

1、概念简介

递归算法的核心思想是通过将问题重复分解为同类的或其子问题的方式,从而可以使用统一的解决方式。很多编程语言支持方法或函数自我调用,简单的说,就是在函数或方法体内,自身可以再次调用自身的方法结构。

2、基础案例

这里通过递归的方式,计算阶乘、求和等相关逻辑。

public class Demo01 {

    public static void main(String[] args) {

        int result1 = factorial(5);

        System.out.println(result1);

        int result2 = sum(100) ;

        System.out.println(result2);

    }

    // 递归阶乘

    private static int factorial (int n){

        if(n <= 1){

            return n ;

        }else{

            return n*factorial(n-1);

        }

    }

    // 递归求和

    private static int sum (int f){

        if(f <= 1){

            return f ;

        }else{

            return f + sum(f-1);

        }

    }

}

3、注意事项

  • 使用方法

使用递归的时候,要明确业务逻辑可以分解为重复相同的问题,且要清楚的知道递归的结束条件,不然很容易出现死循环。

  • 优缺点描述

递归算法的代码比较简洁,可读性较好;但是在实际的业务处理中会出现多次的重复调用,如果处理不好,很容易出现StackOverflowError报错。

二、树状结构

1、概念描述

树形结构是一层次的嵌套结构。一个树形结构的外层和内层有相似的结构,所以这种结构多可以递归的表示。

2、图解和定义

  • 根节点

树的根源,没有父节点的节点,如上图A节点。

  • 兄弟节点

拥有同一父节点的子节点。如图B与C与D节点。

  • 叶子节点

没有子节点的节点。如图E和F等节点。

  • 分支度

指一个节点有几个子节点。 如:A为3、B为2。

  • 节点深度

指从该节点到某一节点的最长路径。如图A为2、B为1。

三、应用场景

1、场景描述

基于递归算法下,处理很多树形结构的业务数据。常见的业务场景如下:

  • 省市区三级联动查询 ;
  • 系统模块、菜单、按钮的授权 ;
  • 常见的业务数据分类:商品分类等 ;
  • 常见各种行业分类细化 ;

2、特殊场景

在管理系统中,对系统模块、菜单、按钮授权操作时候可能会出现如下情况。

假如系统管理员的权限如图所示,但是给到运营人员的权限如下,需要把3号菜单和5号菜单设置为同级别,这时候基本的处理手法就是把3号菜单父级ID作为3号菜单和下属功能的权限的根节点,这里把这里当成两颗树进行分别处理,最后合并数据就好。必要时按照配上节点编码,例如NODE01,NODE0101,NODE0102等方式,这里针对这个场景描述,就是希望在处理类似业务时候,思路要开阔,不必拘泥于单个树形结构。业务很多时候都是出人意料甚至是令人生厌,不过这确实就是生活。

3、工具类封装

这里展示一个树形结构常用的几个封装方法,例如创建树形结构,遍历,判断等。

import
 java.util.ArrayList;

import
 java.util.List;

public
 
class
 
ThreeUtil
 
{

    
/**

     * 递归创建树形结构

     */

    
private
 
static
 List 
getTree
(List nodeList, Integer parentId)
 
{

        List threeNodeList = 
new
 ArrayList<>() ;

        
for
 (ThreeNode entity : nodeList) {

            Integer nodeId = entity.getId() ;

            Integer nodeParentId = entity.getParentId() ;

            
if
 (parentId.intValue() == nodeParentId.intValue()) {

                List childList = getTree(nodeList,nodeId) ;

                
if
 (childList != 
null
 && childList.size()>
0
){

                    entity.setChildNode(childList);

                    entity.setChildNodeSize(childList.size());

                }

                threeNodeList.add(entity) ;

            }

        }

        
return
 threeNodeList ;

    }

    
/**

     * 获取指定子节点

     */

    
private
 
static
 List 
getChildTree
 
(Integer id,List nodeList)
{

        List resultList = 
new
 ArrayList<>();

        
for
 (ThreeNode entity : nodeList) {

            
if
 (entity.getParentId().intValue() == id) {

                List childList = getChildTree(entity.getId(),nodeList) ;

                entity.setChildNode(childList);

                entity.setChildNodeSize(childList.size());

                resultList.add(entity) ;

            }

        }

        
return
 resultList ;

    }

    
/**

     * 遍历树形结构

     */

    
private
 
static
 
transient
 List treeIdList = 
new
 ArrayList<>() ;

    
private
 
static
 List 
getTreeInfo
 
(List treeList)
{

        
for
 (ThreeNode entity : treeList) {

            
if
 (entity.getChildNodeSize()!=
null
 && entity.getChildNodeSize()>
0
){

                getTreeInfo(entity.getChildNode());

            }

            treeIdList.add(entity.getId());

        }

        
return
 treeIdList ;

    }

    
/**

     * 判断节是否是叶子节点

     */

    
private
 
static
 
boolean
 
hasChildNode
 
(Integer id,List nodeList)
{

        
for
 (ThreeNode entity:nodeList){

            
if
 (entity.getParentId().intValue() == id){

                
return
 
true
 ;

            }

        }

        
return
 
false
 ;

    }

    
public
 
static
 
void
 
main
(String[] args)
 
{

        List threeNodeList = 
new
 ArrayList<>() ;

        threeNodeList.add(
new
 ThreeNode(
1
,
"节点A"
,
0
)) ;

        threeNodeList.add(
new
 ThreeNode(
2
,
"节点B"
,
1
)) ;

        threeNodeList.add(
new
 ThreeNode(
3
,
"节点C"
,
1
)) ;

        threeNodeList.add(
new
 ThreeNode(
4
,
"节点D"
,
1
)) ;

        threeNodeList.add(
new
 ThreeNode(
5
,
"节点E"
,
2
)) ;

        threeNodeList.add(
new
 ThreeNode(
6
,
"节点F"
,
2
)) ;

        
// 测试1

        List getTree = getTree(threeNodeList,
0
) ;

        System.out.println(getTree);

        
// 测试2

        
// List getChildTree = getChildTree(2,threeNodeList) ;

        
// System.out.println(getChildTree);

        
// 测试3

        List treeIdList = getTreeInfo(getTree) ;

        System.out.println(treeIdList);

        
// 测试4

        System.out.println(hasChildNode(
2
,threeNodeList)) ;

    }

}

四、源代码地址

GitHub·地址https://github.com/cicadasmileGitEE·
地址https://gitee.com/cicadasmile

原文地址:https://www.cnblogs.com/zhao06666guo77/p/12273784.html

时间: 2024-08-29 09:35:00

基于递归算法,树形结构数据下业务场景,封装解决方法的相关文章

android设计的布局在阿拉伯语下界面错乱的解决方法

(1)正在AndroidManifest.xml声明文件的application元素中,增加" android:supportsRtl=true" (2)建] androidの设计的布局在阿拉伯语下界面错乱的解决方法 (1)在AndroidManifest.xml声明文件的元素中,添加" android:supportsRtl=true" (2)修改应用程序中layout的"left/right"布局属性,改为对应的"start/end

img标签下多余空白BUG解决方法

在进行页面的DIV CSS排版时,遇到IE6(当然有时Firefox下也会偶遇)浏览器中的图片元素img下出现多余空白的问题绝对是常见的 对于该问题的解决方法也是“见机行事”. 1.将图片转换为块级对象 即,设置img为“display:block;”.在本例中添加一组CSS代码:“#sub img {display:block;}”. 2.设置图片的垂直对齐方式 即设置图片的vertical-align属性为“top,text-top,bottom,text-bottom”也可以解决.如本例中

CentOS7 下linux不能上网解决方法?,centos7 eth0 没有ip,IP突然丢失

CentOS7 下linux不能上网解决方法? 在CentOS VMware下安装好linux后,发现有时不能直接联网,特分享下总结出来的经验,希望对新手有用 工具/原料 XP系统 VMware.Workstation.v7.0以上 CentOS-5.5-i386-bin-DVD.iso 其他不同版本应该差不多 方法/步骤 虚拟机安装就不说了,从安装linux后测试发现不能联网,可以先终端重启下网卡 失败如图:   找到点击选择setting   在network Adapter选中,右侧是否是

无法录制下拉菜单的解决方法

QTP默认录制方式无法录制下拉菜单,需修改设置后再录制 修改设置如下: 1.Record-> web event recording configuration -----custom settings... 展开Web objects 2.选中webelement,点击event -> add -> .并确定在record栏内,状态是enabled 3.重新录制你的脚本 4.录制完成后,执行脚本,若回放失败,是因为脚本只录制了鼠标的 事件,却没有录制click事件,所以脚本录制完后要手

高DPI下界面错乱的解决方法和原理

来源: http://bbs.csdn.net/topics/370177760 我在win32 + c写的界面中解决办法,就是把字体的字号给固定了,这样做的结果就是,不管dpi是否有改变,界面中控件的文字的字号不变,就不会出现文字换行的情况. 但像菜单文字的字号就变大了,combobox(右三角),checkbox(选择框)变大一点点,显的有点不协调. 但至少不影响使用. 下面是判断当前系统的dpi,然后重置字体的字号. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

IE6下fixed失效的解决方法

在网上找了好久,终于找到一种亲测有效的解决方法. <!--[if IE 6]> <script type="text/javascript"> (function($) { jQuery.fn.Fixed = function(options) { var defaults = { x:0, y:0 }; var o = jQuery.extend(defaults, options); var isIe6 = !window.XMLHttpRequest; v

windows下mongodb权限设置解决方法

mongodb简介: MongoDB 是一个跨平台的,面向文档的数据库,提供高性能,高可用性和可扩展性方便. MongoDB工作在收集和文件的概念. MongoDB默认设置为无权限访问限制,所以可以直接进入数据库并对数据进行操作, 事件背景:最近,公司放在移动机房的两台装有mongoDB数据库的服务器被绿盟扫描出来有漏洞,要求我们解决 根据绿盟提供的解决方法是在admin库中添加任意用户,并启用认证. 但绿盟给出的方法是基于linux下的方法,但其实原理大同小异. 我更加网上搜来的文章,进行整合

iOS中常见的 Crash 场景以及解决方法

1. 常见的 Crash 场景 访问了僵尸对象 访问了不存在的方法 数组越界 在定时器下一次回调前将定时器释放,会Crash 2.  关于BAD_ACCESS  出现的原因: 访问了野指针, 比如访问已经释放对象的成员变量或者发消息, 死循环等; 解决方法: 1.  重写对象的respondsToSelector 方法, 先找到出现 EXECBADACCESS 前访问的最后一个 object; 2. 设置Enable Zombie Objects; 3. 设置全局断点快速定位问题代码所在行,接收

Eclipse在高分屏下图标过小的解决方法

自己败了一台Surface Pro 4,打算用来看PDF.练代码. 安装了Eclipse并且打开之后,发现图标显示极其细小,肉眼几乎无法看清了.这是由于Eclipse对高分屏没有作适配导致的. Windows 10本身对于高分屏的支持已是相当不错,苏菲4的屏幕分辨率为2736*1824,我设置了200%的缩放级别,总体显示效果不错.但是很多第三方应用的显示就一团糟了,Eclise就在此列. 网上搜寻之后,找了一个不错的解决方法,该方法可解决Eclipse.MyEclipse.STS等IDE在高分