<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.152.112&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=217.66.152.112&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/217.66.152.112"/>
		<updated>2026-08-02T12:30:04Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%87%D1%91%D1%82%D1%87%D0%B8%D0%BA_%D0%9A%D0%BD%D1%83%D1%82%D0%B0&amp;diff=71898</id>
		<title>Счётчик Кнута</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D1%87%D1%91%D1%82%D1%87%D0%B8%D0%BA_%D0%9A%D0%BD%D1%83%D1%82%D0%B0&amp;diff=71898"/>
				<updated>2019-10-23T11:11:17Z</updated>
		
		<summary type="html">&lt;p&gt;217.66.152.112: Опечатка. Слово &amp;quot;дувумя&amp;quot; исправлено на &amp;quot;двумя&amp;quot;.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Определение&lt;br /&gt;
|id=knuth_counter&lt;br /&gt;
|definition= '''Счетчик Кнута''' (англ. ''Knuth's Counter'')  {{---}} структура данных, представленная избыточной двоичной системой счисления, в которой добавление единицы к числу и вычитание единицы выполняется за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=knuth_counter&lt;br /&gt;
|definition= Неотрицательное целое число &amp;lt;tex&amp;gt;N&amp;lt;/tex&amp;gt; в '''избыточной двоичной системе счисления''' записывается в виде последовательности разрядов &amp;lt;tex&amp;gt;(d_n d_{n-1} \dotsc  d_2 d_1)&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; обозначает количество разрядов в числе, &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;  {{---}} &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&amp;amp;ndash;й разряд числа &amp;lt;tex&amp;gt;(1 \leqslant i \leqslant n)&amp;lt;/tex&amp;gt;, причем &amp;lt;tex&amp;gt;d_i \in \{0,1,2\}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\sum\limits_{i=1}^n d_i \cdot 2^{i-1} = N.&lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Заметим, что в этой системе представление числа неоднозначно, например представление &amp;lt;tex&amp;gt;212&amp;lt;/tex&amp;gt; эквивалентно &amp;lt;tex&amp;gt;1100&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Счетчик Кнута ==&lt;br /&gt;
&lt;br /&gt;
==== Описание операции инкремента ====&lt;br /&gt;
&lt;br /&gt;
Оригинальный метод предложен Кнутом и состоит из двух действий:&lt;br /&gt;
&lt;br /&gt;
# Найти младший разряд &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt; равный &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; и, если таковой имеется, заменить последовательность &amp;lt;tex&amp;gt;(\dotsc d_{i+1}d_i \dotsc)&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;(\dotsc (d_{i+1}+1)0 \dotsc)&amp;lt;/tex&amp;gt;&lt;br /&gt;
# Заменить &amp;lt;tex&amp;gt;d_1&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;d_1+1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Чтобы достичь необходимой оценки и не выполнять каждый раз поиск для первого правила, можно хранить односвязный [[Список|список]] позиций двоек в числе. Тогда, чтобы найти младший разряд равный двум, нужно просто взять первый элемент списка. Также, непосредственно перед изменением значений разрядов, необходимо выполнять следующие дополнительные действия:&lt;br /&gt;
&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;d_{i+1}=1&amp;lt;/tex&amp;gt;, то заменить первый элемент списка с &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;i+1&amp;lt;/tex&amp;gt;, иначе удалить его.&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;d_1=1&amp;lt;/tex&amp;gt;, то добавить в начало списка &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==== Инвариант с нулем ====&lt;br /&gt;
&lt;br /&gt;
Проблемой может оказаться появление двух последовательных двоек, при этом первое правило может породить&lt;br /&gt;
тройку. То есть недопустима следующая ситуация: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;(\dotsc 22\dotsc) \overset{Inc} {\longmapsto} (\dotsc 30\dotsc)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
В свою очередь такая ситуация получается из этой:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;(\dotsc 212\dotsc) \overset{Inc} {\longmapsto} (\dotsc 220\dotsc)&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Причем количество единиц между двойками может быть любое, в итоге это приведет к появлению тройки.&lt;br /&gt;
Однако если между любой парой двоек всегда будет находиться хотя бы один&lt;br /&gt;
&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, то такой ситуации не возникнет. Покажем, что этот инвариант&lt;br /&gt;
поддерживается после инкремента, рассмотрев возможные ситуации:&lt;br /&gt;
: Число двоек не изменяется&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 2\dotsc 0\dotsc 12\dotsc 0) \overset{Inc} {\longmapsto} (\dotsc 2\dotsc 0\dotsc 20\dotsc 1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 02\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 10\dotsc 2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 2\dotsc 02\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 2\dotsc 10\dotsc 2)&amp;lt;/tex&amp;gt; (частный случай предыдущего).&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 12) \overset{Inc} {\longmapsto} (\dotsc 21)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Пропадает одна двойка&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 02\dotsc 0) \overset{Inc} {\longmapsto} (\dotsc 10\dotsc 1)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 02) \overset{Inc} {\longmapsto} (\dotsc 11)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Появление новой двойки&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 2)&amp;lt;/tex&amp;gt; (имеется в виду появление единственной двойки).&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 12\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 20\dotsc 2)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
:: &amp;lt;tex&amp;gt;(\dotsc 2\dotsc 0\dotsc 12\dotsc 1) \overset{Inc} {\longmapsto} (\dotsc 2\dotsc 0\dotsc 20\dotsc 2)&amp;lt;/tex&amp;gt; (частный случай предыдущего).&lt;br /&gt;
&lt;br /&gt;
Таким образом мы видим, что &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; всегда сохраняется.&lt;br /&gt;
&lt;br /&gt;
==== Пример ====&lt;br /&gt;
&lt;br /&gt;
В таблице можно увидеть как будет изменятья представление при применении данных правил десять раз к нулю (представления чисел от &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;9&amp;lt;/tex&amp;gt;):&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Шаг&lt;br /&gt;
! Представление&lt;br /&gt;
|-&lt;br /&gt;
| 0 &lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 1 &lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 2 &lt;br /&gt;
| 2&lt;br /&gt;
|-&lt;br /&gt;
| 3 &lt;br /&gt;
| 11&lt;br /&gt;
|-&lt;br /&gt;
| 4 &lt;br /&gt;
| 12&lt;br /&gt;
|-&lt;br /&gt;
| 5 &lt;br /&gt;
| 21&lt;br /&gt;
|-&lt;br /&gt;
| 6 &lt;br /&gt;
| 102&lt;br /&gt;
|-&lt;br /&gt;
| 7 &lt;br /&gt;
| 111&lt;br /&gt;
|-&lt;br /&gt;
| 8 &lt;br /&gt;
| 112&lt;br /&gt;
|-&lt;br /&gt;
| 9 &lt;br /&gt;
| 121&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Обобщение на системы с произвольным основанием ==&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=b_ary_rr&lt;br /&gt;
|definition=В общем случае подобное представление называется '''&amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;-ричным избыточным представлением''' ('''ИП''', англ. ''b-ary redundant representation''), которое похоже на представление в счетчике Кнута, но основание системы может быть произвольным, то есть &amp;lt;tex&amp;gt;d_i \in \{0,1,\dotsc ,b\}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\sum\limits_{i=1}^n d_i \cdot b^i = N&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;  {{---}} основание. Оно позволяет прибавить единицу к любому разряду, то есть увеличить число на &amp;lt;tex&amp;gt;b^i&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=regular_rr&lt;br /&gt;
|definition= Назовем представление '''регулярным''' (англ. ''regular''), если между двумя разрядами равными &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; есть хотя бы один разряд отличный от &amp;lt;tex&amp;gt;b-1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Определение&lt;br /&gt;
|id=fixup&lt;br /&gt;
|definition= Операция '''исправления''' (англ. ''fix'') разряда &amp;lt;tex&amp;gt;d_i=b&amp;lt;/tex&amp;gt; в регулярном ИП увеличивает &amp;lt;tex&amp;gt;d_{i+1}&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; и устанавливает &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;, образуя новое регулярное ИП, представляющее то же число, что и &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Чтобы добавить &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; к разряду &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt; регулярного ИП &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt;,&lt;br /&gt;
нужно выполнить следующие действия:&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;d_i=b&amp;lt;/tex&amp;gt;, исправить &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;d_i=b-1&amp;lt;/tex&amp;gt; и самый младший значащий разряд &amp;lt;tex&amp;gt;d_j&amp;lt;/tex&amp;gt;, такой, что &amp;lt;tex&amp;gt;j&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d_j \ne b-1&amp;lt;/tex&amp;gt;, равен &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; (т.е. &amp;lt;tex&amp;gt;d_j=b&amp;lt;/tex&amp;gt;), применить операцию исправления к разряду &amp;lt;tex&amp;gt;d_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Добавить &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; к &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# Если &amp;lt;tex&amp;gt;d_i=b&amp;lt;/tex&amp;gt;, исправить &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Для реализации данной схемы мы используем односвязный список разрядов от младших&lt;br /&gt;
к старшим. В дополнение каждый разряд &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt; равный &amp;lt;tex&amp;gt;b-1&amp;lt;/tex&amp;gt;&lt;br /&gt;
будет иметь указатель на самый младший разряд &amp;lt;tex&amp;gt;d_j&amp;lt;/tex&amp;gt;, такой,&lt;br /&gt;
что &amp;lt;tex&amp;gt;j&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d_j \ne b-1&amp;lt;/tex&amp;gt;, если он равен &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt;,&lt;br /&gt;
иначе этот указатель будет на произвольный разряд &amp;lt;tex&amp;gt;d_j&amp;lt;/tex&amp;gt; (&amp;lt;tex&amp;gt;j&amp;gt;i&amp;lt;/tex&amp;gt;).&lt;br /&gt;
Теперь во время увеличения разряда &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; будем проверять&lt;br /&gt;
разряд по указателю вперед (п. 2).&lt;br /&gt;
&lt;br /&gt;
Такое представление позволяет увеличивать произвольный разряд на единицу за константное&lt;br /&gt;
время. Обновление указателя вперед происходит следующим образом: когда &amp;lt;tex&amp;gt;d_{i+}&amp;lt;/tex&amp;gt; становится равен &amp;lt;tex&amp;gt;b-1&amp;lt;/tex&amp;gt; при исправлении разряда &amp;lt;tex&amp;gt;d_{i-1}&amp;lt;/tex&amp;gt;, устанавливаем указатель вперед разряда &amp;lt;tex&amp;gt;d_{i}&amp;lt;/tex&amp;gt; на &amp;lt;tex&amp;gt;d_{i+1}&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;d_{i+1}=b&amp;lt;/tex&amp;gt;, либо копируем указатель вперед из &amp;lt;tex&amp;gt;d_{i+1}&amp;lt;/tex&amp;gt; в &amp;lt;tex&amp;gt;d_{i}&amp;lt;/tex&amp;gt;, если &amp;lt;tex&amp;gt;d_{i+1}=b-1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
При собственно добавлении единицы к разряду &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;, также необходимо обновлять его указатель вперед аналогичным образом,&lt;br /&gt;
если этот разряд становится равен &amp;lt;tex&amp;gt;b-1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Амортизационный анализ]]&lt;br /&gt;
* [[Представление целых чисел: прямой код, код со сдвигом, дополнительный код|Представление целых чисел]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* H. Kaplan и R. E. Tarjan. New heap data structures. 1998&lt;br /&gt;
* 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.&lt;br /&gt;
* G. S. Brodal. Worst case priority queues. ''Proc. 7th annual ACM-SIAM Symposium on Discrete Algorithms (SODA 96)'', страницы 52-58. ACM Press, 1996.&lt;br /&gt;
* 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&lt;br /&gt;
* [http://www.cphstl.dk/Paper/Numeral-systems/mfcs-13.pdf In-Place Binary Counter]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Амортизационный анализ]]&lt;/div&gt;</summary>
		<author><name>217.66.152.112</name></author>	</entry>

	</feed>