1.多树进行遍历操作
2.使用的递归的方式
3.深度优先遍历
4.使用队列
/**
* 层次遍历使用到了广度优先搜索,技巧:深度优先用递归,广度优先用队列。
*/
项目开发的时候出现这样的需求:
类似于,将多一个树,进行深度优先遍历,将相同级节点使用 、 连接
效果类似于下面的树
目标:需要的结果数据
{目录{目录1{目录1.1、目录1.2}、目录2{目录2.1、目录2.2{目录2.2.1}}}、目录A{目录A.1、目录A.2}}
下面这些代码,是实现的demo,可以参考
package com.gree.algorithm;
import freemarker.template.utility.StringUtil;
import lombok.Data;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* Create by yang_zzu on 2020/5/19 on 21:13
*/
public class DiGui {
@Data
static class Menu {
private String id;
private String name;
private String pid;
}
/**
* 1. 先找出没有父节点的数据
* 2. 依次对这些父节点进行遍历,查找子节点(递归)
*/
/**
* 查找根节点
* @param menuList
* @return
*/
public static Queue<Menu> rootNode(List<Menu> menuList) {
Queue<Menu> menuQueue = new LinkedList<>();
for (Menu menu : menuList) {
//获得该节点的 父id
String pid = menu.getPid();
//
List<Menu> list = new ArrayList<>();
for (Menu menu1 : menuList) {
if ( pid.equals(menu1.getId())) {
//说明该节点不是根节点
list.add(menu1);
}
}
if (list.size() > 0) {
//说明有子节点
} else {
menuQueue.add(menu);
}
}
return menuQueue;
}
/**
* 当前节点的子节点
* @param menuList
* @param id
* @return
*/
public static Queue<Menu> childNode(List<Menu> menuList, String id) {
Queue<Menu> menus = new LinkedList<>();
for (Menu menu : menuList) {
if (menu.getPid().equals(id)) {
menus.add(menu);
}
}
return menus;
}
/**
*
* @param menuList 节点集合
* @param menuQueue 当前节点的所有子节点
* @param stringBuffer 存储结果
* @return
*/
public static StringBuffer nodeString(List<Menu> menuList, Queue<Menu> menuQueue, StringBuffer stringBuffer) {
//节点集合,父节点后面的额
if (menuQueue.size()>0) {
stringBuffer.append("{");
}
while (menuQueue.size() > 0) {
//获得当前节点
Menu poll = menuQueue.poll();
//获得当前节点的所有子节点
Queue<Menu> menus = childNode(menuList, poll.getId());
if (menus.size() > 0) {
//子节点1 子节点>1
stringBuffer.append(poll.getName());
StringBuffer stringBuffer1 = nodeString(menuList, menus, stringBuffer);
// System.out.println(menus.size());
stringBuffer.append("}");
} else {
//说明父节点的,所有子节点都遍历完了
if (menuQueue.size() == 0) {
stringBuffer.append(poll.getName());
stringBuffer.append("}");
} else {
//当前节点没有子节点
stringBuffer.append(poll.getName());
stringBuffer.append("、");
}
}
}
return stringBuffer;
}
/**
* {目录{目录1{目录1.1、目录1.2}、目录2{目录2.1、目录2.2{目录2.2.1}}}、目录A{目录A.1、目录A.2}}
*/
public static void main(String args[]) {
List<Menu> menuList = new ArrayList<Menu>();
//第一个根节点数据
Menu mu = new Menu();
mu.setId("1");
mu.setName("目录");
mu.setPid("0");
Menu mu1 = new Menu();
mu1.setId("2");
mu1.setName("目录1");
mu1.setPid("1");
Menu mu2 = new Menu();
mu2.setId("3");
mu2.setName("目录1.1");
mu2.setPid("2");
Menu mu3 = new Menu();
mu3.setId("4");
mu3.setName("目录1.2");
mu3.setPid("2");
Menu mu4 = new Menu();
mu4.setId("5");
mu4.setName("目录2");
mu4.setPid("1");
Menu mu5 = new Menu();
mu5.setId("6");
mu5.setName("目录2.1");
mu5.setPid("5");
Menu mu6 = new Menu();
mu6.setId("7");
mu6.setName("目录2.2");
mu6.setPid("5");
Menu mu7 = new Menu();
mu7.setId("8");
mu7.setName("目录2.2.1");
mu7.setPid("7");
//另外一个根节点数据
Menu mu8 = new Menu();
mu8.setId("9");
mu8.setName("目录A");
mu8.setPid("100");
Menu mu9 = new Menu();
mu9.setId("10");
mu9.setName("目录A.1");
mu9.setPid("9");
Menu mu10 = new Menu();
mu10.setId("11");
mu10.setName("目录A.2");
mu10.setPid("9");
menuList.add(mu);
menuList.add(mu1);
menuList.add(mu2);
menuList.add(mu3);
menuList.add(mu4);
menuList.add(mu5);
menuList.add(mu6);
menuList.add(mu7);
menuList.add(mu8);
menuList.add(mu9);
menuList.add(mu10);
//获得所有的根节点
Queue<Menu> menus = rootNode(menuList);
System.out.println(menus.toString());
//存储树返回的结果
StringBuffer stringBuffer = new StringBuffer();
StringBuffer s = nodeString(menuList, menus, stringBuffer );
System.out.println(s);
//获得字符串中 }}} 这个并且后面还有元素的 将最后一个 } 变为 、
String s1 = s.toString();
//用于替换字符串指定索引的字符
StringBuilder sb = new StringBuilder(s1);
String[] split = StringUtil.split(s1, '}');
for (String s2 : split) {
// System.out.println(s2);
if (!s2.isEmpty()) {
int i = s1.indexOf(s2);
if (i > 0) {
//替换多个 }}} 的最后一个字符,[1,2) 包含左不包含右
sb.replace(i - 1, i , "、");
}
System.out.println(i);
}
}
System.out.println(sb);
}
}