Обход части элементов графа для загрузки всех родителей
Есть набор элементов ориентированного графа. Каждый элемент содержит ссылки на родительские элементы (которых может и не быть в наборе). И есть функция, которая может вернуть по идентификатору элемента все его родительские (вплоть до корневого элемента). Цель - минимизировать вызовы этой функции. Т.е. например, в такой ситуации

логично вызвать функцию только для Node4 (в результате функция вернет все ноды - 1-5).
А в ситуации №2
вероятно функцию нужно вызывать для всех элементов в наборе.
Видится такой алгоритм:
- для каждого элемента в наборе проверить наличие на него ссылки в других элементах набора
- при отсутствие ссылок поместить элемент в очередь
- для элементов в очереди вызывать функцию
- проверить наличие в результах вызовов функции наличие элементов, на которые ссылаются элементы набора, для которых вызова не было
- при обнаружении ссылки на элемент, который до сих пор не был получен, делать вызов для элемента набора с этой ссылкой и снова переходить к п.4
Только тут возможна ситуация, когда все элементы имеют ссылку друг на друга (это невозможно в рамках бизнес-логики, но все же не хочется ограничивать алгоритм). Ее нужно обработать отдельно. Подскажите, верно ли расуждаю, кажется это все уже должно быть придумано и не нужно ничего изобретать.
UDP. Реализовал алгоритм по комментарию @Stanislav Volodarskiy
Для набора элементов сделать топологическую сортировку. По полученному списку пройтись с конца. Для каждого элемента вызывать функцию поиска предков. Найденных предков из списка вычеркивать. Алгоритм гарантирует минимальное количество вызовов функции.
Но получается, что, например, в такой ситуации:

выполнив сортировку исходного набора, нужно будет вызвать функцию получения предков для одной из нод (Node1 или Node2 в зависимости от сортировки), результат вывоза функции будет содержать Node4, Node3, Node1 (или Node2). Вычеркнуть из набора мы ничего не сможем, т.к. второго элемента исходного набора в результатах вызова функции нет, а значит нужно выполнить еще один вызов функции для второго элемента в наборе (хотя этот вызов очевидно избыточен!).
Подскажите, правильно ли я понял алгоритм @Stanislav Volodarskiy или это ограничение этого алгоритма?
