java實現樹形結構數據


樹形結構很常見,最典型就是管理系統中的菜單,比如用戶管理下,有新增用戶,刪除用戶等等.

數據庫表中的存儲結構 一般會有一個id 以及一些業務字段 最后一定要有一個父id 存儲上一級的id

這樣就建立了一個級聯關系,我這里就沒有去查詢數據庫了,直接創建幾個記錄即可.

菜單實體類

public class Menu {

    private Integer id;

    private String name;

    private String url;

    private Integer fatherId;


    public Menu(Integer id, String name, String url, Integer fatherId) {
        this.id = id;
        this.name = name;
        this.url = url;
        this.fatherId = fatherId;
    }

    @Override
    public String toString() {
        return "Menu{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", url='" + url + '\'' +
                ", fatherId=" + fatherId +
                '}';
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Integer getFatherId() {
        return fatherId;
    }

    public void setFatherId(Integer fatherId) {
        this.fatherId = fatherId;
    }
}

在新建一個類,和這個菜單實體類相同,但是多一個子節點屬性,存放所有的子節點,其實這個不建,就在菜單實體類多加一個子節點屬性也可以

public class MenuVo {
    private Integer id;

    private String name;

    private String url;

    private Integer fatherId;

    private List<MenuVo>  childNode;

    @Override
    public String toString() {
        return "MenuVo{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", url='" + url + '\'' +
                ", fatherId=" + fatherId +
                ", childNode=" + childNode +
                '}';
    }

    public MenuVo() {
    }

    public MenuVo(Integer id, String name, String url, Integer fatherId, List<MenuVo> childNode) {
        this.id = id;
        this.name = name;
        this.url = url;
        this.fatherId = fatherId;
        this.childNode = childNode;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public Integer getFatherId() {
        return fatherId;
    }

    public void setFatherId(Integer fatherId) {
        this.fatherId = fatherId;
    }

    public List<MenuVo> getChildNode() {
        return childNode;
    }

    public void setChildNode(List<MenuVo> childNode) {
        this.childNode = childNode;
    }
}

接下來貼出測試代碼

public class Test  {
    public static void main(String[] args) {

        List<Menu> sqlData=new ArrayList<>();
        sqlData.add(new Menu(1,"1","xxx",-1));
        sqlData.add(new Menu(2,"1-1","xxx",1));
        sqlData.add(new Menu(3,"1-1-1","xxx",2));
        sqlData.add(new Menu(4,"2","xxx",-1));
        sqlData.add(new Menu(5,"2-1","xxx",4));
        sqlData.add(new Menu(6,"1-2","xxx",1));

        //存儲非根節點
        List<MenuVo> tempList=new ArrayList<>();
        //存儲最終的結果
        List<MenuVo> resultList=new ArrayList<>();
        //遍歷數據庫查詢數據集合,如果父id==-1 代表根節點 添加到最終結果中,否則為非根節點添加到臨時節點
        for (Menu menu : sqlData) {
            if(menu.getFatherId()==-1){
                resultList.add(new MenuVo(menu.getId(),menu.getName(),menu.getUrl(),menu.getFatherId(),new ArrayList<>()));
            }else{
                tempList.add(new MenuVo(menu.getId(),menu.getName(),menu.getUrl(),menu.getFatherId(),new ArrayList<>()));
            }
        }
        //遍歷所有的根節點,通過根節點和非根節點集合,找到這個根節點的所有子節點
        for (MenuVo menuVo : resultList) {
            getChildNode(tempList,menuVo);
        }

        resultList.forEach(System.out::println);
    }


    public static  void getChildNode(List<MenuVo> tempList,MenuVo fatherNode  ){
        for (MenuVo menuVo : tempList) {
            //如果該節點的父id為傳進來父節點的id 那么就為其子節點
            if(menuVo.getFatherId()==fatherNode.getId()){
                //添加到子節點數組
                fatherNode.getChildNode().add(menuVo);
                //遞歸調用 繼續找該子節點  是否還有子節點
                getChildNode(tempList,menuVo);
            }
        }
    }


}

大致思路就是,先區分根節點和非根節點,然后遍歷根節點,根據根節點的id,去非根節點中找父id

為根節點id的節點,添加到根節點的子節點集合中,但是由於子節點還可能有子節點,就是這個樹有

多少層級,我們並不知道,所以在查找子節點時需要遞歸,將每一個子節點作為一個父節點繼續去查找他的子節點

 

想了想其實子節點遞歸這里可以優化,可以將非根節點,根據父id分為一組,就是Map<父id,List<MenuVo>>

以這個格式存儲,這樣在遞歸子節點時,不需要遍歷去找子節點,直接根據id查找子節點即可

把代碼貼出來

public class Test  {
    public static void main(String[] args) {

        List<Menu> sqlData=new ArrayList<>();
        sqlData.add(new Menu(1,"1","xxx",-1));
        sqlData.add(new Menu(2,"1-1","xxx",1));
        sqlData.add(new Menu(3,"1-1-1","xxx",2));
        sqlData.add(new Menu(4,"2","xxx",-1));
        sqlData.add(new Menu(5,"2-1","xxx",4));
        sqlData.add(new Menu(6,"1-2","xxx",1));

        //存儲非根節點
        Map<Integer,List<MenuVo>> tempMap=new HashMap<>();

        //存儲最終的結果
        List<MenuVo> resultList=new ArrayList<>();
        //遍歷數據庫查詢數據集合,如果父id==-1 代表根節點 添加到最終結果中,否則為非根節點添加到臨時節點
        for (Menu menu : sqlData) {
            MenuVo menuVo=new MenuVo(menu.getId(),menu.getName(),menu.getUrl(),menu.getFatherId(),new ArrayList<>());
            if(menu.getFatherId()==-1){
                resultList.add(menuVo);
            }else{
                if (tempMap.containsKey(menu.getFatherId())) {
                    tempMap.get(menu.getFatherId()).add(menuVo);
                }else{
                    List<MenuVo> list=new ArrayList<>();
                    list.add(menuVo);
                    tempMap.put(menu.getFatherId(),list);
                }
            }
        }
        //遍歷所有的根節點,通過根節點和非根節點集合,找到這個根節點的所有子節點
        for (MenuVo menuVo : resultList) {
            getChildNode(tempMap,Arrays.asList(menuVo));
        }

        resultList.forEach(System.out::println);
    }


    public static  void getChildNode(Map<Integer,List<MenuVo>> tempMap,List<MenuVo> fatherNodeList  ){
        for (MenuVo menuVo : fatherNodeList) {
            if (tempMap.containsKey(menuVo.getId())) {
               menuVo.getChildNode().addAll(tempMap.get(menuVo.getId()));
               getChildNode(tempMap,tempMap.get(menuVo.getId()));
            }
        }
    }


}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM