在私人开源项目中,我遇到以下问题:
要执行各种任务。其中一些任务将有注释
我正在寻找一种简单的算法,用于如何根据该信息构建有向图,然后可以用于循环检测并按顺序执行所有任务任务,以允许尊重关于其执行顺序的所有这些条件。
问:构建此类图表的有效方法是什么?
感谢您的帮助。
注意:很明显,我们将在图中需要两个额外的节点:起始节点和结束节点。我们将它们命名为START和END。很明显,没有依赖关系的节点必须以诸如START - >之类的结构结束。 A - >结束。但是我不太清楚如何找到一个如何最终进入START的好方法 - > B - > C - >结束序列,假设B必须跟随C,而没有从B到END的边缘,没有从START到C的边缘。
答案 0 :(得分:0)
您可以从任何订单开始,然后走完该订单,交换任何乱序的元素。您可以重复此操作,直到没有任何更多的任务出现故障。
我会使用哈希表(或简称数组)进行快速查找,以确定任务是否出现故障。
伪代码:
class Task:
id: int # serial id of task, ie 1..n
not_before: array[int] # ids of tasks this task cannot precede
not_after: array[int] # ids of tasks this task cannot come after
tasks: array[Task] = ... # tasks in order of ids
order: array[int] = [1,2,...,n] # task ids in initial order
positions: array[int] = ... # positions[i] is the index of task i in order array
def swap_tasks(i, j):
swap(order[positions[i]], order[positions[j]])
swap(positions[i], positions[j])
repeat:
made_swap = False
for i in 0..n: # loop over task ids
for j in tasks[i].not_before:
if positions[i] < positions[j]:
swap_tasks(i, j)
made_swap = True
for j in tasks[i].not_after:
if positions[i] > positions[j]:
swap_tasks(i, j)
made_swap = True
if made_swap == False:
break
对于每个任务的n
个任务和O(k)
个限制,这应该在O(n²log(k))
中运行,因为任务最多可以移动n
次(因为它不能回到它交换过的最后一个任务的位置。)
我考虑按顺序处理任务并插入not_after
个任务,然后是task
,然后是not_before
个任务,然后插入(或移动,如果它们已经出现)后续任务满足约束,但这似乎并没有帮助,因为not_before
和not_after
任务可能相互之间无序,所以我们仍然需要大量的交换。
答案 1 :(得分:0)
要求中存在“杀手级”功能,无法轻松解决问题。只有两个方向的约束:
在现实世界的情况下,我面临的这些依赖性更加复杂,但这并不重要:所有这些都可以分解为刚刚描述的模拟情况。
现在算法:
步骤1:将每个任务的所有这些约束编译为每个任务的一组单向依赖关系。然后可以容易地处理单向依赖性。首先构建图形,然后执行第二次循环检测然后执行拓扑排序(感谢术语Dimitry)的第一个想法可以完全放弃。因此每个项目都有一组依赖项:
在执行此操作时,我们甚至可以对这些依赖项进行健全性检查。如果约束规范中存在问题,我们可以在此步骤中轻松检测到这一点。
第2步:现在我们遇到一个非常简单的问题,因为只有一种方式依赖。这些可以被认为是先决条件:只有满足所有先决条件才能执行任务。现在我们可以按照以下步骤进行:
pack all tasks into a list named /notYetProcessed/ create empty list /result/ while there are still tasks to process in /notYetProcessed/ do: create empty list /remaining/ for all tasks /t/ in /notYetProcessed/ do: if all dependencies are met for /t/ then do: add /t/ to /result/ else do: add /t/ to /remaining/ if /length(notYetProcessed)/ matches /length(remaining)/ then do: terminate with error /notYetProcessed/ = /remaining/
在外部while条件终止后result
将包含一个要按顺序处理的任务列表,该顺序遵循开头所定义的所有约束。
如果上述算法以错误终止,则意味着: *此循环中无法处理任务 *表示:某些依赖项无法解析 *表示:存在涉及剩余任务的任务依赖循环
第3步:现在逐个处理result
中存储的所有任务,一个接一个,你会没事的。
正如您所看到的,这可以在不构建数据的特殊图形表示的情况下完成。拓扑排序是通过接受第一个解决方案(=所有可能的排序顺序的第一个变体)“直接”在数据上执行的,我们可以得到它们。
可能是一些更有效的算法来解决这个问题(在第一次执行依赖项编译之后)我可能不知道。如果是这样,我很乐意了解它们!