Новая Школа - онлайн-школа подготовки к ЕГЭ
Информатика · 10 класс Задача №3448915
А
Аноним
03 октября 2025 09:48 · публичный вопрос
А
Аноним

искусственный интеллект по алгоритму Хоффмана

Ответ нейросети
03 октября 2025 09:48

Классно. Разберём задачу по Huffman-кодированию (алгоритм Хоффмана) подробно и понятно для 10 класса информатики. Заметим: Huffman-кодирование — это техника сжатия данных, а не искусственный интеллект. Но она часто встречается в задачах по информатике как пример эффективного кодирования информации.

  1. Что такое Huffman-кодирование (кратко)
  • Мы строим двоичное дерево по частотам встречаемости символов в тексте.
  • Частые символы получают короче коды, редкие — длиннее.
  • В итоге текст кодируется последовательностью битов, которая в среднем занимает меньше места.
  1. Пошаговый алгоритм
  • Шаг 1. Подсчитать частоты появления каждого символа в исходной строке.
  • Шаг 2. Создать для каждого символа «лист» дерева кодирования с весом, равным его частоте. Поместить все листья в приоритетную очередь (min-heap) по весу.
  • Шаг 3. Пока в очереди больше одного узла:
    • достать два узла с наименьшей частотой,
    • создать новый внутренний узел, чьи дети — эти два узла, вес нового узла — сумма их весов,
    • вернуть этот новый узел обратно в очередь.
  • Шаг 4. Корень получившегося дерева — это дерево Хоффмана.
  • Шаг 5. Обойти дерево топ-дауном: при переходе влево дописываем 0, вправо — 1. Так получают код для каждого символа.
  • Шаг 6. Закодировать строку, заменив каждый символ на его код.
  • Шаг 7. Декодирование: пройти по битовой строке, ориентируясь по дереву, добираться до листа и записывать соответствующий символ, затем возвращаться к корню.
  1. Пример (наглядно) Возьмём строку: "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".
  1. Плюсы и замечания
  • Huffman эффективен, если частоты символов различаются значительно.
  • Алгоритм не требует длинного обучения; частоты можно посчитать напрямую из текста.
  • В реальных системах после кодирования битовую последовательность упаковывают в байты, и добавляют паддинг, чтобы длина была кратна 8. Здесь для простоты мы работаем с битовой строкой.
  1. Простой пример реализации на 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)

  1. Что можно сделать на практике
  • Попрактиковаться на других строках, например:
    • text = "abracadabra"
    • text = "mississippi"
  • Задания: найти коды и длину закодированной строки, посчитать среднюю длину. Посчитать отношение размера закодированной строки к исходному тексту (коэффициент сжатия), без упаковки бит в байты.

Если хочешь, могу адаптировать решение под конкретную задачу: дать готовый пример с твоей строкой (включая подсчёт частот, коды, кодировку и декодирование) или расписать шаги под другое задание.