<?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=Aabb</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=Aabb"/>
		<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/Aabb"/>
		<updated>2026-07-24T04:32:47Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=74082</id>
		<title>Алгоритм Хаффмана за O(n)</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%A5%D0%B0%D1%84%D1%84%D0%BC%D0%B0%D0%BD%D0%B0_%D0%B7%D0%B0_O(n)&amp;diff=74082"/>
				<updated>2020-04-27T14:02:35Z</updated>
		
		<summary type="html">&lt;p&gt;Aabb: ошибка в алгоритме: выход за границу массива&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Задача&lt;br /&gt;
|definition =&lt;br /&gt;
Пусть у нас есть отсортированный по возрастанию алфавит &amp;lt;tex&amp;gt;\Sigma = \{a_1, a_2, \cdots, a_n\}&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;|\Sigma| = n&amp;lt;/tex&amp;gt;. Где &amp;lt;tex&amp;gt;a_i&amp;lt;/tex&amp;gt; {{---}} число вхождений символа в строку.&lt;br /&gt;
Требуется построить [[Алгоритм_Хаффмана | код Хаффмана]] за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
&lt;br /&gt;
Eсли массив не отсортирован, то это можно сделать, например,[[Цифровая_сортировка | цифровой сортировкой]] за  &amp;lt;tex&amp;gt; O(n) &amp;lt;/tex&amp;gt;, что не ухудшит асимптотику.&lt;br /&gt;
&lt;br /&gt;
Идея алгоритма заключается в том, чтобы создать такую [[Дискретная_математика,_алгоритмы_и_структуры_данных#.D0.9F.D1.80.D0.B8.D0.BE.D1.80.D0.B8.D1.82.D0.B5.D1.82.D0.BD.D1.8B.D0.B5_.D0.BE.D1.87.D0.B5.D1.80.D0.B5.D0.B4.D0.B8 | очередь с приоритетами]], из которой можно было бы доставать два минимума за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;, после чего в эту же очередь с приоритетами положить их сумму за &amp;lt;tex&amp;gt; O(1) &amp;lt;/tex&amp;gt;. У нас уже есть массив с отсортированными частотами, теперь заведем второй массив, в котором мы будем хранить суммы. &lt;br /&gt;
На каждой итерации мы будем выбирать два минимума из четырех элементов (первые 2 элемента первого массива и первые 2 элемента второго массива). Теперь рассмотрим одну итерацию подробнее. &lt;br /&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;f_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;f_2&amp;lt;/tex&amp;gt;, то в силу выбора элементов их суммарная частота &amp;lt;tex&amp;gt;S = f_1 + f_2&amp;lt;/tex&amp;gt; будет не больше суммы двух любых других из нерассмотренных частот, следовательно, никакая из последующих сумм не окажется меньше &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Докажем, что &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; не меньше значений, добавленных во второй массив на предыдущих итерациях. Допустим, что это не так и на каком-то шаге мы добавили в массив число &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; такое, что &amp;lt;tex&amp;gt;S_1 &amp;gt; S&amp;lt;/tex&amp;gt;. Это значит, что на одной из итераций мы выбрали два элемента таким образом, что хотя бы один из них был больше &amp;lt;tex&amp;gt;f_1&amp;lt;/tex&amp;gt; либо больше &amp;lt;tex&amp;gt;f_2&amp;lt;/tex&amp;gt;. Но так как первый массив отсортирован по возрастанию, а второй изначально заполнен &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;, это противоречит тому, что на каждой итерации мы выбираем два минимальных значения. Следовательно, наше предположение неверно, сумма &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; является наибольшей из рассмотренных ранее сумм и второй массив отсортирован по возрастанию.&lt;br /&gt;
&lt;br /&gt;
На каждом шаге количество элементов  уменьшается ровно на один, а минимум из 4-х элементов мы выбираем за константное время, поэтому асимптотика программы составляет &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Пример==&lt;br /&gt;
Для примера возьмем строку &amp;quot;абракадабра&amp;quot;.&lt;br /&gt;
&amp;lt;tex&amp;gt;i, j&amp;lt;/tex&amp;gt; {{---}} указатели на первые неиспользованные элементы в массиве 1 и 2, соответственно.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;tex&amp;gt;i = 0, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!   || || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На первом шаге два минимальных элемента {{---}} это первые две ячейки первого массива. Их сумму сохраняем во второй массив.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 2, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На втором шаге снова суммируются первые две ячейки первого массива (нам все равно что взять, первый элемент второго массива или второй элемент первого).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1|| 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На третьем шаге два минимальных элемента {{---}} это первые две ячейки второго массива.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 4, j = 2&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1|| 2|| 2|| 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2|| 4|| 6 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
На четвертом шаге складываются две оставшиеся ячейки.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; i = 5, j = 3&amp;lt;/tex&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Буква || д || к || б || р || а&lt;br /&gt;
|-&lt;br /&gt;
| Массив 1 || 1 || 1 || 2 || 2 || 5&lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
!  || дк || бр || дкбр || адкбр ||&lt;br /&gt;
|-&lt;br /&gt;
| Массив 2 || 2 || 4 || 6 || 11 || &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
Код возвращает число бит, необходимых для кодирования текста с заданным количеством вхождений каждого символа.&lt;br /&gt;
 '''int''' HuffmanCoding(a: '''int[0..n]'''):&lt;br /&gt;
    b: '''int[0..n]'''&lt;br /&gt;
    i, j, ans: '''int''' ''&amp;lt;font color=green&amp;gt;// i, j {{---}} указатели в массивах&amp;lt;/font&amp;gt;''&lt;br /&gt;
    '''for''' k = 0 '''to''' n&lt;br /&gt;
       b[k] = &amp;lt;tex&amp;gt;\infty&amp;lt;/tex&amp;gt;&lt;br /&gt;
    '''for''' k = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' a[i] + a[i + 1] &amp;lt;= a[i] + b[j] '''and''' a[i] + a[i + 1] &amp;lt;= b[j] + b[j + 1]//уже на 3-ей итерации выход за границу массива&lt;br /&gt;
                                                                                           //i = 4, i + 1 = 5, a[5] = undefined&lt;br /&gt;
          b[k] = a[i] + a[i + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i += 2&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' a[i] + b[j] &amp;lt;= a[i] + a[i + 1] '''and''' a[i] + b[j] &amp;lt;= b[j] + b[j + 1]&lt;br /&gt;
          b[k] = a[i] + b[j]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          i++&lt;br /&gt;
          j++&lt;br /&gt;
          '''continue'''&lt;br /&gt;
       '''if''' b[j] + b[j + 1] &amp;lt;= a[i] + a[i + 1] '''and''' b[j] + b[j + 1] &amp;lt;= a[i] + b[j]&lt;br /&gt;
          b[k] = b[j] + b[j + 1]&lt;br /&gt;
          ans += b[k]&lt;br /&gt;
          j += 2&lt;br /&gt;
    '''return''' ans&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
*[[Оптимальное хранение словаря в алгоритме Хаффмана]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы сжатия ]]&lt;/div&gt;</summary>
		<author><name>Aabb</name></author>	</entry>

	</feed>