Сортировка частичного заказа?
Скажем, у нас есть несколько элементов, и каждый определяет некоторые частичные правила сортировки, например:
Я A
, и я хочу быть до B
Я C
, и я хочу быть после A
, но до D
Итак, у нас есть элементы A,B,C,D
с этими правилами:
-
A>B
-
C<A
, C>D
- ничего больше! Таким образом,
B
и D
не имеют "предпочтений" в упорядочении и считаются равными.
Как вы видите, правила транзитивных отношений здесь не работают. Однако, если A>B
, это все равно означает B<A
. Таким образом, может быть несколько возможных результатов сортировки:
- A B C D
- A C D B
- A C B D
- A B C D
Как я могу реализовать алгоритм сортировки, который обрабатывает такую ситуацию?
Причина: существует несколько загружаемых модулей, и некоторые из них "зависят" от других в некотором роде. Каждый модуль может объявлять простые правила относительно других модулей:
Загрузите меня перед модулем A
Загрузите меня после модуля B
Загрузите меня перед модулем A, но после модуля B
теперь мне нужно каким-то образом реализовать этот порядок..:)
Ответ: code от Paddy McCarthy (MIT)
## {{{ http://code.activestate.com/recipes/577413/ (r1)
try:
from functools import reduce
except:
pass
data = {
'des_system_lib': set('std synopsys std_cell_lib des_system_lib dw02 dw01 ramlib ieee'.split()),
'dw01': set('ieee dw01 dware gtech'.split()),
'dw02': set('ieee dw02 dware'.split()),
'dw03': set('std synopsys dware dw03 dw02 dw01 ieee gtech'.split()),
'dw04': set('dw04 ieee dw01 dware gtech'.split()),
'dw05': set('dw05 ieee dware'.split()),
'dw06': set('dw06 ieee dware'.split()),
'dw07': set('ieee dware'.split()),
'dware': set('ieee dware'.split()),
'gtech': set('ieee gtech'.split()),
'ramlib': set('std ieee'.split()),
'std_cell_lib': set('ieee std_cell_lib'.split()),
'synopsys': set(),
}
def toposort2(data):
for k, v in data.items():
v.discard(k) # Ignore self dependencies
extra_items_in_deps = reduce(set.union, data.values()) - set(data.keys())
data.update({item:set() for item in extra_items_in_deps})
while True:
ordered = set(item for item,dep in data.items() if not dep)
if not ordered:
break
yield ' '.join(sorted(ordered))
data = {item: (dep - ordered) for item,dep in data.items()
if item not in ordered}
assert not data, "A cyclic dependency exists amongst %r" % data
print ('\n'.join( toposort2(data) ))
## end of http://code.activestate.com/recipes/577413/ }}}
Ответы
Ответ 1
Вы захотите построить график зависимостей (который является просто ароматом направленного графа), а затем следуйте топологически отсортированный заказ. Это было какое-то время, так как я взял класс комбинаторики, поэтому статья Википедии, вероятно, будет более полезной, чем я для топологического алгоритма сортировки. Я надеюсь, что вам будет полезна правильная терминология.:)
Что касается построения графика, вам просто нужно будет иметь каждый модуль со списком зависимостей этого модуля.
Вам просто нужно немного перефразировать свои правила... "Я C, и я хочу быть после A, но до D" будет выражаться как "C зависит от A", а также "D зависит от C", так что все течет в стандартном направлении.