edu.uci.ics.jung.graph.DelegateCTree.java Source code

Java tutorial

Introduction

Here is the source code for edu.uci.ics.jung.graph.DelegateCTree.java

Source

/*
 * Created on Feb 12, 2017
 *
 * Copyright (c) 2017, The JUNG Authors
 *
 * All rights reserved.
 *
 * This software is open-source under the BSD license; see either
 * "license.txt" or
 * https://github.com/jrtom/jung/blob/master/LICENSE for a description.
 */
package edu.uci.ics.jung.graph;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static edu.uci.ics.jung.graph.GraphConstants.NODEU_NOT_IN_TREE;
import static edu.uci.ics.jung.graph.GraphConstants.NODEV_IN_TREE;
import static edu.uci.ics.jung.graph.GraphConstants.NODE_NOT_IN_TREE;
import static edu.uci.ics.jung.graph.GraphConstants.NODE_ROOT_OF_TREE;
import static edu.uci.ics.jung.graph.GraphConstants.SELF_LOOP_NOT_ALLOWED;

import com.google.common.collect.Iterables;
import com.google.common.graph.AbstractGraph;
import com.google.common.graph.ElementOrder;
import com.google.common.graph.EndpointPair;
import com.google.common.graph.Graphs;
import com.google.common.graph.MutableGraph;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

class DelegateCTree<N> extends AbstractGraph<N> implements MutableCTree<N> {
    private final MutableGraph<N> delegate;
    private final Map<N, Integer> depths;
    private Optional<Integer> height;
    private Optional<N> root;

    DelegateCTree(MutableGraph<N> graph, Optional<N> root) {
        this.delegate = checkNotNull(graph, "graph");
        this.depths = new HashMap<>();
        setRoot(checkNotNull(root, "root"));
    }

    @Override
    public Optional<N> root() {
        return root;
    }

    @Override
    public Optional<N> predecessor(N node) {
        checkNotNull(node, "node");
        Set<N> predecessors = delegate.predecessors(node);
        checkState(predecessors.size() <= 1);
        return predecessors.isEmpty() ? Optional.empty() : Optional.of(Iterables.getOnlyElement(predecessors));
    }

    @Override
    public int depth(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return depths.get(node);
    }

    @Override
    public Optional<Integer> height() {
        if (!root.isPresent()) {
            return Optional.empty();
        }
        // Calculate the height
        if (!height.isPresent()) {
            calculateHeight();
        }
        return height;
    }

    @Override
    public boolean isDirected() {
        return true;
    }

    @Override
    public boolean allowsSelfLoops() {
        return false;
    }

    @Override
    public Set<N> adjacentNodes(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.adjacentNodes(node);
    }

    @Override
    public int degree(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.degree(node);
    }

    @Override
    public int inDegree(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.inDegree(node);
    }

    @Override
    public ElementOrder<N> nodeOrder() {
        return delegate.nodeOrder();
    }

    @Override
    public Set<N> nodes() {
        return delegate.nodes();
    }

    @Override
    public int outDegree(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.outDegree(node);
    }

    @Override
    public Set<N> predecessors(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.predecessors(node);
    }

    @Override
    public Set<N> successors(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.successors(node);
    }

    @Override
    public Set<EndpointPair<N>> edges() {
        return delegate.edges();
    }

    @Override
    public Set<EndpointPair<N>> incidentEdges(N node) {
        checkNotNull(node, "node");
        checkArgument(delegate.nodes().contains(node), NODE_NOT_IN_TREE, node);
        return delegate.incidentEdges(node);
    }

    @Override
    public boolean hasEdgeConnecting(N nodeU, N nodeV) {
        checkNotNull(nodeU, "nodeU");
        checkNotNull(nodeV, "nodeV");
        checkArgument(delegate.nodes().contains(nodeU), NODE_NOT_IN_TREE, nodeU);
        checkArgument(delegate.nodes().contains(nodeV), NODE_NOT_IN_TREE, nodeV);
        return delegate.hasEdgeConnecting(nodeU, nodeV);
    }

    @Override
    public boolean addNode(N node) {
        checkNotNull(node, "node");
        if (root.isPresent()) {
            N rootValue = root.get();
            checkArgument(rootValue.equals(node), NODE_ROOT_OF_TREE, node, rootValue);
            return false;
        }
        setRoot(Optional.of(node));
        return true;
    }

    @Override
    public boolean putEdge(N nodeU, N nodeV) {
        checkNotNull(nodeU, "nodeU");
        checkNotNull(nodeV, "nodeV");
        checkArgument(!nodeU.equals(nodeV), SELF_LOOP_NOT_ALLOWED, nodeU);
        if (!root.isPresent()) {
            setRoot(Optional.of(nodeU));
        } else {
            checkArgument(nodes().contains(nodeU), NODEU_NOT_IN_TREE, nodeU, nodeV, nodeU);
            if (successors(nodeU).contains(nodeV)) {
                return false; // edge is already present; no-op
            }
            // verify that nodeV is not in the tree
            checkArgument(!nodes().contains(nodeV), NODEV_IN_TREE, nodeU, nodeV, nodeV);
        }
        setDepth(nodeV, nodeU);
        return delegate.putEdge(nodeU, nodeV);
    }

    private void setDepth(N node, N parent) {
        if (parent == null) { // root: both depth and height are 0
            depths.put(node, 0);
            height = Optional.of(0);
        } else {
            depths.putIfAbsent(parent, 0);
            int nodeDepth = Math.max(depths.get(parent) + 1, height.orElse(0));
            depths.put(node, nodeDepth);
            height = Optional.of(nodeDepth);
        }
    }

    private void calculateHeight() {
        // This method is only called when the root is present, so we don't need to check for that.
        int currentHeight = 0;
        List<N> currentLevel = new ArrayList<>(successors(root.orElseThrow(AssertionError::new)));
        List<N> nextLevel;
        while (!currentLevel.isEmpty()) {
            nextLevel = new ArrayList<>();
            currentHeight++; // there's at least one node in the current level
            for (N node : currentLevel) {
                nextLevel.addAll(successors(node));
            }
            currentLevel = nextLevel;
        }
        height = Optional.of(currentHeight);
    }

    @Override
    public boolean removeNode(N node) {
        checkNotNull(node, "node");
        if (!nodes().contains(node)) {
            return false;
        }
        for (N nodeToRemove : Graphs.reachableNodes(delegate, node)) {
            delegate.removeNode(nodeToRemove);
            depths.remove(nodeToRemove);
        }
        if (root.isPresent() && root.get().equals(node)) {
            setRoot(Optional.empty());
        }
        // Reset the height, since we don't know how it was affected by removing the subtree.
        height = Optional.empty();
        return true;
    }

    private void setRoot(Optional<N> root) {
        this.root = root;
        this.root.ifPresent(node -> {
            this.delegate.addNode(node);
            setDepth(node, null);
        });
    }

    @Override
    public boolean removeEdge(N nodeU, N nodeV) {
        checkNotNull(nodeU, "nodeU");
        checkNotNull(nodeV, "nodeV");
        delegate.removeEdge(nodeU, nodeV);
        return removeNode(nodeV);
    }
}