All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrapht.traverse.DegeneracyOrderingIterator Maven / Gradle / Ivy

The newest version!
/*
 * (C) Copyright 2017-2023, by Dimitrios Michail and Contributors.
 *
 * JGraphT : a free Java graph-theory library
 *
 * See the CONTRIBUTORS.md file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0, or the
 * GNU Lesser General Public License v2.1 or later
 * which is available at
 * http://www.gnu.org/licenses/old-licenses/lgpl-2.1-standalone.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR LGPL-2.1-or-later
 */
package org.jgrapht.traverse;

import java.lang.reflect.Array;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;

import org.jgrapht.Graph;
import org.jgrapht.Graphs;

/**
 * A degeneracy ordering iterator.
 * 
 * 

* The degeneracy of a graph $G $is the smallest value d such that every nonempty subgraph of $G$ * contains a vertex of degree at most $d.$ If a graph has degeneracy $d$, then it has a degeneracy * ordering, an ordering such that each vertex has $d$ or fewer neighbors that come later in the * ordering. * *

* The iterator crosses components but does not track them, it only tracks visited vertices. * *

* The iterator treats the input graph as undirected even if the graph is directed. Moreover, it * completely ignores self-loops, meaning that it operates as if self-loops do not contribute to the * degree of a vertex. * * @param the graph vertex type * @param the graph edge type * * @author Dimitrios Michail */ public class DegeneracyOrderingIterator extends AbstractGraphIterator { private Set[] buckets; private Map degrees; private int minDegree; private V cur; /** * Constructor * * @param graph the graph to be iterated */ @SuppressWarnings("unchecked") public DegeneracyOrderingIterator(Graph graph) { super(graph); /* * Count degrees, but skip self-loops */ this.minDegree = Integer.MAX_VALUE; int maxDegree = 0; this.degrees = new HashMap<>(); for (V v : graph.vertexSet()) { int d = 0; for (E e : graph.edgesOf(v)) { V u = Graphs.getOppositeVertex(graph, e, v); if (!v.equals(u)) { d++; } } degrees.put(v, d); minDegree = Math.min(minDegree, d); maxDegree = Math.max(maxDegree, d); } minDegree = Math.min(minDegree, maxDegree); /* * Create buckets */ this.buckets = (Set[]) Array.newInstance(Set.class, maxDegree + 1); for (int i = 0; i < buckets.length; i++) { buckets[i] = new LinkedHashSet<>(); } for (V v : graph.vertexSet()) { buckets[degrees.get(v)].add(v); } } /** * {@inheritDoc} * * Always returns true since the iterator does not care about components. */ @Override public boolean isCrossComponentTraversal() { return true; } /** * {@inheritDoc} * * Trying to disable the cross components nature of this iterator will result into throwing a * {@link IllegalArgumentException}. */ @Override public void setCrossComponentTraversal(boolean crossComponentTraversal) { if (!crossComponentTraversal) { throw new IllegalArgumentException("Iterator is always cross-component"); } } @Override public boolean hasNext() { if (cur != null) { return true; } cur = advance(); if (cur != null && nListeners != 0) { fireVertexTraversed(createVertexTraversalEvent(cur)); } return cur != null; } @Override public V next() { if (!hasNext()) { throw new NoSuchElementException(); } V result = cur; cur = null; if (nListeners != 0) { fireVertexFinished(createVertexTraversalEvent(result)); } return result; } private V advance() { while (minDegree < buckets.length && buckets[minDegree].isEmpty()) { minDegree++; } V result = null; if (minDegree < buckets.length) { Set b = buckets[minDegree]; V v = b.iterator().next(); b.remove(v); degrees.remove(v); for (E e : graph.edgesOf(v)) { V u = Graphs.getOppositeVertex(graph, e, v); if (v.equals(u)) { // ignore self-loop continue; } if (degrees.containsKey(u)) { int uDegree = degrees.get(u); if (uDegree > minDegree) { buckets[uDegree].remove(u); uDegree--; degrees.put(u, uDegree); buckets[uDegree].add(u); } } } result = v; } return result; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy