Это не было четко указано в описании, но я предполагаю, что вы имели в виду, что пакет не может быть скомпилирован, если некоторые из пакетов, от которых он зависит, еще не скомпилированы.
При таком предположении существует довольно простой код, который оптимизирует порядок компиляции.Вычислить глубину зависимости для каждого пакета, а затем скомпилировать в параллельные пакеты одинаковой глубины, начиная с пакетов с наименьшей глубиной.
(Что такое «глубина зависимости»? Думайте о зависимости как о направленном дереве, тогда глубина элемента - это самый длинный путь от элемента до листьев, от которых она зависит. Формально, если пакет не имеетзависимости, тогда его глубина равна нулю, а для других Depth [package] = max (Depth [depen_of_the_package]) + 1. Обратите внимание, что пакеты одинаковой глубины обязательно независимы друг от друга)
Я бы использовал следующий код
class PackageOptimizer
{
public:
struct PackageDependency
{
size_t Count() const
{
return m_end - m_begin;
}
size_t m_begin;
size_t m_end;
};
vector<size_t> FindLeaves()
{
vector<size_t> leaves;
for(size_t i = 0; i<m_deps.size(); i++)
{
if(m_deps[i].m_begin == m_deps[i].m_end)
leaves.push_back(i);
}
return leaves;
}
vector<int> ComputeDepthMap()
{
vector<int> Depth(m_deps.size());
vector<int> Count(m_deps.size(),0);
vector<size_t> currSet = FindLeaves();
vector<size_t> nextSet;
int currDepth = 0;
while(!currSet.empty())
{
for(size_t elem : currSet)
{
Depth[elem] = currDepth;
for( size_t upPackage = m_depsInv[elem].m_begin;
upPackage < m_depsInv[elem].m_end;
upPackage++)
{
Count[upPackage]++;
if(Count[upPackage] == m_deps[upPackage].Count())
{
nextSet.push_back(upPackage);
}
}
}
swap(nextSet, currSet);
currDepth++;
nextSet.clear();
}
return Depth;
}
private:
// package i is dependent on
// m_indices[m_deps[i].m_begin], m_indices[m_deps[i].m_begin+1], ... m_indices[m_deps[i].m_end-1]
vector<PackageDependency> m_deps;
vector<size_t> m_indices;
// following packages are dependant on package i
// m_indicesInv[m_depsInv[i].m_begin], m_indicesInv[m_depsInv[i].m_begin+1], ... m_indicesInv[m_deps[i].m_end-1]
vector<PackageDependency> m_depsInv;
vector<size_t> m_indicesInv;
};
У него просто нет методов для инициации m_deps, m_indices, m_depsInv, m_indicesInv
, но это не сложно.С вычислением Depth
вы можете легко организовать пакеты, соответствующие порядку выполнения.Кроме того, вам нужно убедиться, что в пакетах нет циклов зависимости, иначе этот код никогда не завершится.
С точки зрения производительности этот алгоритм занимает около O(n + m)
, где n
- это числопакетов и m
- общее количество зависимостей.Создание m_deps, m_indices, m_depsInv, m_indicesInv
должно занимать примерно одинаковое количество времени.
Хотя в реальной жизни разные пакеты требуют разного количества времени для компиляции, и у вас всегда есть ограничение на количество пакетов, которые вы можете скомпилировать вв то же время эффективно.