Структура данных - двоичное дерево поиска

Дерево двоичного поиска (BST) - это дерево, в котором все узлы следуют следующим свойствам:

  • Значение ключа левого поддерева меньше, чем значение ключа его родительского (корневого) узла.

  • Значение ключа правого поддерева больше или равно значению ключа его родительского (корневого) узла.

Таким образом, BST делит все свои поддеревья на два сегмента; левое поддерево и правое поддерево и может быть определено как -

left_subtree (keys) < node (key) ≤ right_subtree (keys)

Представление

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

Ниже приводится графическое изображение BST -

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

Основные операции

Ниже приведены основные операции с деревом.

  • Search - Ищет элемент в дереве.

  • Insert - Вставляет элемент в дерево.

  • Pre-order Traversal - Обходит дерево по предварительному заказу.

  • In-order Traversal - Обходит дерево по порядку.

  • Post-order Traversal - Обходит дерево в режиме пост-заказа.

Узел

Определите узел, имеющий некоторые данные, ссылки на его левый и правый дочерние узлы.

struct node {
   int data;   
   struct node *leftChild;
   struct node *rightChild;
};

Поисковая операция

Каждый раз, когда нужно искать элемент, начинайте поиск с корневого узла. Затем, если данные меньше значения ключа, найдите элемент в левом поддереве. В противном случае ищите элемент в правом поддереве. Следуйте одному и тому же алгоритму для каждого узла.

Алгоритм

struct node* search(int data){
   struct node *current = root;
   printf("Visiting elements: ");
	
   while(current->data != data){
	
      if(current != NULL) {
         printf("%d ",current->data);
			
         //go to left tree
         if(current->data > data){
            current = current->leftChild;
         }  //else go to right tree
         else {                
            current = current->rightChild;
         }
			
         //not found
         if(current == NULL){
            return NULL;
         }
      }			
   }
   
   return current;
}

Вставить операцию

Каждый раз, когда нужно вставить элемент, сначала найдите его правильное местоположение. Начните поиск с корневого узла, затем, если данные меньше значения ключа, найдите пустое место в левом поддереве и вставьте данные. В противном случае найдите пустое место в правом поддереве и вставьте данные.

Алгоритм

void insert(int data) {
   struct node *tempNode = (struct node*) malloc(sizeof(struct node));
   struct node *current;
   struct node *parent;

   tempNode->data = data;
   tempNode->leftChild = NULL;
   tempNode->rightChild = NULL;

   //if tree is empty
   if(root == NULL) {
      root = tempNode;
   } else {
      current = root;
      parent = NULL;

      while(1) {                
         parent = current;
			
         //go to left of the tree
         if(data < parent->data) {
            current = current->leftChild;                
            //insert to the left
				
            if(current == NULL) {
               parent->leftChild = tempNode;
               return;
            }
         }  //go to right of the tree
         else {
            current = current->rightChild;
            
            //insert to the right
            if(current == NULL) {
               parent->rightChild = tempNode;
               return;
            }
         }
      }            
   }
}