When I am building nested sets, how do I get the right hand value of a non-leaf node

89 views Asked by At

I'm trying to use a non-recursive depth-first-search approach to read directories and build nested sets. I need to assign left, right, and depth values to the path of the given directory(Files at the same directory level are in no particular order). I have now completed the assignment of depth, left and right to the Leaf node. But I'm confused about how do I get the right-hand value of a non-leaf node.

Here's what I hope to achieve, and what I've already done:

A: Given a directory, where |== stands for folder; |-- stands for file. (You can replace it with your own directory)

 |==resources
            |==data
                  |==table_design
            |==mapper
                  |==server
                        |--ServerMapper.xml
                  |==source
                  |--AMapper.xml
            |--bootstrap.properties
            |--logback-spring.xml

B: Expected result

0   1|||\resources|||20
1   2|||\resources\data||5
2   3|||\resources\data\table_design|||4
1   6|||\resources\mapper|||15
2   7|||\resources\mapper\server|||10
3   8|||\resources\mapper\server\ServerMapper.xml|||9
2   11|||\resources\mapper\source|||12
2   13|||\resources\mapper\AMapper.xml|||14
1   16|||\resources\bootstrap.properties|||17
1   18|||\resources\logback-spring.xml|||19

C: My implementation

  1. entity
  static class MyObject {

        private int left;
        private int right;
        private int depth;
        private String path;
    }
  1. My depth-first-search logic
  private static void dfs(File root) {
        if (root == null) {
            return;
        }
        int depth = 0;
        int index = 1;
        Stack<File> stack = new Stack<>();
        //Indicates whether the node has been pushed onto the stack
        Map<File, MyObject> map = new LinkedHashMap<>();
        stack.add(root);
        MyObject rootObj = new MyObject();
        rootObj.setPath(root.getAbsolutePath());
        rootObj.setDepth(depth);
        rootObj.setLeft(index++);
        map.put(root, rootObj);
        while (!stack.isEmpty()) {
            File cur = stack.pop();
            depth--;
            File[] files = cur.listFiles();
            if (files != null) {
                //Execute as soon as the next node is found
                for (File next : files) {
                    //The next node is pushed if it has not been accessed
                    if (!map.containsKey(next)) {
                        depth++;
                        stack.push(cur);
                        depth++;
                        stack.push(next);
                        MyObject obj = new MyObject();
                        obj.setLeft(index++);
                        obj.setPath(next.getAbsolutePath());
                        obj.setDepth(depth);
                        if (!next.isDirectory()) {
                            obj.setRight(index++);
                        }
                        map.put(next, obj);
                        break;
                    }
                }
            }
        }

        System.out.println("depth" + "\t left|||path|||right");
        for (MyObject value : map.values()) {
            System.out.println(value.getDepth() + "\t" + value.getLeft() + "|||" + value.getPath() + "|||" + value.getRight());
        }
    }
    
  1. my output
0   1|||\resources|||0
1   2|||\resources\bootstrap.properties|||3
1   4|||\resources\data|||0
2   5|||\resources\data\table_design|||6
1   7|||\resources\logback-spring.xml|||8
1   9|||\resources\mapper|||0
2   10|||\resources\mapper\server|||0
3   11|||\resources\mapper\server\UserMapper.xml|||12
2   13|||\resources\mapper\source|||0
2   14|||\resources\mapper\SourceJobMapper.xml|||15
1

There are 1 answers

0
BoboTheKnight On

I finished the data's build.

 public static Map<File, NestedSetObj> dfs2NestedSets(File root) {
        if (root == null) {
            return new HashMap<>(0);
        }

        //Record depth pop -1, push +1
        long depth = 0L;
        //Left and right values
        long index = 1L;
        Deque<File> stack = new ArrayDeque<>();
        stack.push(root);

        //The global collection of objects, which also indicates whether the object has been pushed.
        Map<File, NestedSetObj> map = new LinkedHashMap<>();
        //Root directory, directly give the value
        NestedSetObj rootObj = NestedSetObj.builder().path(root.getAbsolutePath()).depth(depth).left(index++).build();
        map.put(root, rootObj);

        while (!stack.isEmpty()) {
            File cur = stack.pop();
            depth--;
            File[] files = cur.listFiles();
            if (files != null) {
                //Execute as soon as the next node is found
                for (File next : files) {
                    //The next node is executed if it has not been accessed
                    if (!map.containsKey(next)) {
                        //The current node and the next node are pushed
                        depth++;
                        stack.push(cur);
                        depth++;
                        stack.push(next);
                        //On each first access, the node is assigned the value left
                        NestedSetObj obj = NestedSetObj.builder().left(index++).path(next.getAbsolutePath()).depth(depth).build();
                        boolean leaf = !next.isDirectory();
                        boolean emptyDirLeaf = next.listFiles() != null && next.listFiles().length == 0;
                        //Assign right directly to leaf nodes or empty directories
                        if (leaf || emptyDirLeaf) {
                            obj.setRight(index++);
                        }
                        map.put(next, obj);
                        break;
                    }
                }

                //Determine whether the right side of the leaf node needs to be assigned
                //We believe that the current directory can be assigned only if all sub-levels of data in the current directory have a value of RIGHT 
                long min = Long.MAX_VALUE;

                for (File file : files) {
                    NestedSetObj childObject = map.get(file);
                    if (childObject == null) {
                        min = 0L;
                        break;
                    }
                    min = Math.min(min, childObject.getRight());
                }

                //Assign a value to the right of a non-leaf node;
                //If all level 1 child nodes have the right node value, index plus 1 is the right node value of the current node.  
                if (min > 0L && Long.MAX_VALUE != min) {
                    NestedSetObj curObj = map.get(cur);
                    if (curObj.right == 0L) {
                        curObj.setRight(index++);
                    }
                }
            }
        }
        //Rvalue of the root directory = Number of nodes x 2
        rootObj.setRight(map.size() * 2L);
        return map;
    }