Цепные коды
Цепной код — это такое упорядочивание двоичных векторов одной длины, каждый следующий столбец которого (можно рассматривать как таблицу из
элементов) получается из предыдущего циклическим сдвигом вверх.Алгоритм получения цепного кода для двоичных векторов
В качестве первого вектора берём вектор из
нулей. Чтобы получить следующий вектор, берём последний добавленный вектор, пусть . Если в коде до этого не встречатся вектор , то добавляем его. Иначе проверяем на наличие в коде вектора . Если такой не встречался, добавляем его. Если вектор уже встречался, значит, генерация кода закончена.Псевдокод алгоритма
chain_code(n): current = string('0', n) result = [current] while (true): prefix = current.substring(2, n) if concat(prefix, '1') not in result: current = concat(prefix, '1') else concat(prefix, '0') not in result: current = concat(prefix, '0') else: break result.append(current) return result
В приведённом выше псевдокоде:
- current — последний добавленный битовый вектор
- result — список битовых векторов
Доказательство корректности
Разобьем доказательство на две части:
- Доказательство того, что один и тот же вектор встречается в коде не более одного раза.
- Доказательство того, что алгоритм перебирает все возможные вектора прежде, чем получит вектор из нулей.
Доказательство первого пункта
Покажем, что единственная ситуация, когда требуется сгенерировать новый вектор, а оба возможных варианта (добавление нуля или единицы) уже добавлены — сгенерирован вектор из
нулей. Рассмотрим первое такое противоречие: последним добавлен вектор , вектора и уже присутствуют в коде.Далее есть две возможных ситуации: вектор
состоит из нулей или предшествовал другому вектору в коде. В первой ситуации алгоритм завершает работу.Во второй сутиации каждому из векторов
и предшествовали некоторые вектора в коде, пусть и . Так как мы рассматриваем первое противоречие, то .Но в таком случае вектор
совпадает с одним из векторов или . Это противоречит предположению о том, что рассмотренная конфликтная ситуация является первой, следовательно, реализуется только первый вариант ситуации.Доказательство второго пункта
Покажем, что невозможно вернуться к слову из всех нулей, пока не переберем все
слов, где n — длина слова. Допустим, мы всё же получили слово из всех нулей раньше, чем перебрали все слова. Тогда разобьём слова, которые не попали в код на две группы: кончающиеся на единицу и кончающиеся на ноль. Докажем, что второй группы группы нет. Рассмотрим слово {abc..yz}0, не попавшее в код, где {abc..yz} — некоторая последовательность единиц и нулей. Заметим, что слово {bc..yz}00 также не в коде. Оно могло быть получено из слов 1{bc..yz}0 и 0{bc..yz}0, одно из которых есть рассматриваемое {abc..yz}0. Но если другое слово и встретилось в коде, то мы бы получили из него {bc..yz}01, следуя алгоритму (причем это слово точно встретится в первый раз). Таким образом, слово {bc..yz}00 точно не в коде. Такую же цепочку рассуждений можно провести и для слова {c..yz}000, и так далее. На n-ом шаге мы бы получили утверждение, что слова из n нулей тоже нет в коде, и пришли бы к противоречию. Заметим, что исходя из третьего и четвертого шагов, все слова вида {abc..yz}1 встречаются строго раньше {abc..yz}0, которые точно записаны в код. Таким образом, слов, не попавших в код, нет.