Монотонный код Грея — различия между версиями
Gpevnev (обсуждение | вклад) м |
Gpevnev (обсуждение | вклад) |
||
Строка 70: | Строка 70: | ||
</center> | </center> | ||
− | Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время <tex>O(n)</tex>. Легче всего написать этот алгоритм используя | + | Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время <tex>O(n)</tex>. Легче всего написать этот алгоритм используя генератор. |
=== Псевдокод === | === Псевдокод === | ||
+ | Перед тем как писать псевдокод необходимо объяснить что такое <code>'''yield'''</code> и что понимать под выражениями типа <code>(0,)</code> или <code>(1,)</code>. | ||
+ | |||
+ | <code>'''yield'''</code> - аналог <code>'''return'''</code> только для функций-генераторов. То есть генераторы это тоже итерируемые объекты, но прочитать их можно лишь один раз. Это связано с тем, что они не хранят значения в памяти, а генерируют их на лету. | ||
+ | |||
+ | С конструкциями типа <code>(0,)</code> или <code>(1,)</code> все проще. Используя ее совместно с <code>'''yield'''</code> мы можем в изменять наш генерируемый объект. Например, <code>'''yield''' (0,)</code> допишет к генерируемому объекту (в нашем случае кортежу (англ. ''tuple'')) <tex>0</tex> в начало. | ||
{| border="0" | {| border="0" | ||
|align="left" colspan="4"| | |align="left" colspan="4"| | ||
+ | *Вспомогательная функция для генерации перестановки, циклически сдвигает битовый вектор направо <tex>n</tex> раз. | ||
+ | *Принимает и возвращает котреж. Кортеж аналог списка, но в кортеже нельзя менять элементы, можно только добавлять. | ||
<code> | <code> | ||
− | rotateRight(x, n): | + | rotateRight(x, n): |
'''return''' x[-n:] + x[:-n] | '''return''' x[-n:] + x[:-n] | ||
− | + | </code> | |
+ | *Рекурсивная генерация <tex>n</tex>-ой перестановки. | ||
+ | *Возвращает перестановку в виде кортежа. | ||
+ | *Если n становится меньше <tex>2</tex> дописывает в начало кортежа <tex>0</tex> и возвращает его. | ||
+ | <code> | ||
+ | pi(n): | ||
'''if''' n <= 1: | '''if''' n <= 1: | ||
'''return''' (0,) | '''return''' (0,) | ||
x = pi(n - 1) + (n - 1,) | x = pi(n - 1) + (n - 1,) | ||
'''return''' rotate_right('''tuple'''(x[k] '''for''' k '''in''' x), 1) | '''return''' rotate_right('''tuple'''(x[k] '''for''' k '''in''' x), 1) | ||
− | + | </code> | |
+ | *Рекурсивная генерация пути <tex>P_{n, j}</tex>. | ||
+ | *Принимает <tex>n, j</tex>, а так же дополнительный параметр определяющий надо-ли переворачивать кортеж. | ||
+ | <code> | ||
+ | p(n, j, reverse = ''false''): | ||
if n == 1 and j == 0: | if n == 1 and j == 0: | ||
'''if''' '''not''' reverse: | '''if''' '''not''' reverse: | ||
Строка 102: | Строка 118: | ||
'''yield''' (0,) + x | '''yield''' (0,) + x | ||
'''for''' x '''in''' p(n - 1, j - 1, reverse=True): | '''for''' x '''in''' p(n - 1, j - 1, reverse=True): | ||
− | '''yield''' (1,) + '''tuple'''(x[k] '''for''' k '''in''' perm) | + | '''yield''' (1,) + '''tuple'''(x[k] '''for''' k '''in''' perm) |
− | + | </code> | |
+ | *Генерация монотонного кода Грея при помощи уже написанного генератора p. | ||
+ | <code> | ||
+ | monotonic(n): | ||
'''for''' i '''in''' range(n): | '''for''' i '''in''' range(n): | ||
'''for''' x '''in''' (p(n, i) '''if''' i % 2 == 0 '''else''' p(n, i, reverse=True)): | '''for''' x '''in''' (p(n, i) '''if''' i % 2 == 0 '''else''' p(n, i, reverse=True)): |
Версия 15:33, 18 декабря 2016
Определение: |
Монотонный код Грея (англ. Monotonic Gray Code) — способ построения кода Грея, при котором | , что содержит на или больше единиц, чем .
Монотонный код Грея преимущественно используется в теории связанных сетей, например для минимизации ожидания линейным массивом процессоров.[1]
Содержание
Алгоритм построения
Для начала определим такое понятие, как вес двоичного кода, им будет являтся количество код Грея в котором бы вес всегда возрастал. Неплохим решением этой проблемы будет обход всех кодов со смежными с данным весами.
в данном двоичном коде. Очевидно, что нельзя построитьМы можем формализовать модель монотонных кодов Грея рассматривая разбиение гиперкуба
, вершины в котором являются двоичными кодами, на уровни с одинаковым весом вершин.
для
. Для всех уровней выполняется соотношение .Пусть Гамильтонов путь в , при котором любое множество вершин такие, что , то идет перед .
подграф , который является объединением двух смежных уровней, т. е. , и пусть множество граней . Тогда монотонным кодом Грея будет являтсяНиже на катринке Гамильтонов путь в гиперкубе [2]
для , построенный по алгоритму Саважа-Винклера (англ. Savage-Winkler).Элегантная идея построения
-ичного монотонного кода Грея состоит в том, чтобы рекурсивно строить подпути длинны включающих вершины .Определим
и , когда или и . То есть это объединение множеств с приписанной в начале 1 и с приписанным в начале нулем.Здесь
это определенная перестановка элементов множества к которому она применена, а это путь к котрому была применена пересатновка . Существует два варианта построить монотонный код грея по путям .Назовем их
и . Будем строить их таким образом:Выбор перестановки
обусловлен тем, чтобы получившиеся коды соответсвовали требованиям кода Грея и поэтому эта перестановка равна .Чтобы лучше разобратся в том, как сторится этот код и работает перестановка
следует рассмотреть таблицу ниже.Монотонный код Грея может быть эффективно сгенерирован по этому алгоритму за время
. Легче всего написать этот алгоритм используя генератор.Псевдокод
Перед тем как писать псевдокод необходимо объяснить что такое yield
и что понимать под выражениями типа (0,)
или (1,)
.
yield
- аналог return
только для функций-генераторов. То есть генераторы это тоже итерируемые объекты, но прочитать их можно лишь один раз. Это связано с тем, что они не хранят значения в памяти, а генерируют их на лету.
С конструкциями типа (0,)
или (1,)
все проще. Используя ее совместно с yield
мы можем в изменять наш генерируемый объект. Например, yield (0,)
допишет к генерируемому объекту (в нашем случае кортежу (англ. tuple)) в начало.
rotateRight(x, n): return x[-n:] + x[:-n]
pi(n): if n <= 1: return (0,) x = pi(n - 1) + (n - 1,) return rotate_right(tuple(x[k] for k in x), 1)
p(n, j, reverse = false): if n == 1 and j == 0: if not reverse: yield (0,) yield (1,) else: yield (1,) yield (0,) elif j >= 0 and j < n: perm = pi(n - 1) if not reverse: for x in p(n - 1, j - 1): yield (1,) + tuple(x[k] for k in perm) for x in p(n - 1, j): yield (0,) + x else: for x in p(n - 1, j, reverse=True): yield (0,) + x for x in p(n - 1, j - 1, reverse=True): yield (1,) + tuple(x[k] for k in perm)
monotonic(n): for i in range(n): for x in (p(n, i) if i % 2 == 0 else p(n, i, reverse=True)): yield x
|
Визуализация работы алгоритма
Для
Для