Нелинейные структуры данных
[Оглавление] [<< страница] [>>страница]


   6. Идеально сбалансированное бинарное дерево
 

Поскольку максимальный путь до листьев дерева определяется высотой дерева, то при заданном числе n узлов дерева стремятся построить дерево минимальной высоты. Этого можно достичь, если размещать максимально возможное количество узлов на всех уровнях, кроме последнего. В случае двоичного дерева это достигается таким образом, что все поступающие при построении дерева узлы распределяются поровну слева и справа от каждого узла.

Говорят, что бинарное дерево идеально сбалансировано, если для каждого его узла количество узлов в левом и правом поддеревьях различается не более чем на 1.

Создание идеально сбалансированного дерева не вызывает затруднений. Если число узлов и известно и дана последовательность значений поля данных вершин а[0], а[1],...,а[п - 1], то можно использовать следующий рекурсивный алгоритм построения идеально сбалансированного дерева:
1.  Начиная с а[0], берем очередное значение а[i] в качестве значения корня дерева (поддерева).
2.  Строим левое поддерево с n1 = n/2 узлами тем же cпособом.
3.  Строим правое поддерево с nr = n - nl - 1 узлами.

Таким образом, значение a[0] окажется в корне дерева, а именно на него будет ссылаться указатель дерева, а[1],...а[nl] значения попадут в левое поддерево, остальные — в правое поддерево. Следовательно, распределение значений по узлам дерева полностью определяется исходной последовательностью данных.

Теперь рассмотрим программу реализации этого алгоритма на Си. Данными в узлах дерева являются целые числа, которые вводятся с клавиатуры в ходе диалога. Для показа результата построения дерева в программу включена функция обхода узлов дерева, которая выводит данные в узлах на экран.

Пример.


/* ИДЕАЛЬНО СБАЛАНСИРОВАННОЕ БИНАРНОЕ ДЕРЕВО */


#include
#include
#include
typedef struct RECORD    /* Структура элемента дерева */
{ int DATA;          /* данные узла — здесь только ключ */
RECORD *LPTR,*RPTR;    /* левый и правый указатели на поддерево*/
};
RECORD *ROOT;    /* Указатель корня дерева */
static int ndi=0;
/*последовательный номер включаемого элемента ,
удобства работы пользователя и контроля наличия дерева. Перед
каждым обращением к функциям tree, preorder в вызывающей функции
переменную ndi нужно обнулять. */


RECORD* tree(int k);         /* функция создания дерева, к - число узлов*/
int preorder(RECORD *)           ;      /* функция нисходящего обхода дерева*/
void p(RECORD*);   /* Печать данных в узле */
void lnData(RECORD*);   /* Ввод данных узла*/
/* ===============================================9
/* ГЛАВНАЯ ФУНКЦИЯ */
main()
{int i,n;
printf("\n\n РАБОТА С ИДЕАЛЬНО СБАЛАНСИРОВАННЫМ БИНАРНЫМ ДЕРЕВОМ");
printf("\n Создание дерева");
printf("\n Введите число узлов дерева =>");
scanf("%d",&n);
/* Создание идеально сбалансированного дерева */
ndi=O;
if( (ROOT=tree(n))==NULL)
      { printf("\n Дерево не создано");
         getch();          /* return -1; */
}
printf("\n Обход дерева с выводом данных в узлах");
printf("\n Нисходящий обход дерева:\n");
ndi=O;    preorder(ROOT); getch();
printf("\n Конец\n"); getch(); return 0;
}
/* ПОСТРОЕНИЕ БИНАРНОГО ИДЕАЛЬНО СБАЛАНСИРОВАННОГО ДЕРЕ-ВА*/
RECORD* tree(int k)
{ RECORD *newnode;
int nl,nr;
if (k≤0)                       /* k<0 - ошибочное задание параметра */
newnode =0;
   else
    { nl = k/2;
       alloc(1,sizeof(RECORD));
InData(newnode);
newnode.LPTR=tree(nl);
newnode.RPTR=tree(nr);

}
return newnode;
}


/* НИСХОДЯЩИЙ ОБХОД ДЕРЕВА */
int preorder(RECORD *T)
  { if(T==NULL && ndi==0)
     { printf("\n Дерево пустое");
getch(); return -1;
}
if (T!=0)
{ ndi++; p(T);       /* обработка данных в узле */
preorder(T.LPTR);
preorder(T.RPTR);
}
return 0;
}


//* ОБРАБОТКА ДАННЫХ УЗЛА ДЕРЕВА */
void p(RECORD *B)
{ printf(" %d ",B.DATA);
}
/* ВВОД ДАННЫХ УЗЛА ДЕРЕВА */
void lnData(RECORD* d)
   {         printf(“Введите %d-й ключ =>",++ndi);
              scanf("%d",&d.DATA);
}

    Функция tree возвращает указатель на корень построенного дерева, а при рекурсивном обращении — указатель на очередной дочерний узел.

Идеально сбалансированное бинарное дерево, построенное из последовательности ключей: 9,17,20,16,12,21,6,3,11,4,19,14,13,1,5,2,8,18,7,10,15, будет иметь следующий вид:

Рис. Идеально сбалансированное бинарное дерево

При таком построении, несмотря на то, что идеально сбалансированное дерево является упорядоченным в смысле порядка следования вершин на каждом уровне, никакие особые требования относительно значений данных в вершинах не накладываются, т.е. значения данных в вершинах в общем случае не упорядочены. Это ведет к тому, что поиск узла с нужными данными осуществляется последовательным обходом всех n узлов дерева, затраты на поиск будут порядка О(n). Поэтому такие «простые» сбалансированные деревья применяются редко. Обычно используются сбалансированные деревья поиска, которые обеспечивают минимальную длину поиска порядка O(log2n), где n — число узлов дерева.

Добавление и удаление узлов дерева вызывают определенные трудности. Чтобы поддерживать сбалансированность дерева при добавлении и удалении узлов, необходимо иметь информацию о сбалансированности каждого поддерева и определенными действиями поддерживать их сбалансированность. В силу этого идеально сбалансированные деревья поиска применяются для работы с данными, состав которых мало изменяется в процессе обработки.

[Оглавление] [<<страница] [>>страница] [В начало ]