/* * This file is part of ELKI: * Environment for Developing KDD-Applications Supported by Index-Structures * * Copyright (C) 2017 * ELKI Development Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.lmu.ifi.dbs.elki.index.tree; import java.util.*; /** * Breadth first enumeration over the nodes of an index structure. * * @author Elke Achtert * @since 0.2 * * @apiviz.uses IndexTree * @apiviz.has IndexTreePath * * @param <N> the type of Node used in the index * @param <E> the type of Entry used in the index */ public class BreadthFirstEnumeration<N extends Node<E>, E extends Entry> implements Iterator<IndexTreePath<E>> { /** * Represents an empty enumeration. */ public final Iterator<IndexTreePath<E>> EMPTY_ENUMERATION = new Iterator<IndexTreePath<E>>() { @Override public boolean hasNext() { return false; } @Override public IndexTreePath<E> next() { throw new NoSuchElementException("No more children"); } }; /** * The queue for the enumeration. */ private Queue<Iterator<IndexTreePath<E>>> queue; /** * The index storing the nodes. */ private IndexTree<N, E> index; /** * Creates a new breadth first enumeration with the specified node as root * node. * * @param index the index tree storing the nodes * @param rootPath the root entry of the enumeration */ public BreadthFirstEnumeration(final IndexTree<N, E> index, final IndexTreePath<E> rootPath) { super(); this.queue = new LinkedList<>(); this.index = index; Iterator<IndexTreePath<E>> root_enum = new Iterator<IndexTreePath<E>>() { boolean hasNext = true; @Override public boolean hasNext() { return hasNext; } @Override public IndexTreePath<E> next() { hasNext = false; return rootPath; } }; queue.offer(root_enum); } /** * Tests if this enumeration contains more elements. * * @return <code>true</code> if and only if this enumeration object contains * at least one more element to provide; <code>false</code> otherwise. */ @Override public boolean hasNext() { return (!queue.isEmpty() && (queue.peek()).hasNext()); } /** * Returns the next element of this enumeration if this enumeration object has * at least one more element to provide. * * @return the next element of this enumeration. * @throws java.util.NoSuchElementException if no more elements exist. */ @Override public IndexTreePath<E> next() { Iterator<IndexTreePath<E>> enumeration = queue.peek(); IndexTreePath<E> nextPath = enumeration.next(); Iterator<IndexTreePath<E>> children; if(nextPath.getEntry() instanceof LeafEntry) { children = EMPTY_ENUMERATION; } else { N node = index.getNode(nextPath.getEntry()); children = node.children(nextPath); } if(!enumeration.hasNext()) { queue.remove(); } if(children.hasNext()) { queue.offer(children); } return nextPath; } }