JetBrains Academy: Trees in Java - Kamil-Jankowski/Learning-JAVA GitHub Wiki

JetBrains Academy: Trees in Java

Finding the leaves of a tree:

Given a tree in the format of "parent-child" pairs. Write a program that prints the leaves of the tree in ascending order.

Input: The first line contains an integer n — the number of edges in a tree. Each of the next n lines contains two integers separated by space. Each pair of integers corresponds to an edge of a tree: the first integer is a parent, the second one is a child. The node numbered 0 is a root. It is guaranteed that the input corresponds to a correct tree.

Output: The first line should contain the number of leaves in the tree. The second line should be a sequence of these leaves in ascending order.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Leafs<Integer> leafs = Leafs.create();
        Scanner scanner = new Scanner(System.in);
        int lines = Integer.parseInt(scanner.nextLine());
        int[] parents = new int[lines];

        for (int i = 0; i < lines; i++) {
            String[] pair = scanner.nextLine().split("\\s+");
            int parent = Integer.parseInt(pair[0]);
            int child = Integer.parseInt(pair[1]);
            leafs.add(child);
            parents[i] = parent;
        }

        for (int p : parents) {
            leafs.remove(p);
        }

        System.out.println(leafs.size());
        System.out.println(leafs.toString());    
    }
}

class Leafs<E extends Comparable<E>> {

    private final Set<E> leafSet;

    /**
     * Method initializes new collection of leafs.
     *
     * @param <E> - type of leaf elements
     * @return empty Leafs collection
     */
    public static <E extends Comparable<E>> Leafs<E> create() {
        return new Leafs<>();
    }

    /**
     * Private constructor.
     */
    private Leafs() {
        leafSet = new TreeSet<>();
    }

    /**
     * Method adds new child into the collection of leafs.
     *
     * @param child to be added to collection
     */
    public void add(E child) {
        leafSet.add(child);
    }

    /**
     * Method removes a leaf from the collection.
     *
     * @param parent - element to be removed from the collection of leafs
     */
    public void remove(E parent) {
        leafSet.remove(parent);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (E elem : leafSet) {
            sb.append(elem).append(" ");
        }
        return sb.toString();
    }

    /**
     *
     * @return size of leafs collection
     */
    public int size() {
        return leafSet.size();
    }
}

A full binary tree:

Given a tree represented as a list of pairs of adjacent nodes. Write a program that checks whether the given tree is a full binary tree.

Input: the first line contains an integer n ≤ 100 — the number of edges in the tree. Each of the following n lines contains a pair of two integers representing an edge. The first integer is a parent node, the second one is a child. The node numbered 00 is a root. It is guaranteed that the input corresponds to a correct tree.

Output: print "yes" if the given tree is a full binary and "no" otherwise.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int lines = Integer.parseInt(scanner.nextLine());
        Map<Integer, List<Integer>> nodes = new HashMap<>();

        for (int i = 0; i < lines; i++) {
            String[] pair = scanner.nextLine().split("\\s+");
            int parent = Integer.parseInt(pair[0]);
            int child = Integer.parseInt(pair[1]);

            if (nodes.containsKey(parent)) {
                nodes.get(parent).add(child);
            } else {
                List<Integer> children = new ArrayList<>();
                children.add(child);
                nodes.put(parent, children);
            }
        }

        System.out.println(TreeUtils.isFullBinaryTree(nodes) ? "yes" : "no");
    }
}

class TreeUtils {
    /**
     * Method checks if given map represents full binary tree (all parents have exactly two children).
     *
     * @param map - map containing parent as a key and list of children as value;
     * @param <E> - type of elements in the map;
     * @return true if map is full binary tree, false otherwise;
     */
    public static <E> boolean isFullBinaryTree(Map<E, List<E>> map) {
        Set<E> parents = map.keySet();
        boolean isFullBinary = true;

        for (E parent : parents) {
            if (map.get(parent).size() == 2) {
                isFullBinary = true;
            } else {
                isFullBinary = false;
                break;
            }
        }

        return isFullBinary;
    }
}

The pre-order traversal:

A full ternary tree with depth n is given. Write a program that prints all nodes of the tree in Pre-Order. Enumeration starts from 0 and goes sequentially through the levels. In the picture below you can see a tree with depth 2.

Pre-order for k-ary tree is (Root, Child_1, …., Child_k).

Input: n is the depth of the tree.

Output: a sequence of nodes in Pre-Order divided by spaces.

TBD

The height of a tree (v1):

One more way to represent a tree in computer memory is to store it as an array of parents. For example, an array of parents is as follows:

NODE  |  0  |  1  |  2  |  3  |  4  |  5  |  6  |
PARENT|  1  | -1  |  5  |  1  |  0  |  1  |  5  |

The node's 3 parent is 1, thus parent[3] = 1. The node 1 is a root, hence parent[1] = -1.

Your task here is to write a program that finds the height of a tree represented in the described format. The expected time complexity of your algorithm is O(k2), where k is the number of nodes in a tree.

Input: The first line contains an integer k — the number of nodes of a tree. The next line contains k integers corresponding to an array of parents. It is guaranteed that an array represents a correct tree.

Output: The height of the input tree.

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int size = Integer.parseInt(scanner.nextLine());
        String[] input = scanner.nextLine().split("\\s+");
        int[] parents = new int[size];
        for (int i = 0; i < size; i++) {
            parents[i] = Integer.parseInt(input[i]);
        }

        System.out.println(TreeUtils.checkHeight(parents));
    }
}

class TreeUtils {
    private static int nodeDepth = 1;

    /**
     * Method checks depth/height of a tree from provided array of parents;
     * For example:
     * The node's 3 parent is 1, thus parent[3] = 1
     * The node 1 is a root, hence parent[1] = -1.
     *
     * @param parents - array of ints with number of parent node for each index of array
     * @return height of tree
     */
    public static int checkHeight(int[] parents) {
        int treeDepth = 0;
        for (int parent : parents) {
            checkParent(parent, parents);
            treeDepth = Math.max(nodeDepth, treeDepth);
            resetNodeDepth();
        }

        return treeDepth;
    }

    /**
     * Method checks parent of provided node in parents array 
     * 
     * @param node of with parent we are checking
     * @param parents - array of parents
     * @return parent of the node
     */
    private static int checkParent(int node, int[] parents) {
        if (node == -1) {
            return node;
        }
        nodeDepth++;
        return checkParent(parents[node], parents);
    }

    /**
     * Method resets node depth to default value.
     */
    private static void resetNodeDepth() {
        nodeDepth = 1;
    }
}

v2 - O(k)

TBD

⚠️ **GitHub.com Fallback** ⚠️