Искусственный интеллект по алгоритму Хоффмана
Ответ нейросети
03 октября 2025 09:48
Классно. Разберём задачу по Huffman-кодированию (алгоритм Хоффмана) подробно и понятно для 10 класса информатики. Заметим: Huffman-кодирование — это техника сжатия данных, а не искусственный интеллект. Но она часто встречается в задачах по информатике как пример эффективного кодирования информации.
- Что такое Huffman-кодирование (кратко)
- Мы строим двоичное дерево по частотам встречаемости символов в тексте.
- Частые символы получают короче коды, редкие — длиннее.
- В итоге текст кодируется последовательностью битов, которая в среднем занимает меньше места.
- Пошаговый алгоритм
- Шаг 1. Подсчитать частоты появления каждого символа в исходной строке.
- Шаг 2. Создать для каждого символа «лист» дерева кодирования с весом, равным его частоте. Поместить все листья в приоритетную очередь (min-heap) по весу.
- Шаг 3. Пока в очереди больше одного узла:
- достать два узла с наименьшей частотой,
- создать новый внутренний узел, чьи дети — эти два узла, вес нового узла — сумма их весов,
- вернуть этот новый узел обратно в очередь.
- Шаг 4. Корень получившегося дерева — это дерево Хоффмана.
- Шаг 5. Обойти дерево топ-дауном: при переходе влево дописываем 0, вправо — 1. Так получают код для каждого символа.
- Шаг 6. Закодировать строку, заменив каждый символ на его код.
- Шаг 7. Декодирование: пройти по битовой строке, ориентируясь по дереву, добираться до листа и записывать соответствующий символ, затем возвращаться к корню.
- Пример (наглядно) Возьмём строку: "aaabbc"
- Частоты: a — 3, b — 2, c — 1.
- Логику развернём так, как обычно делают приоритетная очередь (минимальные частоты выбираются первыми). Возможна вариация из-за равенств, но суть одинакова.
- Берём c(1) и b(2) → создаём узел n1(3) с дочерними c и b.
- Теперь остаётся a(3) и n1(3). Берём их оба → корень дерева суммарной частоты 6.
- Пути: левый ребёнок корня — код 0 (это a), правый — код начинается с 1; в правом поддереве c и b получают коды 10 и 11 соответственно.
- В итоге коды могут быть такими:
- a: 0
- c: 10
- b: 11
- Кодируем строку "aaabbc":
- a a a b b c → 0 0 0 11 11 10
- Без пробелов: "000111110" (9 бит)
- Средняя длина кода: для каждого символа умножаем частоту на длину кода и делим на общее число символов.
- Длины: a — 1 бит, b — 2 бита, c — 2 бита.
- Средняя длина = (31 + 22 + 1*2) / 6 = (3 + 4 + 2) / 6 = 9/6 = 1.5 бита на символ.
- Декодирование: по битам "000111110" пройти по дереву и получить исходную строку "aaabbc".
- Плюсы и замечания
- Huffman эффективен, если частоты символов различаются значительно.
- Алгоритм не требует длинного обучения; частоты можно посчитать напрямую из текста.
- В реальных системах после кодирования битовую последовательность упаковывают в байты, и добавляют паддинг, чтобы длина была кратна 8. Здесь для простоты мы работаем с битовой строкой.
- Простой пример реализации на Python (пояснение к коду)
Задаём структуру узла дерева, используем мин-кучу для выбора двух минимальных весов.
Функции:
- build_tree(text) — строит дерево Хоффмана и возвращает корень и частоты.
- build_codes(node) — создаёт словарь кодов для каждого символа.
- encode(text, codes) — кодирует текст по кодам.
- decode(bits, root) — раскодирует битовую строку обратно в текст.
Пример кода (упрощённый, без упаковки бит в байты):
импортируем модуль Counter (для частот) и heapq (для очереди с приоритетом).
определяем класс Node с полями freq, ch (символ, если лист), left и right.
lt в классе нужен для корректной работы очереди по весу.
Пример кода:
from collections import Counter import heapq
class Node: def init(self, freq, ch=None, left=None, right=None): self.freq = freq self.ch = ch self.left = left self.right = right
# для корректной работы в heapq
def __lt__(self, other):
return self.freq < other.freq
def build_tree(text): freq = Counter(text) heap = [] for ch, f in freq.items(): heapq.heappush(heap, (f, Node(f, ch))) while len(heap) > 1: f1, n1 = heapq.heappop(heap) f2, n2 = heapq.heappop(heap) parent = Node(f1 + f2, left=n1, right=n2) heapq.heappush(heap, (parent.freq, parent)) root = heap[0][1] if heap else None return root, freq
def build_codes(node, prefix="", code_map=None): if code_map is None: code_map = {} if node is None: return code_map if node.ch is not None: code_map[node.ch] = prefix else: build_codes(node.left, prefix + "0", code_map) build_codes(node.right, prefix + "1", code_map) return code_map
def encode(text, code_map): return "".join(code_map[ch] for ch in text)
def decode(bitstring, root): out = [] node = root for bit in bitstring: node = node.left if bit == "0" else node.right if node.ch is not None: out.append(node.ch) node = root return "".join(out)
Пример использования
text = "aaabbc" root, freq = build_tree(text) codes = build_codes(root) encoded = encode(text, codes) decoded = decode(encoded, root)
print("Частоты:", freq) print("Коды:", codes) print("Закодировано:", encoded) print("Декодировано:", decoded)
- Что можно сделать на практике
- Попрактиковаться на других строках, например:
- text = "abracadabra"
- text = "mississippi"
- Задания: найти коды и длину закодированной строки, посчитать среднюю длину. Посчитать отношение размера закодированной строки к исходному тексту (коэффициент сжатия), без упаковки бит в байты.
Если хочешь, могу адаптировать решение под конкретную задачу: дать готовый пример с твоей строкой (включая подсчёт частот, коды, кодировку и декодирование) или расписать шаги под другое задание.
Понравился ответ?
Задай свой вопрос
Напиши любую задачу или вопрос, а нейросеть её решит



