Счётчик Кнута — различия между версиями
(→Алгоритм) |
м (rollbackEdits.php mass rollback) |
||
(не показано 15 промежуточных версий 8 участников) | |||
Строка 1: | Строка 1: | ||
− | '''Счетчик Кнута''' (англ. ''Knuth's Counter'') {{---}} структура данных, представленная избыточной двоичной системой счисления, | + | {{Определение |
+ | |id=knuth_counter | ||
+ | |definition= '''Счетчик Кнута''' (англ. ''Knuth's Counter'') {{---}} структура данных, представленная избыточной двоичной системой счисления, в которой добавление единицы к числу и вычитание единицы выполняется за <tex>O(1)</tex>. | ||
+ | }} | ||
− | Неотрицательное целое число <tex>N</tex> в ''избыточной двоичной системе счисления'' записывается в виде последовательности разрядов <tex>d_n d_{n-1} \dotsc d_2 d_1</tex>, где <tex>n</tex> обозначает количество разрядов в числе, <tex>d_i</tex> {{---}} <tex>i</tex>–й разряд числа <tex>(1 \leqslant i \leqslant n)</tex>, причем <tex>d_i \in \{0,1,2\}</tex> и <tex>\sum\limits_{i=1}^n d_i \cdot 2^i = N. | + | {{Определение |
+ | |id=knuth_counter | ||
+ | |definition= Неотрицательное целое число <tex>N</tex> в '''избыточной двоичной системе счисления''' записывается в виде последовательности разрядов <tex>(d_n d_{n-1} \dotsc d_2 d_1)</tex>, где <tex>n</tex> обозначает количество разрядов в числе, <tex>d_i</tex> {{---}} <tex>i</tex>–й разряд числа <tex>(1 \leqslant i \leqslant n)</tex>, причем <tex>d_i \in \{0,1,2\}</tex> и <tex>\sum\limits_{i=1}^n d_i \cdot 2^{i-1} = N. | ||
</tex> | </tex> | ||
+ | }} | ||
− | + | Заметим, что в этой системе представление числа неоднозначно, например представление <tex>212</tex> эквивалентно <tex>1100</tex>. | |
− | + | == Счетчик Кнута == | |
− | # Найти младший разряд <tex>d_i</tex> равный <tex>2</tex> и, если таковой имеется, заменить последовательность <tex>d_{i+1}d_i</tex> на <tex>(d_{i+1}+1)0</tex> | + | ==== Описание операции инкремента ==== |
+ | |||
+ | Оригинальный метод предложен Кнутом и состоит из двух действий: | ||
+ | |||
+ | # Найти младший разряд <tex>d_i</tex> равный <tex>2</tex> и, если таковой имеется, заменить последовательность <tex>(\dotsc d_{i+1}d_i \dotsc)</tex> на <tex>(\dotsc (d_{i+1}+1)0 \dotsc)</tex> | ||
# Заменить <tex>d_1</tex> на <tex>d_1+1</tex>. | # Заменить <tex>d_1</tex> на <tex>d_1+1</tex>. | ||
− | Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный список позиций двоек в числе. Тогда чтобы найти младший разряд равный двум нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов | + | Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный [[Список|список]] позиций двоек в числе. Тогда, чтобы найти младший разряд равный двум, нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов, необходимо выполнять следующие дополнительные действия: |
# Если <tex>d_{i+1}=1</tex>, то заменить первый элемент списка с <tex>i</tex> на <tex>i+1</tex>, иначе удалить его. | # Если <tex>d_{i+1}=1</tex>, то заменить первый элемент списка с <tex>i</tex> на <tex>i+1</tex>, иначе удалить его. | ||
# Если <tex>d_1=1</tex>, то добавить в начало списка <tex>1</tex>. | # Если <tex>d_1=1</tex>, то добавить в начало списка <tex>1</tex>. | ||
− | Проблемой может оказаться появление двух последовательных двоек, при этом | + | ==== Инвариант с нулем ==== |
− | тройку. То есть недопустима следующая ситуация <tex>\dotsc 22\dotsc \ | + | |
− | В свою очередь такая ситуация получается из этой <tex>\dotsc 212\dotsc \ | + | Проблемой может оказаться появление двух последовательных двоек, при этом первое правило может породить |
+ | тройку. То есть недопустима следующая ситуация: | ||
+ | |||
+ | <tex>(\dotsc 22\dotsc) \overset{Inc} {\longmapsto} (\dotsc 30\dotsc)</tex>. | ||
+ | |||
+ | В свою очередь такая ситуация получается из этой: | ||
+ | |||
+ | <tex>(\dotsc 212\dotsc) \overset{Inc} {\longmapsto} (\dotsc 220\dotsc)</tex> | ||
+ | |||
Причем количество единиц между двойками может быть любое, в итоге это приведет к появлению тройки. | Причем количество единиц между двойками может быть любое, в итоге это приведет к появлению тройки. | ||
− | Однако если между любой парой двоек всегда будет | + | Однако если между любой парой двоек всегда будет находиться хотя бы один |
− | <tex>0</tex>, то такой ситуации не возникнет. Покажем, | + | <tex>0</tex>, то такой ситуации не возникнет. Покажем, что этот инвариант |
поддерживается после инкремента, рассмотрев возможные ситуации: | поддерживается после инкремента, рассмотрев возможные ситуации: | ||
− | + | : Число двоек не изменяется | |
− | + | :: <tex>(\dotsc 2\dotsc 0\dotsc 12\dotsc 0) \overset{Inc} {\longmapsto} (\dotsc 2\dotsc 0\dotsc 20\dotsc 1)</tex>. | |
− | + | :: <tex>(\dotsc 02\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 10\dotsc 2)</tex>. | |
− | + | :: <tex>(\dotsc 2\dotsc 02\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 2\dotsc 10\dotsc 2)</tex> (частный случай предыдущего). | |
− | + | :: <tex>(\dotsc 12) \overset{Inc} {\longmapsto} (\dotsc 21)</tex>. | |
− | + | : Пропадает одна двойка | |
− | + | :: <tex>(\dotsc 02\dotsc 0) \overset{Inc} {\longmapsto} (\dotsc 10\dotsc 1)</tex>. | |
− | + | :: <tex>(\dotsc 02) \overset{Inc} {\longmapsto} (\dotsc 11)</tex>. | |
− | + | : Появление новой двойки | |
− | + | :: <tex>(\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 2)</tex> (имеется в виду появление единственной двойки). | |
− | + | :: <tex>(\dotsc 12\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 20\dotsc 2)</tex>. | |
− | + | :: <tex>(\dotsc 2\dotsc 0\dotsc 12\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 2\dotsc 0\dotsc 20\dotsc 2)</tex> (частный случай предыдущего). | |
+ | |||
+ | Таким образом мы видим, что <tex>0</tex> всегда сохраняется. | ||
− | + | ==== Пример ==== | |
− | В таблице можно увидеть как будет | + | В таблице можно увидеть как будет изменяться представление при применении данных правил десять раз к нулю (представления чисел от <tex>0</tex> до <tex>9</tex>): |
{| class="wikitable" | {| class="wikitable" | ||
Строка 78: | Строка 98: | ||
== Обобщение на системы с произвольным основанием == | == Обобщение на системы с произвольным основанием == | ||
− | В общем случае | + | {{Определение |
− | но основание системы может быть произвольным, то есть <tex>d_i \in \{0,1,\dotsc ,b\}</tex> и <tex>\sum\limits_{i=1}^n d_i \cdot b^i = N</tex> | + | |id=b_ary_rr |
− | , где <tex>b</tex> {{---}} основание. | + | |definition=В общем случае подобное представление называется '''<tex>b</tex>-ричным избыточным представлением''' ('''ИП''', англ. ''b-ary redundant representation''), которое похоже на представление в счетчике Кнута, но основание системы может быть произвольным, то есть <tex>d_i \in \{0,1,\dotsc ,b\}</tex> и <tex>\sum\limits_{i=1}^n d_i \cdot b^i = N</tex>, где <tex>b</tex> {{---}} основание. Оно позволяет прибавить единицу к любому разряду, то есть увеличить число на <tex>b^i</tex> за <tex>O(1)</tex> |
− | за <tex>O(1)</tex> | + | }} |
− | Назовем | + | |
− | <tex>b-1</tex>. | + | {{Определение |
− | Операция ''исправления'' (''fix'') разряда <tex>d_i=b</tex> в | + | |id=regular_rr |
− | + | |definition= Назовем представление '''регулярным''' (англ. ''regular''), если между двумя разрядами равными <tex>b</tex> есть хотя бы один разряд отличный от <tex>b-1</tex>. | |
− | <tex>d_i</tex> в <tex>0</tex>, | + | }} |
− | что и <tex>d</tex>. | + | |
− | Чтобы добавить <tex>1</tex> к разряду <tex>d_i</tex> регулярного | + | {{Определение |
− | нужно | + | |id=fixup |
+ | |definition= Операция '''исправления''' (англ. ''fix'') разряда <tex>d_i=b</tex> в регулярном ИП увеличивает <tex>d_{i+1}</tex> на <tex>1</tex> и устанавливает <tex>d_i</tex> в <tex>0</tex>, образуя новое регулярное ИП, представляющее то же число, что и <tex>d</tex>. | ||
+ | }} | ||
+ | |||
+ | Чтобы добавить <tex>1</tex> к разряду <tex>d_i</tex> регулярного ИП <tex>d</tex>, | ||
+ | нужно выполнить следующие действия: | ||
# Если <tex>d_i=b</tex>, исправить <tex>d_i</tex>. | # Если <tex>d_i=b</tex>, исправить <tex>d_i</tex>. | ||
# Если <tex>d_i=b-1</tex> и самый младший значащий разряд <tex>d_j</tex>, такой, что <tex>j>i</tex> и <tex>d_j \ne b-1</tex>, равен <tex>b</tex> (т.е. <tex>d_j=b</tex>), применить операцию исправления к разряду <tex>d_j</tex>. | # Если <tex>d_i=b-1</tex> и самый младший значащий разряд <tex>d_j</tex>, такой, что <tex>j>i</tex> и <tex>d_j \ne b-1</tex>, равен <tex>b</tex> (т.е. <tex>d_j=b</tex>), применить операцию исправления к разряду <tex>d_j</tex>. | ||
− | # Добавить 1 к <tex>d_i</tex>. | + | # Добавить <tex>1</tex> к <tex>d_i</tex>. |
# Если <tex>d_i=b</tex>, исправить <tex>d_i</tex>. | # Если <tex>d_i=b</tex>, исправить <tex>d_i</tex>. | ||
− | Для реализации данной схемы | + | Для реализации данной схемы мы используем односвязный список разрядов от младших |
к старшим. В дополнение каждый разряд <tex>d_i</tex> равный <tex>b-1</tex> | к старшим. В дополнение каждый разряд <tex>d_i</tex> равный <tex>b-1</tex> | ||
будет иметь указатель на самый младший разряд <tex>d_j</tex>, такой, | будет иметь указатель на самый младший разряд <tex>d_j</tex>, такой, | ||
что <tex>j>i</tex> и <tex>d_j \ne b-1</tex>, если он равен <tex>b</tex>, | что <tex>j>i</tex> и <tex>d_j \ne b-1</tex>, если он равен <tex>b</tex>, | ||
иначе этот указатель будет на произвольный разряд <tex>d_j</tex> (<tex>j>i</tex>). | иначе этот указатель будет на произвольный разряд <tex>d_j</tex> (<tex>j>i</tex>). | ||
− | Теперь | + | Теперь во время увеличения разряда <tex>d_i</tex> на <tex>1</tex> будем проверять |
разряд по указателю вперед (п. 2). | разряд по указателю вперед (п. 2). | ||
− | Такое представление позволяет | + | Такое представление позволяет увеличивать произвольный разряд на единицу за константное |
время. Обновление указателя вперед происходит следующим образом: когда <tex>d_{i+}</tex> становится равен <tex>b-1</tex> при исправлении разряда <tex>d_{i-1}</tex>, устанавливаем указатель вперед разряда <tex>d_{i}</tex> на <tex>d_{i+1}</tex>, если <tex>d_{i+1}=b</tex>, либо копируем указатель вперед из <tex>d_{i+1}</tex> в <tex>d_{i}</tex>, если <tex>d_{i+1}=b-1</tex>. | время. Обновление указателя вперед происходит следующим образом: когда <tex>d_{i+}</tex> становится равен <tex>b-1</tex> при исправлении разряда <tex>d_{i-1}</tex>, устанавливаем указатель вперед разряда <tex>d_{i}</tex> на <tex>d_{i+1}</tex>, если <tex>d_{i+1}=b</tex>, либо копируем указатель вперед из <tex>d_{i+1}</tex> в <tex>d_{i}</tex>, если <tex>d_{i+1}=b-1</tex>. | ||
При собственно добавлении единицы к разряду <tex>d_i</tex>, также необходимо обновлять его указатель вперед аналогичным образом, | При собственно добавлении единицы к разряду <tex>d_i</tex>, также необходимо обновлять его указатель вперед аналогичным образом, | ||
если этот разряд становится равен <tex>b-1</tex>. | если этот разряд становится равен <tex>b-1</tex>. | ||
+ | |||
+ | == См. также == | ||
+ | * [[Амортизационный анализ]] | ||
+ | * [[Представление целых чисел: прямой код, код со сдвигом, дополнительный код|Представление целых чисел]] | ||
== Источники информации == | == Источники информации == | ||
Строка 113: | Строка 142: | ||
* G. S. Brodal. Worst case priority queues. ''Proc. 7th annual ACM-SIAM Symposium on Discrete Algorithms (SODA 96)'', страницы 52-58. ACM Press, 1996. | * G. S. Brodal. Worst case priority queues. ''Proc. 7th annual ACM-SIAM Symposium on Discrete Algorithms (SODA 96)'', страницы 52-58. ACM Press, 1996. | ||
* H. Kaplan и R. E. Tarjan. Purely functional representations of catenable sorted lists. ''Proceedings of the 28th Annual ACM Symposium of Computing'', страницы 202-211. ACM Press, 1996 | * H. Kaplan и R. E. Tarjan. Purely functional representations of catenable sorted lists. ''Proceedings of the 28th Annual ACM Symposium of Computing'', страницы 202-211. ACM Press, 1996 | ||
− | * http://www.cphstl.dk/Paper/Numeral-systems/mfcs-13.pdf | + | * [http://www.cphstl.dk/Paper/Numeral-systems/mfcs-13.pdf In-Place Binary Counter] |
− | |||
− | |||
− | |||
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Амортизационный анализ]] | [[Категория: Амортизационный анализ]] |
Текущая версия на 19:13, 4 сентября 2022
Определение: |
Счетчик Кнута (англ. Knuth's Counter) — структура данных, представленная избыточной двоичной системой счисления, в которой добавление единицы к числу и вычитание единицы выполняется за | .
Определение: |
Неотрицательное целое число | в избыточной двоичной системе счисления записывается в виде последовательности разрядов , где обозначает количество разрядов в числе, — –й разряд числа , причем и
Заметим, что в этой системе представление числа неоднозначно, например представление эквивалентно .
Содержание
Счетчик Кнута
Описание операции инкремента
Оригинальный метод предложен Кнутом и состоит из двух действий:
- Найти младший разряд равный и, если таковой имеется, заменить последовательность на
- Заменить на .
Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный список позиций двоек в числе. Тогда, чтобы найти младший разряд равный двум, нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов, необходимо выполнять следующие дополнительные действия:
- Если , то заменить первый элемент списка с на , иначе удалить его.
- Если , то добавить в начало списка .
Инвариант с нулем
Проблемой может оказаться появление двух последовательных двоек, при этом первое правило может породить тройку. То есть недопустима следующая ситуация:
.
В свою очередь такая ситуация получается из этой:
Причем количество единиц между двойками может быть любое, в итоге это приведет к появлению тройки. Однако если между любой парой двоек всегда будет находиться хотя бы один
, то такой ситуации не возникнет. Покажем, что этот инвариант поддерживается после инкремента, рассмотрев возможные ситуации:- Число двоек не изменяется
- .
- .
- (частный случай предыдущего).
- .
- Пропадает одна двойка
- .
- .
- Появление новой двойки
- (имеется в виду появление единственной двойки).
- .
- (частный случай предыдущего).
Таким образом мы видим, что
всегда сохраняется.Пример
В таблице можно увидеть как будет изменяться представление при применении данных правил десять раз к нулю (представления чисел от
до ):Шаг | Представление |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
3 | 11 |
4 | 12 |
5 | 21 |
6 | 102 |
7 | 111 |
8 | 112 |
9 | 121 |
Обобщение на системы с произвольным основанием
Определение: |
В общем случае подобное представление называется | -ричным избыточным представлением (ИП, англ. b-ary redundant representation), которое похоже на представление в счетчике Кнута, но основание системы может быть произвольным, то есть и , где — основание. Оно позволяет прибавить единицу к любому разряду, то есть увеличить число на за
Определение: |
Назовем представление регулярным (англ. regular), если между двумя разрядами равными | есть хотя бы один разряд отличный от .
Определение: |
Операция исправления (англ. fix) разряда | в регулярном ИП увеличивает на и устанавливает в , образуя новое регулярное ИП, представляющее то же число, что и .
Чтобы добавить к разряду регулярного ИП ,
нужно выполнить следующие действия:
- Если , исправить .
- Если и самый младший значащий разряд , такой, что и , равен (т.е. ), применить операцию исправления к разряду .
- Добавить к .
- Если , исправить .
Для реализации данной схемы мы используем односвязный список разрядов от младших к старшим. В дополнение каждый разряд
равный будет иметь указатель на самый младший разряд , такой, что и , если он равен , иначе этот указатель будет на произвольный разряд ( ). Теперь во время увеличения разряда на будем проверять разряд по указателю вперед (п. 2).Такое представление позволяет увеличивать произвольный разряд на единицу за константное время. Обновление указателя вперед происходит следующим образом: когда
становится равен при исправлении разряда , устанавливаем указатель вперед разряда на , если , либо копируем указатель вперед из в , если . При собственно добавлении единицы к разряду , также необходимо обновлять его указатель вперед аналогичным образом, если этот разряд становится равен .См. также
Источники информации
- H. Kaplan и R. E. Tarjan. New heap data structures. 1998
- M. J. Clancy и D. E. Knuth. A programming and problem-solving seminar. Technical Report STAN-CS-77-606, Department of Computer Sciencr, Stanford University, Palo Alto, 1977.
- G. S. Brodal. Worst case priority queues. Proc. 7th annual ACM-SIAM Symposium on Discrete Algorithms (SODA 96), страницы 52-58. ACM Press, 1996.
- H. Kaplan и R. E. Tarjan. Purely functional representations of catenable sorted lists. Proceedings of the 28th Annual ACM Symposium of Computing, страницы 202-211. ACM Press, 1996
- In-Place Binary Counter