Счётчик Кнута — различия между версиями
(Переписывание конспекта заново) |
(Исправления) |
||
Строка 1: | Строка 1: | ||
− | '''Счетчик Кнута''' (англ. ''Knuth's Counter'') | + | '''Счетчик Кнута''' (англ. ''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>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. |
− | </ | + | </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>d_{i+1}d_i</tex> на <tex>(d_{i+1}+1)0</tex> | ||
Строка 13: | Строка 13: | ||
Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный список позиций двоек в числе. Тогда чтобы найти младший разряд равный двум нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов в правилах необходимо выполнять следующее: | Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный список позиций двоек в числе. Тогда чтобы найти младший разряд равный двум нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов в правилах необходимо выполнять следующее: | ||
− | # Если <tex>d_{i+1}=1</tex>, то заменить первый элемент списка с < | + | # Если <tex>d_{i+1}=1</tex>, то заменить первый элемент списка с <tex>i</tex> на <tex>i+1</tex>, иначе удалить его. |
− | # Если <tex>d_1=1</tex>, то добавить в начало списка 1. | + | # Если <tex>d_1=1</tex>, то добавить в начало списка <tex>1</tex>. |
Проблемой может оказаться появление двух последовательных двоек, при этом перое правило может породить | Проблемой может оказаться появление двух последовательных двоек, при этом перое правило может породить | ||
− | тройку, | + | тройку. То есть недопустима следующая ситуация <tex>\dotsc 22\dotsc \rightarrow \dotsc 30\dotsc</tex>. |
− | 0, то такой ситуации не возникнет. Покажем, что | + | В свою очередь такая ситуация получается из этой <tex>\dotsc 212\dotsc \rightarrow \dotsc 220\dotsc</tex>. |
− | + | Причем количество единиц между двойками может быть любое, в итоге это приведет к появлению тройки. | |
− | + | Однако если между любой парой двоек всегда будет находится хотя бы один | |
− | + | <tex>0</tex>, то такой ситуации не возникнет. Покажем, что что этот инвариант | |
− | + | поддерживается после инкремента, рассмотрев возможные ситуации: | |
− | + | # Число двоек не изменяется | |
− | + | ## <tex>\dotsc 2\dotsc 0\dotsc 12\dotsc 0 \rightarrow \dotsc 2\dotsc 0\dotsc 20\dotsc 1</tex>. | |
+ | ## <tex>\dotsc 02\dotsc 1 \rightarrow \dotsc 10\dotsc 2</tex>. | ||
+ | ## <tex>\dotsc 2\dotsc 02\dotsc 1 \rightarrow \dotsc 2\dotsc 10\dotsc 2</tex> (частный случай предыдущего). | ||
+ | # Проподает одна двойка | ||
+ | ## <tex> \dotsc 02\dotsc 0 \rightarrow \dotsc 10\dotsc 1</tex>. | ||
+ | ## <tex> \dotsc 02 \rightarrow \dotsc 11</tex>. | ||
+ | # Появление новой двойки | ||
+ | ## <tex>\dotsc 1 \rightarrow \dotsc 2</tex> (имеется в виду появление единственной двойки). | ||
+ | ## <tex>\dotsc 12\dotsc 1 \rightarrow \dotsc 20\dotsc 2</tex>. | ||
+ | ## <tex>\dotsc 2\dotsc 0\dotsc 12\dotsc 1 \rightarrow \dotsc 2\dotsc 0\dotsc 20\dotsc 2</tex> (частный случай предыдущего). | ||
− | В таблице можно увидеть как будет изменятья представление при применении данных правил десять раз к нулю (представления чисел от 0 до | + | Таким образом мы видим, что 0 всегда сохраняется. |
+ | |||
+ | В таблице можно увидеть как будет изменятья представление при применении данных правил десять раз к нулю (представления чисел от <tex>0</tex> до <tex>9</tex>): | ||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
− | |||
− | |||
! Шаг | ! Шаг | ||
! Представление | ! Представление | ||
Строка 37: | Строка 46: | ||
| 0 | | 0 | ||
| 0 | | 0 | ||
+ | |- | ||
+ | | 1 | ||
+ | | 1 | ||
+ | |- | ||
+ | | 2 | ||
+ | | 2 | ||
+ | |- | ||
+ | | 3 | ||
+ | | 11 | ||
+ | |- | ||
+ | | 4 | ||
+ | | 12 | ||
+ | |- | ||
| 5 | | 5 | ||
| 21 | | 21 | ||
|- | |- | ||
− | |||
− | |||
| 6 | | 6 | ||
| 102 | | 102 | ||
|- | |- | ||
− | |||
− | |||
| 7 | | 7 | ||
| 111 | | 111 | ||
|- | |- | ||
− | |||
− | |||
| 8 | | 8 | ||
| 112 | | 112 | ||
|- | |- | ||
− | |||
− | |||
| 9 | | 9 | ||
| 121 | | 121 | ||
Строка 63: | Строка 77: | ||
== Обобщение на системы с произвольным основанием == | == Обобщение на системы с произвольным основанием == | ||
− | В общем случае подобные счётчики называются ''< | + | В общем случае подобные счётчики называются ''<tex>b</tex>-ричными избыточными счетчиками'' (''ИС''), которые похожи на счетчик Кнута, |
− | но основание системы может быть произвольным, то есть < | + | но основание системы может быть произвольным, то есть <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>b</tex> есть хотя бы один разряд отличный от |
− | < | + | <tex>b-1</tex>. |
− | Операция ''исправления'' (''fix'') разряда < | + | Операция ''исправления'' (''fix'') разряда <tex>d_i=b</tex> в регулярной <tex>b</tex>-ричного |
− | счетчика < | + | счетчика <tex>d</tex> увеличивает <tex>d_{i+1}</tex> на <tex>1</tex> и устанавливает |
− | < | + | <tex>d_i</tex> в <tex>0</tex>, образуая новый регулярный счетчик, представляющий то же число, |
− | что и < | + | что и <tex>d</tex>. |
− | Чтобы добавить 1 к разряду < | + | Чтобы добавить <tex>1</tex> к разряду <tex>d_i</tex> регулярного ИС <tex>d</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>. |
− | # Добавить 1 к < | + | # Добавить 1 к <tex>d_i</tex>. |
− | # Если < | + | # Если <tex>d_i=b</tex>, исправить <tex>d_i</tex>. |
− | Для реализации данной схемы, мы используем односвязный список | + | Для реализации данной схемы, мы используем односвязный список разрядов от младших |
− | к старшим. В дополнение каждый разряд < | + | к старшим. В дополнение каждый разряд <tex>d_i</tex> равный <tex>b-1</tex> |
− | будет иметь указатель на самый младший разряд < | + | будет иметь указатель на самый младший разряд <tex>d_j</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_i</tex> на 1, будем проверять |
разряд по указателю вперед (п. 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>. |
− | == | + | == Источники информации == |
* H. Kaplan и R. E. Tarjan. New heap data structures. 1998 | * 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. | * 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. | * 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 | |
− | |||
* [[Амортизационный анализ]] | * [[Амортизационный анализ]] | ||
* [[Представление целых чисел: прямой код, код со сдвигом, дополнительный код]] | * [[Представление целых чисел: прямой код, код со сдвигом, дополнительный код]] | ||
+ | * [[Список]] | ||
[[Категория: Дискретная математика и алгоритмы]] | [[Категория: Дискретная математика и алгоритмы]] | ||
[[Категория: Амортизационный анализ]] | [[Категория: Амортизационный анализ]] |
Версия 22:57, 15 июня 2014
Счетчик Кнута (англ. Knuth's Counter) — структура данных, представленная избыточной двоичной системой счисления, где добавление единицы к числу выполняется за
.Неотрицательное целое число
в избыточной двоичной системе счисления записывается в виде последовательности разрядов , где обозначает количество разрядов в числе, — –й разряд числа , причем иАлгоритм
Оригинальный алгоритм предложен в Кнутом, и состоит из двух правил:
- Найти младший разряд равный и, если таковой имеется, заменить последовательность на
- Заменить на .
Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный список позиций двоек в числе. Тогда чтобы найти младший разряд равный двум нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов в правилах необходимо выполнять следующее:
- Если , то заменить первый элемент списка с на , иначе удалить его.
- Если , то добавить в начало списка .
Проблемой может оказаться появление двух последовательных двоек, при этом перое правило может породить тройку. То есть недопустима следующая ситуация
. В свою очередь такая ситуация получается из этой . Причем количество единиц между двойками может быть любое, в итоге это приведет к появлению тройки. Однако если между любой парой двоек всегда будет находится хотя бы один , то такой ситуации не возникнет. Покажем, что что этот инвариант поддерживается после инкремента, рассмотрев возможные ситуации:- Число двоек не изменяется
- .
- .
- (частный случай предыдущего).
- Проподает одна двойка
- .
- .
- Появление новой двойки
- (имеется в виду появление единственной двойки).
- .
- (частный случай предыдущего).
Таким образом мы видим, что 0 всегда сохраняется.
В таблице можно увидеть как будет изменятья представление при применении данных правил десять раз к нулю (представления чисел от
до ):Шаг | Представление |
---|---|
0 | 0 |
1 | 1 |
2 | 2 |
3 | 11 |
4 | 12 |
5 | 21 |
6 | 102 |
7 | 111 |
8 | 112 |
9 | 121 |
Обобщение на системы с произвольным основанием
В общем случае подобные счётчики называются
-ричными избыточными счетчиками (ИС), которые похожи на счетчик Кнута, но основание системы может быть произвольным, то есть и , где — основание. Такие счетчики позволяют прибавить единицу к любому разряду, то есть увеличить число на за Назовем такое представление регулярным, если между дувумя разрядами равными есть хотя бы один разряд отличный от . Операция исправления (fix) разряда в регулярной -ричного счетчика увеличивает на и устанавливает в , образуая новый регулярный счетчик, представляющий то же число, что и . Чтобы добавить к разряду регулярного ИС , нужно сделать следующее:- Если , исправить .
- Если и самый младший значащий разряд , такой, что и , равен (т.е. ), применить операцию исправления к разряду .
- Добавить 1 к .
- Если , исправить .
Для реализации данной схемы, мы используем односвязный список разрядов от младших к старшим. В дополнение каждый разряд
равный будет иметь указатель на самый младший разряд , такой, что и , если он равен , иначе этот указатель будет на произвольный разряд ( ). Теперь, во время увеличения разряда на 1, будем проверять разряд по указателю вперед (п. 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
- http://www.cphstl.dk/Paper/Numeral-systems/mfcs-13.pdf
- Амортизационный анализ
- Представление целых чисел: прямой код, код со сдвигом, дополнительный код
- Список