/** * Algorithm of Tarjan for computing the strongly connected components of a graph. * * @param v current node * @throws QueryException if a variable directly calls itself */ private void tarjan(final int v) throws QueryException { final int ixv = 2 * v, llv = ixv + 1, idx = next++; while (list.size() <= llv) list.add(-1); list.set(ixv, idx); list.set(llv, idx); stack.push(v); for (final int w : adjacentTo(v)) { final int ixw = 2 * w, llw = ixw + 1; if (list.size() <= ixw || list.get(ixw) < 0) { // Successor w has not yet been visited; recurse on it tarjan(w); list.set(llv, Math.min(list.get(llv), list.get(llw))); } else if (stack.contains(w)) { // Successor w is in stack S and hence in the current SCC list.set(llv, Math.min(list.get(llv), list.get(ixw))); } } // If v is a root node, pop the stack and generate an SCC if (list.get(llv) == list.get(ixv)) { int w; Scope[] out = null; do { w = stack.pop(); final Scope scp = scopes.get(w); out = out == null ? new Scope[] {scp} : Array.add(out, scp); } while (w != v); result.add(out); } }
@Override public Value value(final QueryContext qc) throws QueryException { final FItem getKey = checkArity(exprs[1], 1, qc); final long k = Math.min(toLong(exprs[2], qc), Integer.MAX_VALUE); if (k < 1) return Empty.SEQ; final Iter iter = exprs[0].iter(qc); final MinHeap<Item, Item> heap = new MinHeap<>( new Comparator<Item>() { @Override public int compare(final Item it1, final Item it2) { try { return OpV.LT.eval(it1, it2, sc.collation, sc, info) ? -1 : 1; } catch (final QueryException qe) { throw new QueryRTException(qe); } } }); try { for (Item it; (it = iter.next()) != null; ) { heap.insert(checkNoEmpty(getKey.invokeItem(qc, info, it)), it); if (heap.size() > k) heap.removeMin(); } } catch (final QueryRTException ex) { throw ex.getCause(); } final ValueBuilder vb = new ValueBuilder(); while (!heap.isEmpty()) vb.addFront(heap.removeMin()); return vb.value(); }