Сразу замечу, что дерево необязательно должно быть поисковым, но обязательно должно быть бинарным. Также симметричность я буду проверять с точки зрения связей вершин дерева, а не значений ключей.

Почему я не исследую проверку на зеркальность с точки зрения ключевых значений? Да потому что, если дерево является поисковым, то «ключевая» зеркальность в таком дереве в принципе невозможна. Поэтому все изображения деревьев, которые буду приводить в данной статье-шпаргалке, не будут иметь никаких значений, то есть я буду показывать все алгоритмы на анонимных бинарных деревьях.

 

Для начала было бы неплохо понять, какое двоичное дерево является симметричным, а какое — нет. Вот $2$ картинки.

анонимное поисковое двоичное дерево

Рисунок — несимметричное ( относительно корня ) двоичное дерево

симметричное относительно корня бинарное дерево

Рисунок — симметричное ( относительно корня ) двоичное дерево

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

💡 Очевидно, что виртуальная плоскость проходит через вершину двоичного дерева.

На следующем рисунке показана плоскость, проходящая через вершину двоичного дерева, а симметрично-зеркальные узлы раскрашены в соответственные цвета.

два зеркальных бинарных поддерева, разделенных плоскостью

Рисунок — два бинарных поддерева, разделенных зеркальной плоскостью

Моя конечная цель — написание программной функции, которая проверяет заданное двоичное дерево на зеркальную симметрию относительно корня.

➡ Очевидно, что мне придется рекурсивно перебирать узлы дерева и отслеживать направления «спуска». Но перебирать узлы нужно одновременно в обоих поддеревьях. Следовательно, мне нужно иметь $2$ поддерева при проверке, поэтому функция на вход будет принимать $2$ указателя: указатель на корень левого поддерева и указатель на корень правого поддерева.

при проверке на симметричность надо иметь указатели на левое и правое бинарное поддерево

Рисунок — при проверке на симметричность надо иметь указатели на левое и правое бинарное поддерево

💡 Если количество вершин в заданном двоичном дереве поиска — четное число ( например, $12$ ), то гарантировано это бинарное дерево не является зеркально-симметричным. Один узел будет корневым и остается $11$ узлов, которые нужно в равной пропорции разделить на два поддерева. Математически это невозможно!

В общем не стоит предварительно рассчитывать количество узлов в заданном дереве, так как эта операция имеет вычислительную сложность $O( n )$, $n$ — количество вершин.

➡ Нужно понимать такой момент ( правило ): если количество NULL-касаний в левом и правом поддереве равно и зеркально соответственно друг другу, то проверяемое бинарное дерево является зеркально-симметричным относительно своего корня.

На следующем рисунке показаны $2$ зеркально-симметричных NULL-касания.

два зеркально-симметричных NULL-касания

Рисунок — два зеркально-симметричных NULL-касания

В результате всех приведенных размышлений закодировал следующую функцию ( разумеется, рекурсивную, так как бинарные деревья крайне удобно обрабатывать рекурсивно ) на языке «чистый» Си:

Вызов этой функции может иметь такой вид:

Из представленной программной реализации видно, что вершины левого поддерева я посещаю LKP-обходом, а правого — PKL-обходом. Напомню, что всего существует $6$ классических способов обхода двоичного дерева ( поиска ).

Что касается вычислительной сложности функции Is_mirrow_simmetric(). Очевидно, что в «худшем» случае нужно посетить все вершины проверяемого на симметричность двоичного дерева. Но их достаточно посетить только по $1$ разу. Следовательно, вычислительная сложность приведенного алгоритма составляет $O( n )$, где $n$ — количество вершин проверяемого бинарного дерева.

💡 Но быстродействие функции Is_mirrow_simmetric() в некоторых случаях можно увеличить, если обратить внимание на следующий нюанс. Иногда можно выяснить, что проверяемое бинарное дерево не является зеркально-симметричным, даже не достигнув NULL-касания. Рассмотрим следующее дерево.

почти зеркально-симметричное двоичное дерево

Рисунок — почти зеркально-симметричное двоичное дерево

Симметричность этого дерева нарушается на элементах, выделенных красным цветом ( см. рисунок ниже ), но алгоритм продолжает проверки, так как никакого NULL-касания достигнуто не было. Следовательно, можно прерывать обработку, если статусы текущих вершин дерева зеркально не соответственны друг другу.

нарушение зеркальной симметрии на красных узлах

Рисунок — нарушение зеркальной симметрии на красных узлах

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

ВНИМАНИЕ Для заказа программы на бинарное дерево ( поиска ) пишите на мой электронный адрес proglabs@mail.ru