常见树结构构造

          前两天有用到一个简单的树结构,和平常数据结构关注二叉树、BTree的观察点不同;这边主要是介绍一种树如何通过常见的树数据存储结构(各节点都包含parentId的数据)构造或操作。

 Tree接口:

import java.util.List;

/**
 * @author: huangpp02
 * @time: 2018-02-26 11:18
 */
public interface Tree<T> {
    /**
     * 自身属性
     *
     * @return
     */
    T getValue();

    /**
     * 子属性
     *
     * @return
     */
    List<Tree<T>> getChildren();

    /**
     * 是否是叶子节点
     * @return
     */
    boolean isLeaf();
}

Tree的默认实现:DefaultTree

/**
 * @author: huangpp02
 * @time: 2018-02-26 11:24
 */
@Setter
public class DefaultTree<T> implements Tree<T> {
    private T value;

    private List<Tree<T>> children;

    @Override
    public T getValue() {
        return value;
    }

    @Override
    public List<Tree<T>> getChildren() {
        return children;
    }

    @Override
    public boolean isLeaf() {
        return CollectionUtils.isEmpty(children);
    }
}

重点来了,如何构造Tree?

public class TreeUtils {
    /**
     *
     * @param initValue 树初始化节点
     * @param childrenFunc 根据自身获取子节点列表
     * @param <T> tree对应的value值
     * @return 树
     */
    public static <T> Tree<T> buildTree(T initValue, Function<T, List<T>> childrenFunc) {
        DefaultTree<T> result = new DefaultTree<>();
        result.setValue(initValue);
        List<T> children = childrenFunc.apply(initValue);
        if (!CollectionUtils.isEmpty(children)) {
            result.setChildren(CollectionUtils.selectList(children, child -> buildTree(child, childrenFunc)));
        }
        return result;
    }
}

上面是抽象了一个根据当前结点找到子节点列表的childrenFunc,这个Func要如何构造,可以参考下面的测试用例:

public class TestTreeUtils {
    @Getter
    @Setter
    static class Area {
        int parentId;

        int id;

        String name;

        public Area(int parentId, int id, String name) {
            this.parentId = parentId;
            this.id = id;
            this.name = name;
        }

        @Override
        public String toString() {
            return name;
        }
    }

    private List<Area> areas;

    @Before
    public void init() {
        areas = new ArrayList<>();
        areas.add(new Area(0, 1, "湖北省"));
        areas.add(new Area(0, 2, "福建省"));
        areas.add(new Area(0, 3, "广东省"));
        areas.add(new Area(1, 4, "武汉市"));
        areas.add(new Area(1, 5, "潜江市"));
        areas.add(new Area(4, 6, "武昌区"));
        areas.add(new Area(2, 7, "泉州市"));
        areas.add(new Area(2, 8, "厦门市"));
        areas.add(new Area(8, 9, "思明区"));
        areas.add(new Area(3, 10, "深圳市"));
        areas.add(new Area(3, 11, "广州市"));
    }

    @Test
    public void testBuild() {
        Tree<Area> areaTree = TreeUtils.buildTree(new Area(0, 0, "中国"), new ChildFunc(areas));
        TreeUtils.preOrder(areaTree).stream().forEach(System.out::println);
    }

    private class ChildFunc implements Function<Area, List<Area>> {
        private Map<Integer, List<Area>> parentIdMap;

        public ChildFunc(List<Area> areas) {
            parentIdMap = CollectionUtils.toMapList(areas, Area::getParentId);
        }

        @Override
        public List<Area> apply(Area area) {
            return parentIdMap.get(area.getId());
        }
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值