Binární strom je nelineární datová struktura kde každý uzel má nejvýše dvě děti. V tomto článku pokryjeme všechny základy binárního stromu, operace s binárním stromem, jeho implementaci, výhody a nevýhody, které vám pomohou vyřešit všechny problémy založené na binárním stromu.
Obsah
- Co je binární strom?
- Reprezentace binárního stromu
- Typy binárních stromů
- Operace Na Binárním Stromu
- Pomocné Operace Na Binárním Stromu
- Implementace binárního stromu
- Analýza složitosti operací binárních stromů
- Výhody binárního stromu
- Nevýhody binárního stromu
- Aplikace binárního stromu
- Často kladené otázky o binárním stromu
Co je binární strom?
Binární strom je a stromová datová struktura (nelineární) ve kterém může mít každý uzel maximálně dvě děti které jsou označovány jako levé dítě a správné dítě .
Nejvyšší uzel v binárním stromě se nazývá vykořenit a jsou volány nejspodnější uzly listy . Binární strom lze zobrazit jako hierarchickou strukturu s kořenem nahoře a listy dole.
Reprezentace binárního stromu
Každý uzel v binárním stromu má tři části:
- Data
- Ukazatel na levé dítě
- Ukazatel na správné dítě
Níže je znázorněna reprezentace uzlu binárního stromu v různých jazycích:
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; };> Jáva // 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; } }> Krajta # 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 >
Typy binárních stromů
Binární strom lze klasifikovat do několika typů na základě více faktorů:
- Na základě Počet dětí
- Úplný binární strom
- Degenerovaný binární strom
- Zkosené binární stromy
- Na základě Dokončení úrovní
- Kompletní binární strom
- Perfektní binární strom
- Vyvážený binární strom
- Na základě hodnot uzlů:
- Binární vyhledávací strom
- Strom AVL
- Červený černý strom
- B strom
- B+ strom
- Segmentový strom
Operace Na Binárním Stromu
1. Vložení do binárního stromu
Uzel můžeme vložit kamkoli do binárního stromu vložením uzlu jako levého nebo pravého potomka libovolného uzlu nebo tím, že uzel učiníme kořenem stromu.
Algoritmus pro vložení uzlu do binárního stromu:
- Zkontrolujte, zda je v binárním stromu uzel, kterému chybí levé potomky. Pokud takový uzel existuje, vložte nový uzel jako jeho levého potomka.
- Zkontrolujte, zda je v binárním stromu uzel, kterému chybí pravé potomstvo. Pokud takový uzel existuje, vložte nový uzel jako jeho pravý potomek.
- Pokud nenajdeme žádný uzel s chybějícím levým nebo pravým potomkem, pak najděte uzel, ve kterém chybí oba potomci, a vložte uzel jako jeho levé nebo pravé potomky.
2. Procházení binárního stromu
Procházení binárního stromu zahrnuje návštěvu všech uzlů binárního stromu. Algoritmy procházení stromů lze obecně rozdělit do dvou kategorií:
- Algoritmy hloubkového vyhledávání (DFS).
- Algoritmy BFS (Breadth-First Search).
Algoritmy hloubkového vyhledávání (DFS):
- Předobjednávka Traversal (aktuální-levá-pravá): Než navštívíte jakýkoli uzel v levém nebo pravém podstromu, navštivte aktuální uzel. Zde je přechod kořen – levé dítě – pravé dítě. To znamená, že nejprve projde kořenový uzel, poté jeho levý potomek a nakonec pravý potomek.
- Průjezd v pořadí (levý-proud-pravý): Navštivte aktuální uzel po návštěvě všech uzlů v levém podstromu, ale před návštěvou jakéhokoli uzlu v pravém podstromu. Zde je přechodem levé dítě – kořen – pravé dítě. To znamená, že nejprve prochází levé dítě, potom jeho kořenový uzel a nakonec pravé dítě.
- Postorder Traversal (levo-pravý-proud): Po návštěvě všech uzlů levého a pravého podstromu navštivte aktuální uzel. Zde je přechodem levé dítě – pravé dítě – kořen. To znamená, že nejprve prošlo levé dítě, poté pravé dítě a nakonec jeho kořenový uzel.
Algoritmy BFS (Breadth-First Search):
- Procházení objednávky úrovně: Navštivte uzly úroveň po úrovni a způsobem zleva doprava na stejné úrovni. Zde je procházení rovinné. To znamená, že dítě, které je nejvíce vlevo, prošlo jako první a poté ostatní děti stejné úrovně zleva doprava prošly.
3. Vymazání v binárním stromu
Můžeme smazat libovolný uzel v binárním stromě a po smazání přeuspořádat uzly tak, aby opět tvořily platný binární strom.
Algoritmus pro odstranění uzlu v binárním stromu:
- Začněte u kořene a najděte nejhlubší a nejpravější uzel v binárním stromě a uzel, který chceme odstranit.
- Nahraďte data nejhlubšího pravého uzlu uzlem, který chcete odstranit.
- Potom odstraňte nejhlubší uzel vpravo.
4. Vyhledávání v binárním stromu
Prvek v uzlu můžeme vyhledat pomocí libovolné techniky procházení.
Algoritmus pro vyhledávání uzlu v binárním stromu:
- Začněte od kořenového uzlu.
- Zkontrolujte, zda se hodnota aktuálního uzlu rovná cílové hodnotě.
- Pokud je hodnota aktuálního uzlu rovna cílové hodnotě, pak je tento uzel požadovaným uzlem.
- V opačném případě, pokud se hodnota uzlu nerovná cílové hodnotě, spusťte vyhledávání v levém a pravém potomku.
- Pokud nenajdeme žádný uzel, jehož hodnota je rovna cílové, pak hodnota není ve stromu přítomna.
Pomocné Operace Na Binárním Stromu
- Zjištění výšky stromu
- Najděte úroveň uzlu v binárním stromu
- Zjištění velikosti celého stromu
Implementace binárního stromu
Níže je uveden kód pro vkládání, mazání a procházení binárního stromu:
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->data = val; temp->left = temp->right = NULL; návratová teplota; } // Funkce pro vložení uzlů Node* insert(Node* root, int data) { // Pokud je strom prázdný, nový uzel se stane kořenem if (root == NULL) { root = newNode(data); vrátit kořen; } // Fronta pro procházení stromu a nalezení pozice pro vložení uzlu Node* queue[100]; vnitřní přední = 0, zadní = 0; fronta[zadni++] = root; while (přední != zadní) { Node* temp = fronta[front++]; // Vloží uzel jako levého potomka nadřazeného uzlu if (temp->left == NULL) { temp->left = newNode(data); přestávka; } // Pokud levý potomek není null, pošle ho do fronty else queue[rear++] = temp->left; // Vložit uzel jako pravého potomka nadřazeného uzlu if (temp->right == NULL) { temp->right = newNode(data); přestávka; } // Pokud pravý potomek není null, pošle ho do fronty else queue[rear++] = temp->right; } return root; } /* Funkce pro smazání daného nejhlubšího uzlu (d_uzel) v binárním stromě */ void deletDeepest(Node* root, Node* d_node) { Node* queue[100]; vnitřní přední = 0, zadní = 0; fronta[zadni++] = root; // Provede procházení pořadí úrovní až do posledního uzlu Node* temp; while (přední != zadní) { temp = fronta[front++]; if (temp == d_uzel) { temp = NULL; free(d_uzel); vrátit se; } if (temp->vpravo) { if (temp->vpravo == d_uzel) { temp->vpravo = NULL; free(d_uzel); vrátit se; } else queue[zadni++] = temp->vpravo; } if (temp->left) { if (temp->left == d_uzel) { temp->left = NULL; free(d_uzel); vrátit se; } else queue[zadní++] = temp->left; } } } /* Funkce pro odstranění prvku v binárním stromu */ Node* deletion(Node* root, int key) { if (!root) return NULL; if (root->left == NULL && root->right == NULL) { if (root->data == key) return NULL; jinak vrátit kořen; } Uzel* fronta[100]; vnitřní přední = 0, zadní = 0; fronta[zadni++] = root; Node* temp; Uzel* klíč_uzel = NULL; // Proveďte procházení pořadím úrovní, abyste našli nejhlubší uzel (temp) a uzel, který má být smazán (key_node) while (front != zadní) { temp = queue[front++]; if (temp->data == klíč) key_node = temp; if (temp->left) queue[zadní++] = temp->left; if (temp->right) queue[zadní++] = temp->right; } if (klíč_uzel != NULL) { int x = temp->data; klíč_uzel->data = x; deletDeepest(kořen, teplota); } return root; } // Procházení stromem pořadí (Left - Root - Right) void inorderTraversal(Node* root) { if (!root) return; inorderTraversal(root->left); printf('%d ', root->data); inorderTraversal(root->right); } // Preorder tree traversal (Root - Left - Right) void preorderTraversal(Node* root) { if (!root) return; printf('%d ', root->data); preorderTraversal(root->left); preorderTraversal(root->right); } // Procházení stromem postorderu (Left - Right - Root) void postorderTraversal(Node* root) { if (root == NULL) return; postorderTraversal(root->left); postorderTraversal(root->right); printf('%d ', root->data); } // Funkce pro procházení stromu pořadí úrovní void levelorderTraversal(Uzel* root) { if (kořen == NULL) return; // Fronta pro průchod pořadím úrovně Uzel* fronta[100]; vnitřní přední = 0, zadní = 0; fronta[zadni++] = root; while (přední != zadní) { Node* temp = fronta[front++]; printf('%d ', temp->data); // Push levého potomka ve frontě if (temp->left) queue[rear++] = temp->left; // Push right child ve frontě if (temp->right) queue[rear++] = temp->right; } } /* Funkce ovladače pro kontrolu výše uvedeného algoritmu. */ int main() { Uzel* root = NULL; // Vložení uzlů root = insert(root, 10); root = insert(kořen, 20); root = insert(kořen, 30); root = insert(kořen, 40); printf('Přechod předobjednávky: '); preorderTraversal(root); printf('
Pořadí procházení: '); inorderTraversal(kořen); printf('
Postorder traversal: '); postorderTraversal(root); printf('
Přechod pořadím úrovně: '); levelorderTraversal(kořen); // Smaže uzel s daty = 20 root = deletion(root, 20); printf('
Pořadí procházení po smazání: '); inorderTraversal(kořen); návrat 0; }> Jáva 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 = new LinkedList(); q.offer(kořen); while (!q.isEmpty()) { Node temp = q.poll(); // Vložit uzel jako levého potomka nadřazeného uzlu if (temp.left == null) { temp.left = new Node(data); přestávka; } // Pokud levý potomek není null, pošle ho do // fronty else q.offer(temp.left); // Vložit uzel jako pravého potomka nadřazeného uzlu if (temp.right == null) { temp.right = new Node(data); přestávka; } // Pokud správný potomek není null, pošle ho do // fronty else q.offer(temp.right); } return root; } /* funkce pro odstranění daného nejhlubšího uzlu (d_uzel) v binárním stromu */ public static void deletDeepest(kořen uzlu, uzel d_uzel) { Queueq = new LinkedList(); q.offer(kořen); // Provede procházení pořadí úrovní až do posledního uzlu Teplota uzlu; while (!q.isEmpty()) { temp = q.poll(); if (temp == d_uzel) { temp = null; d_uzel = null; vrátit se; } if (temp.right != null) { if (temp.right == d_node) { temp.right = null; d_uzel = null; vrátit se; } else q.offer(temp.right); } if (temp.left != null) { if (temp.left == d_uzel) { temp.left = null; d_uzel = null; vrátit se; } else q.offer(temp.left); } } } /* funkce pro odstranění prvku v binárním stromu */ public static Odstranění uzlu (kořen uzlu, klíč int) { if (root == null) return null; if (root.left == null && root.right == null) { if (root.data == klíč) return null; jinak vrátit kořen; } Frontaq = new LinkedList(); q.offer(kořen); Teplota uzlu = new Node(0); Uzel klíč_uzel = null; // Proveďte procházení pořadím úrovní za účelem nalezení nejhlubšího // node(temp) a uzlu, který má být smazán (key_node) while (!q.isEmpty()) { temp = q.poll(); if (temp.data == klíč) key_node = temp; if (temp.left != null) q.offer(temp.left); if (temp.right != null) q.offer(temp.right); } if (uzel_klíče != null) { int x = temp.data; key_node.data = x; deletDeepest(kořen, temp); } return root; } // Procházení stromem pořadí (Left - Root - Right) public static void inorderTraversal(Node root) { if (root == null) return; inorderTraversal(root.left); System.out.print(root.data + ' '); inorderTraversal(root.right); } // Preorder tree traversal (Root - Left - Right) public static void preorderTraversal(Node root) { if (root == null) return; System.out.print(root.data + ' '); preorderTraversal(root.left); preorderTraversal(root.right); } // Procházení stromu postorderu (Left - Right - Root) public static void postorderTraversal(Node root) { if (root == null) return; postorderTraversal(root.left); postorderTraversal(root.right); System.out.print(root.data + ' '); } // Funkce pro procházení stromu pořadí úrovní public static void levelorderTraversal(kořen uzlu) { if (kořen == null) return; // Fronta pro průchod pořadím úrovně Frontaq = new LinkedList(); q.offer(kořen); while (!q.isEmpty()) { Node temp = q.poll(); System.out.print(temp.data + ' '); // Posune levého potomka ve frontě if (temp.left != null) q.offer(temp.left); // Vložit pravého potomka do fronty if (temp.right != null) q.offer(temp.right); } } /* Funkce ovladače pro kontrolu výše uvedeného algoritmu. */ public static void main(String[] args) { Kořen uzlu = null; // Vložení uzlů root = insert(root, 10); root = insert(kořen, 20); root = insert(kořen, 30); root = insert(kořen, 40); System.out.print('Přechod předobjednávky: '); preorderTraversal(root); System.out.print('
Pořadí procházení: '); inorderTraversal(kořen); System.out.print('
Postorder traversal: '); postorderTraversal(root); System.out.print('
Přechod objednávky úrovně: '); levelorderTraversal(kořen); // Smaže uzel s daty = 20 root = deletion(root, 20); System.out.print('
Pořadí procházení po smazání: '); inorderTraversal(kořen); } }> Krajta 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 = nová fronta(); q.Enqueue(kořen); while (q.Count != 0) { Teplota uzlu = q.Dequeue(); // Vložit uzel jako levého potomka nadřazeného uzlu if (temp.left == null) { temp.left = new Node(data); přestávka; } // Pokud levý potomek není null, pošle ho do fronty else q.Enqueue(temp.left); // Vložit uzel jako pravého potomka nadřazeného uzlu if (temp.right == null) { temp.right = new Node(data); přestávka; } // Pokud správný potomek není null, pošle ho do fronty else q.Enqueue(temp.right); } return root; } /* funkce pro odstranění daného nejhlubšího uzlu (d_node) v binárním stromu */ public static void DeleteDeepest(Node root, Node d_node) { Queueq = nová fronta(); q.Enqueue(kořen); // Provede procházení pořadí úrovní až do posledního uzlu Teplota uzlu; while (q.Count != 0) { temp = q.Dequeue(); if (temp == d_uzel) { temp = null; d_uzel = null; vrátit se; } if (temp.right != null) { if (temp.right == d_node) { temp.right = null; d_uzel = null; vrátit se; } else q.Enqueue(temp.right); } if (temp.left != null) { if (temp.left == d_uzel) { temp.left = null; d_uzel = null; vrátit se; } else q.Enqueue(temp.left); } } } /* funkce pro odstranění prvku v binárním stromu */ public static Odstranění uzlu (kořen uzlu, klíč int) { if (root == null) return null; if (root.left == null && root.right == null) { if (root.data == klíč) return null; jinak vrátit kořen; } Frontaq = nová fronta(); q.Enqueue(kořen); Teplota uzlu = new Node(0); Uzel klíč_uzel = null; // Proveďte procházení pořadím úrovní pro nalezení nejhlubšího uzlu (temp) a uzlu, který má být smazán (key_node) while (q.Count != 0) { temp = q.Dequeue(); if (temp.data == klíč) key_node = temp; if (temp.left != null) q.Enqueue(temp.left); if (temp.right != null) q.Enqueue(temp.right); } if (uzel_klíče != null) { int x = temp.data; key_node.data = x; DeleteDeepest(root, temp); } return root; } // Procházení stromem pořadí (Left - Root - Right) public static void InorderTraversal(Node root) { if (root == null) return; InorderTraversal(root.left); Console.Write(root.data + ' '); InorderTraversal(root.right); } // Procházení stromu předobjednávky (kořen - vlevo - vpravo) public static void PreorderTraversal(kořen uzlu) { if (kořen == null) return; Console.Write(root.data + ' '); PreorderTraversal(root.left); PreorderTraversal(root.right); } // Procházení stromem Postorderu (Left - Right - Root) public static void PostorderTraversal(Node root) { if (root == null) return; PostorderTraversal(root.left); PostorderTraversal(root.right); Console.Write(root.data + ' '); } // Funkce pro procházení stromu pořadí úrovní public static void LevelorderTraversal(kořen uzlu) { if (kořen == null) return; // Fronta pro průchod pořadím úrovně Frontaq = nová fronta(); q.Enqueue(kořen); while (q.Count != 0) { Teplota uzlu = q.Dequeue(); Console.Write(temp.data + ' '); // Vloží levého potomka do fronty if (temp.left != null) q.Enqueue(temp.left); // Vložení pravého potomka do fronty if (temp.right != null) q.Enqueue(temp.right); } } /* Funkce ovladače pro kontrolu výše uvedeného algoritmu. */ public static void Main(string[] args) { Kořen uzlu = null; // Vložení uzlů root = Insert(root, 10); root = Insert(kořen, 20); root = Insert(kořen, 30); root = Insert(kořen, 40); Console.Write('Přechod předobjednávky: '); PreorderTraversal(root); Console.Write('
Pořadí procházení: '); InorderTraversal(root); Console.Write('
Postorder traversal: '); PostorderTraversal(root); Console.Write('
Přechod objednávky úrovně: '); LevelorderTraversal(kořen); // Smaže uzel s daty = 20 root = Deletion(root, 20); Console.Write('
Pořadí procházení po smazání: '); InorderTraversal(root); } }> 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(kořen); while (!q.empty()) { Node* temp = q.front(); q.pop(); // Vložit uzel jako levého potomka nadřazeného uzlu if (temp->left == NULL) { temp->left = new Node(data); přestávka; } // Pokud levý potomek není null, pošle ho do // fronty else q.push(temp->left); // Vložit uzel jako pravého potomka nadřazeného uzlu if (temp->right == NULL) { temp->right = new Node(data); přestávka; } // Pokud správný potomek není null, pošle ho do // fronty else q.push(temp->right); } return root; } /* funkce pro odstranění daného nejhlubšího uzlu (d_uzel) v binárním stromu */ void deletDeepest(Node* root, Node* d_node) { queueq; q.push(kořen); // Provede procházení pořadí úrovní až do posledního uzlu Node* temp; while (!q.empty()) { temp = q.front(); q.pop(); if (temp == d_uzel) { temp = NULL; delete (d_uzel); vrátit se; } if (temp->vpravo) { if (temp->vpravo == d_uzel) { temp->vpravo = NULL; delete (d_uzel); vrátit se; } else q.push(temp->right); } if (temp->left) { if (temp->left == d_uzel) { temp->left = NULL; delete (d_uzel); vrátit se; } else q.push(temp->left); } } } /* funkce pro smazání prvku v binárním stromu */ Node* deletion(Node* root, int key) { if (!root) return NULL; if (root->left == NULL && root->right == NULL) { if (root->data == key) return NULL; jinak vrátit kořen; } frontaq; q.push(kořen); Node* temp; Uzel* key_node = NULL; // Proveďte procházení pořadím úrovní, abyste našli nejhlubší // node(temp) a uzel, který má být smazán (key_node) while (!q.empty()) { temp = q.front(); q.pop(); if (temp->data == klíč) key_node = temp; if (temp->left) q.push(temp->left); if (temp->right) q.push(temp->right); } if (klíčový_uzel != NULL) { int x = temp->data; klíč_uzel->data = x; deletDeepest(kořen, temp); } return root; } // Procházení stromem pořadí (Left - Root - Right) void inorderTraversal(Node* root) { if (!root) return; inorderTraversal(root->left); cout<< root->data<< ' '; inorderTraversal(root->že jo); } // Preorder tree traversal (Root - Left - Right) void preorderTraversal(Node* root) { if (!root) return; cout<< root->data<< ' '; preorderTraversal(root->vlevo, odjet); preorderTraversal(root->right); } // Procházení stromem postorderu (Left - Right - Root) void postorderTraversal(Node* root) { if (root == NULL) return; postorderTraversal(root->left); postorderTraversal(root->right); cout<< root->data<< ' '; } // Function for Level order tree traversal void levelorderTraversal(Node* root) { if (root == NULL) return; // Queue for level order traversal queueq; q.push(kořen); while (!q.empty()) { Node* temp = q.front(); q.pop(); cout<< temp->data<< ' '; // Push left child in the queue if (temp->vlevo) q.push(temp->left); // Push right child ve frontě if (temp->right) q.push(temp->right); } } /* Funkce ovladače pro kontrolu výše uvedeného algoritmu. */ int main() { Uzel* root = NULL; // Vložení uzlů root = insert(root, 10); root = insert(kořen, 20); root = insert(kořen, 30); root = insert(kořen, 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); }> Výstup
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>
Analýza složitosti operací binárních stromů
| Operace | Časová složitost | Vesmírná složitost |
|---|---|---|
| Vložení | NA) | NA) |
| Předobjednávka Traversal | NA) | NA) jak převést řetězec na celé číslo java |
Inorder Traversal | NA) | NA) |
| Přechod poštovní poukázkou | NA) | NA) |
| Level Order Traversal | NA) | NA) |
Vymazání | NA) | NA) |
Hledání | NA) | NA) |
Můžeme použít Morris Traversal procházet všechny uzly binárního stromu v O(1) čase.
Výhody binárního stromu
- Efektivní vyhledávání: Binární stromy jsou efektivní při hledání konkrétního prvku, protože každý uzel má maximálně dva podřízené uzly, což umožňuje Paměťově efektivní: Binární stromy vyžadují méně paměti ve srovnání s jinými stromovými datovými strukturami, proto jsou paměťově efektivní.
- Binární stromy lze relativně snadno implementovat a pochopit, protože každý uzel má nejvýše dvě potomky, levé dítě a pravé dítě.
Nevýhody binárního stromu
- Omezená struktura: Binární stromy jsou omezeny na dva podřízené uzly na uzel, což může omezit jejich užitečnost v určitých aplikacích. Pokud například strom vyžaduje více než dva podřízené uzly na uzel, může být vhodnější jiná stromová struktura.
- Nevyvážené stromy: Nevyvážené binární stromy, kde je jeden podstrom výrazně větší než druhý, může vést k neefektivním vyhledávacím operacím. K tomu může dojít, pokud strom není správně vyvážen nebo pokud jsou data vložena v nenáhodném pořadí.
- Prostorová neefektivita: Binární stromy mohou být prostorově neefektivní ve srovnání s jinými datovými strukturami. Důvodem je, že každý uzel vyžaduje dva podřízené ukazatele, což může představovat značné množství paměti pro velké stromy.
- Pomalý výkon v nejhorších scénářích: V nejhorším případě může binární strom degenerovat nebo zkosit, což znamená, že každý uzel má pouze jednoho potomka. V tomto případě mohou vyhledávací operace degradovat na časovou složitost O(n), kde n je počet uzlů ve stromu.
Aplikace binárního stromu
- Binární strom lze použít představují hierarchická data .
- Používají se Huffmanovy kódovací stromy datové kompresní algoritmy .
- Prioritní fronta je další aplikací binárního stromu, která se používá pro hledání maxima nebo minima v časové složitosti O(1).
- Užitečné pro indexování segmentované v databázi je užitečné při ukládání mezipaměti v systému,
- Binární stromy lze použít k implementaci rozhodovacích stromů, což je typ algoritmu strojového učení používaného pro klasifikaci a regresní analýzu.
Často kladené otázky o binárním stromu
1. Co je to binární strom?
Binární strom je nelineární datová struktura sestávající z uzlů, kde každý uzel má nejvýše dva potomky (levý potomek a pravý potomek).
2. Jaké jsou typy binárních stromů?
Binární stromy lze klasifikovat do různých typů, včetně úplných binárních stromů, úplných binárních stromů, dokonalých binárních stromů, vyvážených binárních stromů (jako jsou stromy AVL a Red-Black stromy) a degenerovaných (nebo patologických) binárních stromů.
3. Jakou výšku má binární strom?
Výška binárního stromu je délka nejdelší cesty od kořenového uzlu k listovému uzlu. Představuje počet hran na nejdelší cestě od kořenového uzlu k listovému uzlu.
4. Jaká je hloubka uzlu v binárním stromě?
Hloubka uzlu v binárním stromu je délka cesty od kořenového uzlu k tomuto konkrétnímu uzlu. Hloubka kořenového uzlu je 0.
5. Jak provádíte procházení stromu v binárním stromu?
Procházení stromem v binárním stromě lze provést různými způsoby: Procházení v pořadí, Procházení před objednávkou, Procházení po objednávce a Procházení podle úrovně (také známé jako procházení do šířky).
6. Co je to Inorder traversal v Binary Tree?
V Inorder traversal jsou uzly rekurzivně navštěvovány v tomto pořadí: levý potomek, kořen, pravý potomek. Toto procházení má za následek navštívení uzlů v neklesajícím pořadí v binárním vyhledávacím stromu.
7. Co je to procházení předobjednávky v binárním stromu?
V Preorder traversal jsou uzly rekurzivně navštěvovány v tomto pořadí: kořen, levý potomek, pravý potomek. Toto procházení vede k tomu, že kořenový uzel je prvním navštíveným uzlem.
8. Co je to Postorder traversal v Binary Tree?
V Postorder traversal jsou uzly rekurzivně navštěvovány v tomto pořadí: levé dítě, pravé dítě a kořen. Toto procházení vede k tomu, že kořenový uzel je posledním navštíveným uzlem.
9. Jaký je rozdíl mezi binárním stromem a binárním vyhledávacím stromem?
Binární strom je hierarchická datová struktura, kde každý uzel má nejvýše dva potomky, zatímco binární vyhledávací strom je typ binárního stromu, ve kterém levý potomek uzlu obsahuje hodnoty menší než hodnota uzlu a pravý potomek obsahuje hodnoty. větší než hodnota uzlu.
10. Co je to vyvážený binární strom?
Vyvážený binární strom je binární strom, ve kterém se výška levého a pravého podstromu každého uzlu liší nejvýše o jednu. Vyvážené stromy pomáhají udržovat efektivní operace, jako je vyhledávání, vkládání a mazání, s časovou složitostí blízkou O(log n).
sql klauzule
Závěr:
Strom je hierarchická datová struktura. Mezi hlavní využití stromů patří udržování hierarchických dat, poskytování středního přístupu a operací vkládání/mazání. Binární stromy jsou speciální případy stromu, kde každý uzel má nejvýše dva potomky.
Související články:
- Vlastnosti binárního stromu
- Typy binárních stromů