Бінарне дерево це нелінійна структура даних де кожен вузол має не більше двох дітей. У цій статті ми розглянемо всі основи бінарного дерева, операції з бінарним деревом, його реалізацію, переваги та недоліки, що допоможе вам вирішити всі проблеми на основі бінарного дерева.
Зміст
- Що таке бінарне дерево?
- Представлення двійкового дерева
- Типи бінарного дерева
- Операції над бінарним деревом
- Допоміжні операції над бінарним деревом
- Реалізація бінарного дерева
- Аналіз складності операцій з бінарним деревом
- Переваги бінарного дерева
- Недоліки бінарного дерева
- Застосування бінарного дерева
- Часті запитання щодо бінарного дерева
Що таке бінарне дерево?
Двійкове дерево - це a структура даних дерева (нелінійна) в якому кожен вузол може мати не більше двох дітей які називаються ліва дитина і права дитина .
Найвищий вузол у бінарному дереві називається корінь , а самі нижні вузли називаються листя . Бінарне дерево можна візуалізувати як ієрархічну структуру з коренем у верхній частині та листям унизу.
Представлення двійкового дерева
Кожен вузол у бінарному дереві складається з трьох частин:
- Дані
- Покажчик на ліву дитину
- Вказівник на праву дитину
змінна bash
Нижче наведено представлення вузла бінарного дерева різними мовами:
C++ // Use any below method to implement Nodes of tree // Method 1: Using 'struct' to make // user-define data type struct node { int data; struct node* left; struct node* right; }; // Method 2: Using 'class' to make // user-define data type class Node { public: int data; Node* left; Node* right; };> C // Structure of each node of the tree struct node { int data; struct node* left; struct node* right; };> Java // Class containing left and right child // of current node and key value class Node { int key; Node left, right; public Node(int item) { key = item; left = right = null; } }> Python # A Python class that represents # an individual node in a Binary Tree class Node: def __init__(self, key): self.left = None self.right = None self.val = key>
C# // Class containing left and right child // of current node and key value class Node { int key; Node left, right; public Node(int item) { key = item; left = right = null; } }> JavaScript >
Типи бінарного дерева
Двійкове дерево можна класифікувати на кілька типів на основі кількох факторів:
- На основі кількості дітей
- Повне бінарне дерево
- Вироджене бінарне дерево
- Перекошені бінарні дерева
- На основі завершення рівнів
- Повне бінарне дерево
- Ідеальне бінарне дерево
- Збалансоване бінарне дерево
- На основі значень вузла:
- Двійкове дерево пошуку
- Дерево AVL
- Червоне чорне дерево
- B Дерево
- B+ Дерево
- Дерево сегментів
Операції над бінарним деревом
1. Вставка в бінарне дерево
Ми можемо вставити вузол у будь-яке місце у бінарному дереві, вставивши вузол як лівий або правий дочірній елемент будь-якого вузла або зробивши вузол коренем дерева.
Алгоритм вставки вузла в бінарне дерево:
- Перевірте, чи є вузол у бінарному дереві, у якому відсутній лівий дочірній елемент. Якщо такий вузол існує, вставте новий вузол як його лівий дочірній елемент.
- Перевірте, чи є вузол у бінарному дереві, у якому відсутній правий дочірній елемент. Якщо такий вузол існує, вставте новий вузол як його правий дочірній елемент.
- Якщо ми не знайдемо жодного вузла з відсутнім лівим чи правим дочірнім елементом, тоді знайдіть вузол, у якому відсутні обидва дочірні елементи, і вставте цей вузол як його лівий чи правий дочірній елемент.
2. Обхід бінарного дерева
Обхід бінарного дерева передбачає відвідування всіх вузлів бінарного дерева. Алгоритми обходу дерева можна розділити на дві категорії:
- Алгоритми пошуку в глибину (DFS).
- Алгоритми пошуку в ширину (BFS).
Алгоритми пошуку в глибину (DFS):
- Обхід попереднього замовлення (поточний-ліво-право): Відвідайте поточний вузол перед відвідуванням будь-яких вузлів усередині лівого чи правого піддерева. Тут обхід корінь – лівий дочірній – правий дочірній. Це означає, що спочатку проходить кореневий вузол, потім його лівий дочірній вузол і, нарешті, правий дочірній вузол.
- Обхід порядку (зліва-потоку-право): Відвідайте поточний вузол після відвідування всіх вузлів усередині лівого піддерева, але перед відвідуванням будь-якого вузла в межах правого піддерева. Тут обхід лівий дочірній – корінь – правий дочірній. Це означає, що спочатку проходить лівий дочірній елемент, потім його кореневий вузол і, нарешті, правий дочірній вузол.
- Обхід після замовлення (зліва-право-потоку): Перейти до поточного вузла після відвідування всіх вузлів лівого та правого піддерева. Тут обхід лівий дочірній – правий дочірній – корінь. Це означає, що лівий дочірній елемент пройшов спочатку правий дочірній елемент і, нарешті, його кореневий вузол.
Алгоритми пошуку в ширину (BFS):
- Обхід порядку рівня: Відвідайте вузли рівень за рівнем і зліва направо на одному рівні. Тут обхід відбувається по рівнях. Це означає, що першим пройшов крайній лівий нащадок, а потім пройшли інші нащадки того самого рівня зліва направо.
3. Видалення в бінарному дереві
Ми можемо видалити будь-який вузол у бінарному дереві та змінити порядок вузлів після видалення, щоб знову сформувати дійсне двійкове дерево.
ініціалізація списку python
Алгоритм видалення вузла в бінарному дереві:
- Починаючи з кореня, знайдіть найглибший і правий вузол у бінарному дереві та вузол, який ми хочемо видалити.
- Замініть дані найглибшого правого вузла вузлом, який потрібно видалити.
- Потім видаліть найглибший правий вузол.
4. Пошук у бінарному дереві
Ми можемо шукати елемент у вузлі, використовуючи будь-яку техніку обходу.
Алгоритм пошуку вузла у бінарному дереві:
- Почніть з кореневого вузла.
- Перевірте, чи поточне значення вузла дорівнює цільовому значенню.
- Якщо значення поточного вузла дорівнює цільовому значенню, то цей вузол є необхідним вузлом.
- В іншому випадку, якщо значення вузла не дорівнює цільовому значенню, почніть пошук у лівому та правому дочірніх елементах.
- Якщо ми не знайдемо жодного вузла, значення якого дорівнює цільовому, це значення не присутнє в дереві.
Допоміжні операції над бінарним деревом
- Знаходження висоти дерева
- Знайдіть рівень вузла у двійковому дереві
- Знаходження розміру всього дерева
Реалізація бінарного дерева
Нижче наведено код для вставки, видалення та обходу бінарного дерева:
C #include // Node structure to define the structure of the node typedef struct Node { int data; struct Node *left, *right; } Node; // Function to create a new node Node* newNode(int val) { Node* temp = (Node*)malloc(sizeof(Node)); temp->дані = значення; temp->left = temp->right = NULL; зворотна температура; } // Функція для вставки вузлів Node* insert(Node* root, int data) { // Якщо дерево порожнє, новий вузол стає коренем if (root == NULL) { root = newNode(data); повернути корінь; } // Черга для обходу дерева та пошуку позиції для вставки вузла Node* queue[100]; int front = 0, rear = 0; queue[rear++] = корінь; while (front != rear) { Node* temp = queue[front++]; // Вставити вузол як лівий дочірній елемент батьківського вузла if (temp->left == NULL) { temp->left = newNode(data); перерва; } // Якщо лівий дочірній елемент не є нульовим, надішліть його до черги else queue[rear++] = temp->left; // Вставити вузол як правий дочірній елемент батьківського вузла if (temp->right == NULL) { temp->right = newNode(data); перерва; } // Якщо правий дочірній елемент не нульовий, надішліть його до черги else queue[rear++] = temp->right; } повернути корінь; } /* Функція видалення заданого найглибшого вузла (d_node) у бінарному дереві */ void deletDeepest(Node* root, Node* d_node) { Node* queue[100]; int front = 0, rear = 0; queue[rear++] = корінь; // Виконати обхід порядку рівня до останнього вузла Node* temp; while (front != rear) { temp = queue[front++]; if (temp == d_node) { temp = NULL; вільний (d_node); повернення; } if (temp->right) { if (temp->right == d_node) { temp->right = NULL; вільний (d_node); повернення; } else queue[rear++] = temp->right; } if (temp->left) { if (temp->left == d_node) { temp->left = NULL; вільний (d_node); повернення; } else queue[rear++] = temp->left; } } } /* Функція видалення елемента у бінарному дереві */ Node* deletion(Node* root, int key) { if (!root) return NULL; if (root->left == NULL && root->right == NULL) { if (root->data == key) return NULL; інакше повернути корінь; } Node* queue[100]; int front = 0, rear = 0; queue[rear++] = корінь; Node* temp; Node* key_node = NULL; // Виконайте обхід порядку рівня, щоб знайти найглибший вузол (temp) і вузол, який потрібно видалити (key_node) while (front != rear) { temp = queue[front++]; if (temp->data == ключ) key_node = temp; if (temp->left) queue[rear++] = temp->left; if (temp->right) queue[rear++] = temp->right; } if (key_node != NULL) { int x = temp->data; key_node->data = x; deletDeepest(root, temp); } повернути корінь; } // Обхід дерева за порядком (ліворуч – корінь – праворуч) void inorderTraversal(Node* root) { if (!root) return; inorderTraversal(корінь->ліворуч); printf('%d ', корінь->дані); inorderTraversal(root->right); } // Попередній обхід дерева (корінь - ліворуч - праворуч) void preorderTraversal(Node* root) { if (!root) return; printf('%d ', корінь->дані); preorderTraversal(root->left); preorderTraversal(root->right); } // Обхід дерева Postorder (Ліворуч - Праворуч - Корінь) void postorderTraversal(Node* root) { if (root == NULL) return; postorderTraversal(корінь->ліворуч); postorderTraversal(корінь->справа); printf('%d ', корінь->дані); } // Функція для обходу дерева порядку рівня void levelorderTraversal(Node* root) { if (root == NULL) return; // Черга для проходження порядку рівня Node* queue[100]; int front = 0, rear = 0; queue[rear++] = корінь; while (front != rear) { Node* temp = queue[front++]; printf('%d ', temp->data); // Проштовхнути лівого дочірнього елемента в чергу if (temp->left) queue[rear++] = temp->left; // Проштовхнути правий дочірній елемент у чергу if (temp->right) queue[rear++] = temp->right; } } /* Функція драйвера для перевірки наведеного вище алгоритму. */ int main() { Node* root = NULL; // Вставка вузлів root = insert(root, 10); корінь = вставити (корінь, 20); корінь = вставити (корінь, 30); корінь = вставка (корінь, 40); printf('Обхід попереднього порядку: '); preorderTraversal(корінь); printf('
Обхід у порядку: '); inorderTraversal(корінь); printf('
Обхід після замовлення: '); postorderTraversal(корінь); printf('
Обхід порядку рівня: '); levelorderTraversal(корінь); // Видалення вузла з даними = 20 root = deletion(root, 20); printf('
Обхід у порядку після видалення: '); inorderTraversal(корінь); повернути 0; }> Java import java.util.LinkedList; import java.util.Queue; // Node class to define the structure of the node class Node { int data; Node left, right; // Parameterized Constructor Node(int val) { data = val; left = right = null; } } public class BinaryTree { // Function to insert nodes public static Node insert(Node root, int data) { // If tree is empty, new node becomes the root if (root == null) { root = new Node(data); return root; } // Queue to traverse the tree and find the position to // insert the node Queueq = новий LinkedList(); q.offer(корінь); while (!q.isEmpty()) { Node temp = q.poll(); // Вставити вузол як лівий дочірній елемент батьківського вузла if (temp.left == null) { temp.left = new Node(data); перерва; } // Якщо лівий дочірній елемент не має значення null, надішліть його // до черги else q.offer(temp.left); // Вставити вузол як правий дочірній елемент батьківського вузла if (temp.right == null) { temp.right = new Node(data); перерва; } // Якщо правий дочірній елемент не є null, надішліть його // до черги else q.offer(temp.right); } повернути корінь; } /* функція видалення заданого найглибшого вузла (d_node) у бінарному дереві */ public static void deletDeepest(Node root, Node d_node) { Queueq = новий LinkedList(); q.offer(корінь); // Виконати обхід порядку рівня до останнього вузла Node temp; while (!q.isEmpty()) { temp = q.poll(); if (temp == d_node) { temp = null; d_node = нуль; повернення; } if (temp.right != null) { if (temp.right == d_node) { temp.right = null; d_node = нуль; повернення; } else q.offer(temp.right); } if (temp.left != null) { if (temp.left == d_node) { temp.left = null; d_node = нуль; повернення; } else q.offer(temp.left); } } } /* функція видалення елемента у бінарному дереві */ public static Node deletion(Node root, int key) { if (root == null) return null; if (root.left == null && root.right == null) { if (root.data == ключ) повертає null; інакше повернути корінь; } Чергаq = новий LinkedList(); q.offer(корінь); Node temp = новий вузол (0); Вузол key_node = null; // Виконайте обхід порядку рівня, щоб знайти // найглибший вузол (temp) і вузол, який потрібно видалити (key_node) while (!q.isEmpty()) { temp = q.poll(); if (temp.data == ключ) key_node = temp; if (temp.left != null) q.offer(temp.left); if (temp.right != null) q.offer(temp.right); } if (key_node != null) { int x = temp.data; key_node.data = x; deletDeepest(root, temp); } повернути корінь; } // Обхід дерева за порядком (Ліворуч - Корінь - Праворуч) public static void inorderTraversal(Node root) { if (root == null) return; inorderTraversal(root.left); System.out.print(root.data + ' '); inorderTraversal(root.right); } // Попередній обхід дерева (корінь - ліворуч - праворуч) public static void preorderTraversal(Node root) { if (root == null) return; System.out.print(root.data + ' '); preorderTraversal(root.left); preorderTraversal(root.right); } // Обхід дерева постпорядку (Ліворуч - Праворуч - Корінь) public static void postorderTraversal(Node root) { if (root == null) return; postorderTraversal(root.left); postorderTraversal(root.right); System.out.print(root.data + ' '); } // Функція для обходу дерева порядку рівня public static void levelorderTraversal(Node root) { if (root == null) return; // Черга для проходження порядку рівня Чергаq = новий LinkedList(); q.offer(корінь); while (!q.isEmpty()) { Node temp = q.poll(); System.out.print(temp.data + ' '); // Проштовхнути лівого дочірнього елемента в чергу if (temp.left != null) q.offer(temp.left); // Проштовхнути правий дочірній елемент у чергу if (temp.right != null) q.offer(temp.right); } } /* Функція драйвера для перевірки наведеного вище алгоритму. */ public static void main(String[] args) { Node root = null; // Вставка вузлів root = insert(root, 10); корінь = вставити (корінь, 20); корінь = вставити (корінь, 30); корінь = вставка (корінь, 40); System.out.print('Обхід попереднього замовлення: '); preorderTraversal(корінь); System.out.print('
Обхід у порядку: '); inorderTraversal(корінь); System.out.print('
Обхід після замовлення: '); postorderTraversal(корінь); System.out.print('
Обхід порядку рівня: '); levelorderTraversal(корінь); // Видалення вузла з даними = 20 root = deletion(root, 20); System.out.print('
Обхід у порядку після видалення: '); inorderTraversal(корінь); } }> Python from collections import deque # Node class to define the structure of the node class Node: def __init__(self, val): self.data = val self.left = self.right = None # Function to insert nodes def insert(root, data): # If tree is empty, new node becomes the root if root is None: root = Node(data) return root # Queue to traverse the tree and find the position to insert the node q = deque() q.append(root) while q: temp = q.popleft() # Insert node as the left child of the parent node if temp.left is None: temp.left = Node(data) break # If the left child is not null push it to the queue else: q.append(temp.left) # Insert node as the right child of parent node if temp.right is None: temp.right = Node(data) break # If the right child is not null push it to the queue else: q.append(temp.right) return root # Function to delete the given deepest node (d_node) in binary tree def deletDeepest(root, d_node): q = deque() q.append(root) # Do level order traversal until last node while q: temp = q.popleft() if temp == d_node: temp = None del d_node return if temp.right: if temp.right == d_node: temp.right = None del d_node return else: q.append(temp.right) if temp.left: if temp.left == d_node: temp.left = None del d_node return else: q.append(temp.left) # Function to delete element in binary tree def deletion(root, key): if not root: return None if root.left is None and root.right is None: if root.data == key: return None else: return root q = deque() q.append(root) temp = None key_node = None # Do level order traversal to find deepest node (temp) and node to be deleted (key_node) while q: temp = q.popleft() if temp.data == key: key_node = temp if temp.left: q.append(temp.left) if temp.right: q.append(temp.right) if key_node is not None: x = temp.data key_node.data = x deletDeepest(root, temp) return root # Inorder tree traversal (Left - Root - Right) def inorderTraversal(root): if not root: return inorderTraversal(root.left) print(root.data, end=' ') inorderTraversal(root.right) # Preorder tree traversal (Root - Left - Right) def preorderTraversal(root): if not root: return print(root.data, end=' ') preorderTraversal(root.left) preorderTraversal(root.right) # Postorder tree traversal (Left - Right - Root) def postorderTraversal(root): if root is None: return postorderTraversal(root.left) postorderTraversal(root.right) print(root.data, end=' ') # Function for Level order tree traversal def levelorderTraversal(root): if root is None: return # Queue for level order traversal q = deque() q.append(root) while q: temp = q.popleft() print(temp.data, end=' ') # Push left child in the queue if temp.left: q.append(temp.left) # Push right child in the queue if temp.right: q.append(temp.right) # Driver function to check the above algorithm if __name__ == '__main__': root = None # Insertion of nodes root = insert(root, 10) root = insert(root, 20) root = insert(root, 30) root = insert(root, 40) print('Preorder traversal:', end=' ') preorderTraversal(root) print('
Inorder traversal:', end=' ') inorderTraversal(root) print('
Postorder traversal:', end=' ') postorderTraversal(root) print('
Level order traversal:', end=' ') levelorderTraversal(root) # Delete the node with data = 20 root = deletion(root, 20) print('
Inorder traversal after deletion:', end=' ') inorderTraversal(root)> C# using System; using System.Collections.Generic; // Node class to define the structure of the node public class Node { public int data; public Node left, right; // Parameterized Constructor public Node(int val) { data = val; left = right = null; } } public class Program { // Function to insert nodes public static Node Insert(Node root, int data) { // If tree is empty, new node becomes the root if (root == null) { root = new Node(data); return root; } // Queue to traverse the tree and find the position to insert the node Queueq = нова черга(); q.Enqueue(корінь); while (q.Count != 0) { Node temp = q.Dequeue(); // Вставити вузол як лівий дочірній елемент батьківського вузла if (temp.left == null) { temp.left = new Node(data); перерва; } // Якщо лівий дочірній елемент не є нульовим, помістіть його до черги else q.Enqueue(temp.left); // Вставити вузол як правий дочірній елемент батьківського вузла if (temp.right == null) { temp.right = new Node(data); перерва; } // Якщо правий дочірній елемент не є нульовим, надішліть його до черги else q.Enqueue(temp.right); } повернути корінь; } /* функція видалення заданого найглибшого вузла (d_node) у бінарному дереві */ public static void DeleteDeepest(Node root, Node d_node) { Queueq = нова черга(); q.Enqueue(корінь); // Виконати обхід порядку рівня до останнього вузла Node temp; while (q.Count != 0) { temp = q.Dequeue(); if (temp == d_node) { temp = null; d_node = нуль; повернення; } if (temp.right != null) { if (temp.right == d_node) { temp.right = null; d_node = нуль; повернення; } else q.Enqueue(temp.right); } if (temp.left != null) { if (temp.left == d_node) { temp.left = null; d_node = нуль; повернення; } else q.Enqueue(temp.left); } } } /* функція видалення елемента у бінарному дереві */ public static Node Deletion(Node root, int key) { if (root == null) return null; if (root.left == null && root.right == null) { if (root.data == ключ) повертає null; інакше повернути корінь; } Чергаq = нова черга(); q.Enqueue(корінь); Node temp = новий вузол (0); Вузол key_node = null; // Виконайте обхід порядку рівня, щоб знайти найглибший вузол (temp) і вузол, який потрібно видалити (key_node) while (q.Count != 0) { temp = q.Dequeue(); if (temp.data == ключ) key_node = temp; if (temp.left != null) q.Enqueue(temp.left); if (temp.right != null) q.Enqueue(temp.right); } if (key_node != null) { int x = temp.data; key_node.data = x; DeleteDeepest(root, temp); } повернути корінь; } // Обхід дерева за порядком (Ліворуч - Корінь - Праворуч) public static void InorderTraversal(Node root) { if (root == null) return; InorderTraversal(root.left); Console.Write(root.data + ' '); InorderTraversal(root.right); } // Попередній обхід дерева (корінь - ліворуч - праворуч) public static void PreorderTraversal(Node root) { if (root == null) return; Console.Write(root.data + ' '); PreorderTraversal(root.left); PreorderTraversal(root.right); } // Обхід дерева постпорядку (Ліворуч - Праворуч - Корінь) public static void PostorderTraversal(Node root) { if (root == null) return; PostorderTraversal(root.left); PostorderTraversal(root.right); Console.Write(root.data + ' '); } // Функція для обходу дерева порядку рівня public static void LevelorderTraversal(Node root) { if (root == null) return; // Черга для проходження порядку рівня Чергаq = нова черга(); q.Enqueue(корінь); while (q.Count != 0) { Node temp = q.Dequeue(); Console.Write(temp.data + ' '); // Проштовхнути лівого дочірнього елемента в чергу if (temp.left != null) q.Enqueue(temp.left); // Проштовхнути правий дочірній елемент у чергу if (temp.right != null) q.Enqueue(temp.right); } } /* Функція драйвера для перевірки наведеного вище алгоритму. */ public static void Main(string[] args) { Node root = null; // Вставка вузлів root = Insert(root, 10); корінь = Вставити (корінь, 20); корінь = Вставити (корінь, 30); корінь = Вставити (корінь, 40); Console.Write('Обхід попереднього замовлення: '); PreorderTraversal(корінь); Console.Write('
Обхід у порядку: '); InorderTraversal(корінь); Console.Write('
Обхід постордера: '); PostorderTraversal(корінь); Console.Write('
Обхід порядку рівня: '); LevelorderTraversal(корінь); // Видалення вузла з даними = 20 root = Deletion(root, 20); Console.Write('
Обхід у порядку після видалення: '); InorderTraversal(корінь); } }> Javascript // Node class to define the structure of the node class Node { constructor(val) { this.data = val; this.left = null; this.right = null; } } // Function to insert nodes function insert(root, data) { // If tree is empty, new node becomes the root if (root === null) { root = new Node(data); return root; } // queue to traverse the tree and find the position to // insert the node const q = []; q.push(root); while (q.length !== 0) { const temp = q.shift(); // Insert node as the left child of the parent node if (temp.left === null) { temp.left = new Node(data); break; } // If the left child is not null push it to the // queue else q.push(temp.left); // Insert node as the right child of parent node if (temp.right === null) { temp.right = new Node(data); break; } // If the right child is not null push it to the // queue else q.push(temp.right); } return root; } /* function to delete the given deepest node (d_node) in binary tree */ function deletDeepest(root, d_node) { const q = []; q.push(root); // Do level order traversal until last node let temp; while (q.length !== 0) { temp = q.shift(); if (temp === d_node) { temp = null; delete d_node; return; } if (temp.right) { if (temp.right === d_node) { temp.right = null; delete d_node; return; } else q.push(temp.right); } if (temp.left) { if (temp.left === d_node) { temp.left = null; delete d_node; return; } else q.push(temp.left); } } } /* function to delete element in binary tree */ function deletion(root, key) { if (!root) return null; if (root.left === null && root.right === null) { if (root.data === key) return null; else return root; } const q = []; q.push(root); let temp; let key_node = null; // Do level order traversal to find deepest // node(temp) and node to be deleted (key_node) while (q.length !== 0) { temp = q.shift(); if (temp.data === key) key_node = temp; if (temp.left) q.push(temp.left); if (temp.right) q.push(temp.right); } if (key_node !== null) { const x = temp.data; key_node.data = x; deletDeepest(root, temp); } return root; } // Inorder tree traversal (Left - Root - Right) function inorderTraversal(root) { if (!root) return; inorderTraversal(root.left); console.log(root.data + ' '); inorderTraversal(root.right); } // Preorder tree traversal (Root - Left - Right) function preorderTraversal(root) { if (!root) return; console.log(root.data + ' '); preorderTraversal(root.left); preorderTraversal(root.right); } // Postorder tree traversal (Left - Right - Root) function postorderTraversal(root) { if (root === null) return; postorderTraversal(root.left); postorderTraversal(root.right); console.log(root.data + ' '); } // Function for Level order tree traversal function levelorderTraversal(root) { if (root === null) return; // Queue for level order traversal const q = []; q.push(root); while (q.length !== 0) { const temp = q.shift(); console.log(temp.data + ' '); // Push left child in the queue if (temp.left) q.push(temp.left); // Push right child in the queue if (temp.right) q.push(temp.right); } } /* Driver function to check the above algorithm. */ let root = null; // Insertion of nodes root = insert(root, 10); root = insert(root, 20); root = insert(root, 30); root = insert(root, 40); console.log('Preorder traversal: '); preorderTraversal(root); console.log('
Inorder traversal: '); inorderTraversal(root); console.log('
Postorder traversal: '); postorderTraversal(root); console.log('
Level order traversal: '); levelorderTraversal(root); // Delete the node with data = 20 root = deletion(root, 20); console.log('
Inorder traversal after deletion: '); inorderTraversal(root);> C++14 #include using namespace std; // Node class to define the structure of the node class Node { public: int data; Node *left, *right; // Parameterized Constructor Node(int val) { data = val; left = right = NULL; } }; // Function to insert nodes Node* insert(Node* root, int data) { // If tree is empty, new node becomes the root if (root == NULL) { root = new Node(data); return root; } // queue to traverse the tree and find the position to // insert the node queueq; q.push(корінь); while (!q.empty()) { Node* temp = q.front(); q.pop(); // Вставити вузол як лівий дочірній елемент батьківського вузла if (temp->left == NULL) { temp->left = new Node(data); перерва; } // Якщо лівий дочірній елемент не є null, надішліть його // до черги else q.push(temp->left); // Вставити вузол як правий дочірній елемент батьківського вузла if (temp->right == NULL) { temp->right = new Node(data); перерва; } // Якщо правий дочірній елемент не є null, надішліть його // до черги else q.push(temp->right); } повернути корінь; } /* функція видалення заданого найглибшого вузла (d_node) у бінарному дереві */ void deletDeepest(Node* root, Node* d_node) { queueq; q.push(корінь); // Виконати обхід порядку рівня до останнього вузла Node* temp; while (!q.empty()) { temp = q.front(); q.pop(); if (temp == d_node) { temp = NULL; видалити (d_node); повернення; } if (temp->right) { if (temp->right == d_node) { temp->right = NULL; видалити (d_node); повернення; } else q.push(temp->right); } if (temp->left) { if (temp->left == d_node) { temp->left = NULL; видалити (d_node); повернення; } else q.push(temp->left); } } } /* функція для видалення елемента в бінарному дереві */ Node* deletion(Node* root, int key) { if (!root) return NULL; if (root->left == NULL && root->right == NULL) { if (root->data == key) return NULL; інакше повернути корінь; } чергаq; q.push(корінь); Node* temp; Node* key_node = NULL; // Виконайте обхід порядку рівня, щоб знайти // найглибший вузол (temp) і вузол, який потрібно видалити (key_node) while (!q.empty()) { temp = q.front(); q.pop(); if (temp->data == ключ) key_node = temp; if (temp->left) q.push(temp->left); if (temp->right) q.push(temp->right); } if (key_node != NULL) { int x = temp->data; key_node->data = x; deletDeepest(root, temp); } повернути корінь; } // Обхід дерева за порядком (ліворуч - корінь - праворуч) void inorderTraversal(Node* root) { if (!root) return; inorderTraversal(корінь->ліворуч); cout<< root->даних<< ' '; inorderTraversal(root->праворуч); } // Попередній обхід дерева (корінь - ліворуч - праворуч) void preorderTraversal(Node* root) { if (!root) return; cout<< root->даних<< ' '; preorderTraversal(root->ліворуч); preorderTraversal(root->right); } // Обхід дерева Postorder (Ліворуч - Праворуч - Корінь) void postorderTraversal(Node* root) { if (root == NULL) return; postorderTraversal(корінь->ліворуч); postorderTraversal(root->right); cout<< root->даних<< ' '; } // Function for Level order tree traversal void levelorderTraversal(Node* root) { if (root == NULL) return; // Queue for level order traversal queueq; q.push(корінь); while (!q.empty()) { Node* temp = q.front(); q.pop(); cout<< temp->даних<< ' '; // Push left child in the queue if (temp->вліво) q.push(temp->left); // Переміщення правого дочірнього елемента в чергу if (temp->right) q.push(temp->right); } } /* Функція драйвера для перевірки наведеного вище алгоритму. */ int main() { Node* root = NULL; // Вставка вузлів root = insert(root, 10); корінь = вставити (корінь, 20); корінь = вставити (корінь, 30); корінь = вставка (корінь, 40); cout<< 'Preorder traversal: '; preorderTraversal(root); cout << '
Inorder traversal: '; inorderTraversal(root); cout << '
Postorder traversal: '; postorderTraversal(root); cout << '
Level order traversal: '; levelorderTraversal(root); // Delete the node with data = 20 root = deletion(root, 20); cout << '
Inorder traversal after deletion: '; inorderTraversal(root); }> Вихід
Preorder traversal: 10 20 40 30 Inorder traversal: 40 20 10 30 Postorder traversal: 40 20 30 10 Level order traversal: 10 20 30 40 Inorder traversal after deletion: 40 10 30>
Аналіз складності операцій з бінарним деревом
| Операції | Часова складність | Космічна складність arp - команда |
|---|---|---|
| Вставка | O(N) | O(N) |
| Обхід попереднього замовлення | O(N) | O(N) |
Обхід порядку | O(N) | O(N) |
| Обхід поштових переказів | O(N) | O(N) |
| Обхід порядку рівня | O(N) | O(N) |
Видалення зворотний рядок у java | O(N) | O(N) |
Пошук | O(N) | O(N) |
Ми можемо використовувати Морріс Траверсал щоб обійти всі вузли бінарного дерева за час O(1).
Переваги бінарного дерева
- Ефективний пошук: Бінарні дерева ефективні під час пошуку певного елемента, оскільки кожен вузол має не більше двох дочірніх вузлів, що дозволяє Ефективна пам'ять: Двійкові дерева потребують менше пам’яті порівняно з іншими структурами даних дерева, тому вони ефективні з використанням пам’яті.
- Бінарні дерева відносно легко реалізувати та зрозуміти, оскільки кожен вузол має не більше двох дочірніх елементів, ліву та праву.
Недоліки бінарного дерева
- Обмежена структура: Двійкові дерева обмежені двома дочірніми вузлами на вузол, що може обмежити їхню корисність у певних програмах. Наприклад, якщо дерево вимагає більше двох дочірніх вузлів на вузол, інша структура дерева може бути більш підходящою.
- Незбалансовані дерева: Незбалансовані двійкові дерева, де одне піддерево значно більше за інше, можуть призвести до неефективних операцій пошуку. Це може статися, якщо дерево неправильно збалансоване або якщо дані вставляються в невипадковому порядку.
- Неефективність простору: Бінарні дерева можуть бути неефективними у порівнянні з іншими структурами даних. Це пов’язано з тим, що кожен вузол потребує двох дочірніх покажчиків, що може бути значним обсягом пам’яті для великих дерев.
- Повільна продуктивність у найгірших сценаріях: У гіршому випадку бінарне дерево може стати виродженим або перекошеним, що означає, що кожен вузол має лише одного дочірнього елемента. У цьому випадку пошукові операції можуть знизитися до O(n) часової складності, де n – кількість вузлів у дереві.
Застосування двійкового дерева
- Двійкове дерево можна використовувати для представляють ієрархічні дані .
- Дерева кодування Хаффмана використовуються в алгоритми стиснення даних .
- Пріоритетна черга це інше застосування бінарного дерева, яке використовується для пошуку максимальної або мінімальної складності часу O(1).
- Корисно для сегментованого індексування в базі даних, корисно для зберігання кешу в системі,
- Бінарні дерева можна використовувати для впровадження дерев рішень, типу алгоритму машинного навчання, який використовується для класифікації та регресійного аналізу.
Часті запитання щодо бінарного дерева
1. Що таке бінарне дерево?
Двійкове дерево — це нелінійна структура даних, що складається з вузлів, де кожен вузол має не більше двох дочірніх елементів (лівий і правий дочірній).
2. Які бувають типи бінарних дерев?
Бінарні дерева можна класифікувати на різні типи, включаючи повні бінарні дерева, повні бінарні дерева, ідеальні бінарні дерева, збалансовані бінарні дерева (такі як дерева AVL і червоно-чорні дерева) і вироджені (або патологічні) бінарні дерева.
3. Що таке висота бінарного дерева?
Висота бінарного дерева - це довжина найдовшого шляху від кореневого вузла до листкового вузла. Він представляє кількість ребер на найдовшому шляху від кореневого вузла до кінцевого вузла.
лінійний пошук в java
4. Яка глибина вузла у бінарному дереві?
Глибина вузла у бінарному дереві — це довжина шляху від кореневого вузла до цього конкретного вузла. Глибина кореневого вузла дорівнює 0.
5. Як виконати обхід дерева у бінарному дереві?
Обхід дерева у двійковому дереві можна виконати різними способами: обхід у порядку, обхід попереднього замовлення, обхід після замовлення та обхід за рівнем порядку (також відомий як обхід у ширину).
6. Що таке обхід порядку в бінарному дереві?
У Inorder обході вузли рекурсивно відвідуються в такому порядку: лівий дочірній, корінь, правий дочірній. Цей обхід призводить до того, що вузли відвідуються в порядку не спадання в бінарному дереві пошуку.
7. Що таке попередній обхід у бінарному дереві?
У попередньому обході вузли рекурсивно відвідуються в такому порядку: корінь, лівий дочірній, правий дочірній. Цей обхід призводить до того, що кореневий вузол є першим відвідуваним вузлом.
8. Що таке обхід Postorder у бінарному дереві?
У Postorder traversal вузли рекурсивно відвідуються в такому порядку: лівий дочірній, правий дочірній і корінь. Цей обхід призводить до того, що кореневий вузол є останнім відвідуваним вузлом.
9. Яка різниця між бінарним деревом і бінарним деревом пошуку?
Двійкове дерево — це ієрархічна структура даних, де кожен вузол має щонайбільше два дочірніх вузла, тоді як бінарне дерево пошуку — це тип бінарного дерева, у якому лівий дочірній елемент вузла містить значення, менші за значення вузла, а правий дочірній елемент містить значення більше, ніж значення вузла.
10. Що таке збалансоване бінарне дерево?
Збалансоване бінарне дерево — це бінарне дерево, у якому висота лівого та правого піддерев кожного вузла відрізняється щонайбільше на одиницю. Збалансовані дерева допомагають підтримувати ефективні операції, такі як пошук, вставка та видалення з часовими складностями, близькими до O(log n).
Висновок:
Дерево — це ієрархічна структура даних. Основне використання дерев включає підтримку ієрархічних даних, надання помірного доступу та операції вставки/видалення. Бінарні дерева — це окремі випадки дерева, де кожен вузол має не більше двох дочірніх елементів.
Пов'язані статті:
- Властивості бінарного дерева
- Типи бінарного дерева