Drzewo binarne jest nieliniowa struktura danych gdzie każdy węzeł ma co najwyżej dwoje dzieci. W tym artykule omówimy wszystkie podstawy drzewa binarnego, operacje na drzewie binarnym, jego implementację, zalety i wady, które pomogą Ci rozwiązać wszystkie problemy oparte na drzewie binarnym.
Spis treści
- Co to jest drzewo binarne?
- Reprezentacja drzewa binarnego
- Rodzaje drzew binarnych
- Operacje na drzewie binarnym
- Operacje pomocnicze na drzewie binarnym
- Implementacja drzewa binarnego
- Analiza złożoności operacji na drzewie binarnym
- Zalety drzewa binarnego
- Wady drzewa binarnego
- Zastosowania drzewa binarnego
- Często zadawane pytania dotyczące drzewa binarnego
Co to jest drzewo binarne?
Drzewo binarne to a drzewiasta struktura danych (nieliniowa) w którym każdy węzeł może mieć najwyżej dwójkę dzieci które określane są mianem pozostawione dziecko i właściwe dziecko .
Najwyższy węzeł w drzewie binarnym nazywa się źródło i nazywane są węzły położone najniżej liście . Drzewo binarne można sobie wyobrazić jako strukturę hierarchiczną z korzeniem na górze i liśćmi na dole.
Aktorka Sai Pallavi
Reprezentacja drzewa binarnego
Każdy węzeł drzewa binarnego składa się z trzech części:
- Dane
- Wskaźnik do lewego dziecka
- Wskaźnik do odpowiedniego dziecka
Poniżej znajduje się reprezentacja węzła drzewa binarnego w różnych językach:
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; };> Jawa // 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; } }> Pyton # 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 >
Rodzaje drzew binarnych
Drzewo binarne można podzielić na typy wielokrotne w oparciu o wiele czynników:
- Na podstawie liczby dzieci
- Pełne drzewo binarne
- Zdegenerowane drzewo binarne
- Przekrzywione drzewa binarne
- Na podstawie ukończenia poziomów
- Kompletne drzewo binarne
- Idealne drzewo binarne
- Zrównoważone drzewo binarne
- Na podstawie wartości węzłów:
- Drzewo wyszukiwania binarnego
- Drzewo AVL
- Czerwone Czarne Drzewo
- Drzewo B
- B+ Drzewo
- Drzewo segmentowe
Operacje na drzewie binarnym
1. Wstawienie do drzewa binarnego
Możemy wstawić węzeł w dowolnym miejscu drzewa binarnego, wstawiając go jako lewe lub prawe dziecko dowolnego węzła lub czyniąc węzeł korzeniem drzewa.
Algorytm wstawiania węzła do drzewa binarnego:
- Sprawdź, czy w drzewie binarnym znajduje się węzeł, w którym brakuje lewego dziecka. Jeśli taki węzeł istnieje, wstaw nowy węzeł jako jego lewe dziecko.
- Sprawdź, czy w drzewie binarnym znajduje się węzeł, w którym brakuje prawego dziecka. Jeśli taki węzeł istnieje, wstaw nowy węzeł jako jego prawy element podrzędny.
- Jeśli nie znajdziemy żadnego węzła z brakującym lewym lub prawym dzieckiem, znajdź węzeł, w którym brakuje obu dzieci i wstaw węzeł jako jego lewe lub prawe dziecko.
2. Przechodzenie przez drzewo binarne
Przechodzenie przez drzewo binarne polega na odwiedzeniu wszystkich węzłów drzewa binarnego. Algorytmy przechodzenia przez drzewo można ogólnie podzielić na dwie kategorie:
- Algorytmy przeszukiwania w głąb (DFS).
- Algorytmy wyszukiwania wszerz (BFS).
Algorytmy wyszukiwania w głąb (DFS):
- Przemierzanie w przedsprzedaży (bieżący-lewy-prawy): Odwiedź bieżący węzeł przed odwiedzeniem jakichkolwiek węzłów w lewym lub prawym poddrzewie. Tutaj przejście to korzeń – lewe dziecko – prawe dziecko. Oznacza to, że najpierw przechodzi się przez węzeł główny, potem przez jego lewe dziecko, a na końcu przez prawe dziecko.
- Przemierzanie porządku (lewy-prąd-prawy): Odwiedź bieżący węzeł po odwiedzeniu wszystkich węzłów w lewym poddrzewie, ale przed odwiedzeniem dowolnego węzła w prawym poddrzewie. Tutaj przejściem jest lewe dziecko – korzeń – prawe dziecko. Oznacza to, że najpierw przechodzi lewe dziecko, potem jego węzeł główny, a na koniec prawe dziecko.
- Przechodzenie po zamówieniu (lewy-prawy-prąd): Odwiedź bieżący węzeł po odwiedzeniu wszystkich węzłów lewego i prawego poddrzewa. Tutaj przejściem jest lewe dziecko – prawe dziecko – korzeń. Oznacza to, że najpierw przeszło lewe dziecko, potem prawe i na koniec jego węzeł główny.
Algorytmy wyszukiwania wszerz (BFS):
- Przechodzenie przez kolejność poziomów: Odwiedzaj węzły poziom po poziomie i od lewej do prawej na tym samym poziomie. Tutaj przejście odbywa się na poziomie. Oznacza to, że dziecko znajdujące się najbardziej po lewej stronie przeszło jako pierwsze, a następnie przeszły pozostałe dzieci na tym samym poziomie, od lewej do prawej.
3. Usuwanie w drzewie binarnym
Możemy usunąć dowolny węzeł w drzewie binarnym i zmienić kolejność węzłów po usunięciu, aby ponownie utworzyć prawidłowe drzewo binarne.
Algorytm usuwania węzła w drzewie binarnym:
- Zaczynając od korzenia, znajdź najgłębszy i najbardziej na prawo położony węzeł w drzewie binarnym oraz węzeł, który chcemy usunąć.
- Zastąp dane najgłębszego prawego węzła węzłem, który ma zostać usunięty.
- Następnie usuń najgłębszy węzeł położony skrajnie na prawo.
4. Wyszukiwanie w drzewie binarnym
Elementu w węźle możemy szukać dowolną techniką przechodzenia.
modulacja amplitudy
Algorytm przeszukiwania węzła w drzewie binarnym:
- Zacznij od węzła głównego.
- Sprawdź, czy wartość bieżącego węzła jest równa wartości docelowej.
- Jeśli wartość bieżącego węzła jest równa wartości docelowej, wówczas ten węzeł jest węzłem wymaganym.
- W przeciwnym razie, jeśli wartość węzła nie jest równa wartości docelowej, rozpocznij wyszukiwanie w lewym i prawym dziecku.
- Jeśli nie znajdziemy żadnego węzła, którego wartość jest równa target, to tej wartości nie ma w drzewie.
Operacje pomocnicze na drzewie binarnym
- Znalezienie wysokości drzewa
- Znajdź poziom węzła w drzewie binarnym
- Znalezienie rozmiaru całego drzewa
Implementacja drzewa binarnego
Poniżej znajduje się kod umożliwiający wstawianie, usuwanie i przeglądanie drzewa binarnego:
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->dane = wartość; temp->lewo = temp->prawo = NULL; temperatura powrotu; } // Funkcja wstawiania węzłów Node* wstaw(Node* root, int data) { // Jeśli drzewo jest puste, nowy węzeł staje się korzeniem if (root == NULL) { root = newNode(data); zwróć korzeń; } // Kolejka do przejścia przez drzewo i znalezienia miejsca, w którym można wstawić węzeł Node* kolejka[100]; int przód = 0, tył = 0; kolejka[tył++] = korzeń; while (przód != tył) { Węzeł* temp = kolejka[przód++]; // Wstaw węzeł jako lewy element podrzędny węzła nadrzędnego if (temp->left == NULL) { temp->left = newNode(data); przerwa; } // Jeśli lewe dziecko nie ma wartości null, wepchnij je do kolejki w przeciwnym razie kolejka[rear++] = temp->left; // Wstaw węzeł jako prawy element podrzędny węzła nadrzędnego if (temp->right == NULL) { temp->right = newNode(data); przerwa; } // Jeśli prawe dziecko nie ma wartości null, wepchnij je do kolejki, w przeciwnym razie kolejka[rear++] = temp->right; } zwróć korzeń; } /* Funkcja usuwająca podany najgłębszy węzeł (d_node) w drzewie binarnym */ void deletDeepest(Node* root, Node* d_node) { Node* kolejka[100]; int przód = 0, tył = 0; kolejka[tył++] = korzeń; // Wykonaj przechodzenie w kolejności poziomów aż do ostatniego węzła Node* temp; while (przód != tył) { temp = kolejka[przód++]; if (temp == d_node) { temp = NULL; wolny(d_węzeł); powrót; } if (temp->right) { if (temp->right == d_node) { temp->right = NULL; wolny(d_węzeł); powrót; } else kolejka[tył++] = temp->prawo; } if (temp->lewy) { if (temp->lewy == d_node) { temp->lewy = NULL; wolny(d_węzeł); powrót; } else kolejka[tył++] = temp->lewo; } } } /* Funkcja usuwająca element z drzewa binarnego */ Node* deletion(Node* root, int key) { if (!root) return NULL; if (root->left == NULL && root->right == NULL) { if (root->data == klucz) return NULL; w przeciwnym razie zwróć root; } Węzeł* kolejka[100]; int przód = 0, tył = 0; kolejka[tył++] = korzeń; temperatura węzła*; Węzeł* węzeł_klucza = NULL; // Wykonaj przechodzenie w kolejności poziomów, aby znaleźć najgłębszy węzeł (temp) i węzeł do usunięcia (key_node) while (front != rear) { temp = kolejka[front++]; if (temp->data == klucz) key_node = temp; if (temp->lewo) kolejka[tył++] = temp->lewo; if (temp->prawo) kolejka[tył++] = temp->prawo; } if (key_node != NULL) { int x = temp->data; węzeł_klucza->dane = x; deletDeepest(korzeń, temperatura); } zwróć korzeń; } // Przechodzenie przez drzewo w kolejności (w lewo - korzeń - w prawo) void inorderTraversal(Node* root) { if (!root) return; inorderTraversal(root->lewy); printf('%d ', root->dane); inorderTraversal(root->right); } // Zamawianie w przedsprzedaży przejścia przez drzewo (Korzeń - Lewo - Prawo) void preorderTraversal(Node* root) { if (!root) return; printf('%d ', root->dane); preorderTraversal(root->lewy); preorderTraversal(root->right); } // Przechodzenie przez drzewo postorderu (Lewo - Prawo - Korzeń) void postorderTraversal(Node* root) { if (root == NULL) return; postorderTraversal(root->lewy); postorderTraversal(root->right); printf('%d ', root->dane); } // Funkcja umożliwiająca przechodzenie przez drzewo kolejności poziomów void poziomorderTraversal(Node* root) { if (root == NULL) return; // Kolejka do przejścia kolejności poziomów Węzeł* kolejka[100]; int przód = 0, tył = 0; kolejka[tył++] = korzeń; while (przód != tył) { Węzeł* temp = kolejka[przód++]; printf('%d ', temp->dane); // Włóż lewe dziecko do kolejki if (temp->left) kolejka[rear++] = temp->left; // Włóż prawe dziecko do kolejki if (temp->right) kolejka[rear++] = temp->right; } } /* Funkcja sterownika sprawdzająca powyższy algorytm. */ int main() { Węzeł* root = NULL; // Wstawienie węzłów root = wstaw(root, 10); root = wstaw(korzeń, 20); root = wstaw(korzeń, 30); root = wstaw(korzeń, 40); printf('Przechodzenie w przedsprzedaży: '); zamówienie w przedsprzedażyTraversal(root); printf('
Przejście w kolejności: '); inorderTraversal(root); printf('
Przechodzenie po zamówieniu: '); postorderTraversal(root); printf('
Przechodzenie przez poziom: '); LevelorderTraversal(root); // Usuń węzeł z danymi = 20 root = deletion(root, 20); printf('
Przejście w kolejności po usunięciu: '); inorderTraversal(root); zwróć 0; }> Jawa 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 = nowa lista połączona(); q.oferta(root); while (!q.isEmpty()) { Temp. węzła = q.poll(); // Wstaw węzeł jako lewy element podrzędny węzła nadrzędnego if (temp.left == null) { temp.left = new Node(data); przerwa; } // Jeśli lewe dziecko nie ma wartości null, włóż je do // kolejki, w przeciwnym razie q.offer(temp.left); // Wstaw węzeł jako prawy element podrzędny węzła nadrzędnego if (temp.right == null) { temp.right = new Node(data); przerwa; } // Jeśli właściwe dziecko nie ma wartości null, włóż je do // kolejki, w przeciwnym razie q.offer(temp.right); } zwróć korzeń; } /* funkcja usuwająca podany najgłębszy węzeł (d_node) w drzewie binarnym */ public static void deletDeepest(Node root, Node d_node) { Queueq = nowa lista połączona(); q.oferta(root); // Wykonaj przechodzenie na poziomie aż do ostatniego węzła Temp. węzła; while (!q.isEmpty()) { temp = q.poll(); if (temp == d_node) { temp = null; d_node = null; powrót; } if (temp.right != null) { if (temp.right == d_node) { temp.right = null; d_node = null; powrót; } else q.offer(temp.right); } if (temp.left != null) { if (temp.left == d_node) { temp.left = null; d_node = null; powrót; } else q.offer(temp.left); } } } /* funkcja usuwająca element z drzewa binarnego */ public static Usuwanie węzła (korzeń węzła, klucz int) { if (root == null) return null; if (root.left == null && root.right == null) { if (root.data == klucz) return null; w przeciwnym razie zwróć root; } Kolejkaq = nowa lista połączona(); q.oferta(root); Temperatura węzła = nowy węzeł (0); Węzeł klucz_node = null; // Wykonaj przechodzenie w kolejności poziomów, aby znaleźć najgłębszy // węzeł (temp) i węzeł do usunięcia (key_node) while (!q.isEmpty()) { temp = q.poll(); if (temp.data == klucz) 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; węzeł_klucza.dane = x; deletDeepest(korzeń, temperatura); } zwróć korzeń; } // Przechodzenie przez drzewo w kolejności (Lewo - Korzeń - Prawo) public static void inorderTraversal(Node root) { if (root == null) return; inorderTraversal(root.left); System.out.print(root.data + ' '); inorderTraversal(root.right); } // Zamówienie przejścia drzewa w przedsprzedaży (Korzeń - Lewy - Prawy) public static void preorderTraversal(Korzeń węzła) { if (root == null) return; System.out.print(root.data + ' '); zamówienie w przedsprzedażyTraversal(root.left); zamówienie w przedsprzedażyTraversal(root.right); } // Przechodzenie przez drzewo postorderu (Lewo - Prawo - Korzeń) public static void postorderTraversal(Korzeń węzła) { if (root == null) return; postorderTraversal(root.left); postorderTraversal(root.right); System.out.print(root.data + ' '); } // Funkcja przechodzenia przez drzewo kolejności poziomów public static void poziomorderTraversal(Node root) { if (root == null) return; // Kolejka do przejścia kolejności poziomów Kolejkaq = nowa lista połączona(); q.oferta(root); while (!q.isEmpty()) { Temp. węzła = q.poll(); System.out.print(temp.dane + ' '); // Włóż lewe dziecko do kolejki if (temp.left != null) q.offer(temp.left); // Wciśnij prawe dziecko w kolejkę if (temp.right != null) q.offer(temp.right); } } /* Funkcja sterownika sprawdzająca powyższy algorytm. */ public static void main(String[] args) { Korzeń węzła = null; // Wstawienie węzłów root = wstaw(root, 10); root = wstaw(korzeń, 20); root = wstaw(korzeń, 30); root = wstaw(korzeń, 40); System.out.print('Przechodzenie w przedsprzedaży: '); zamówienie w przedsprzedażyTraversal(root); System.out.print('
Przejście w kolejności: '); inorderTraversal(root); System.out.print('
Przechodzenie po zamówieniu: '); postorderTraversal(root); System.out.print('
Przechodzenie przez poziom: '); LevelorderTraversal(root); // Usuń węzeł z danymi = 20 root = deletion(root, 20); System.out.print('
Przejście w kolejności po usunięciu: '); inorderTraversal(root); } }> Pyton 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 = nowa kolejka(); q.Kolejkuj(root); while (q.Count != 0) { Temp. węzła = q.Dequeue(); // Wstaw węzeł jako lewy element podrzędny węzła nadrzędnego if (temp.left == null) { temp.left = new Node(data); przerwa; } // Jeśli lewe dziecko nie ma wartości null, włóż je do kolejki w przeciwnym razie q.Enqueue(temp.left); // Wstaw węzeł jako prawy element podrzędny węzła nadrzędnego if (temp.right == null) { temp.right = new Node(data); przerwa; } // Jeśli właściwe dziecko nie ma wartości null, włóż je do kolejki w przeciwnym razie q.Enqueue(temp.right); } zwróć korzeń; } /* funkcja usuwająca podany najgłębszy węzeł (d_node) w drzewie binarnym */ public static void DeleteDeepest(Node root, Node d_node) { Queueq = nowa kolejka(); q.Kolejkuj(root); // Wykonaj przechodzenie na poziomie aż do ostatniego węzła Temp. węzła; póki (q.Count!= 0) { temp = q.Dequeue(); if (temp == d_node) { temp = null; d_node = null; powrót; } if (temp.right != null) { if (temp.right == d_node) { temp.right = null; d_node = null; powrót; } else q.Enqueue(temp.right); } if (temp.left != null) { if (temp.left == d_node) { temp.left = null; d_node = null; powrót; } else q.Enqueue(temp.left); } } } /* funkcja usuwająca element z drzewa binarnego */ public static Node Deletion(root węzła, int klucz) { if (root == null) return null; if (root.left == null && root.right == null) { if (root.data == klucz) return null; w przeciwnym razie zwróć root; } Kolejkaq = nowa kolejka(); q.Kolejkuj(root); Temperatura węzła = nowy węzeł (0); Węzeł klucz_node = null; // Wykonaj przechodzenie w kolejności poziomów, aby znaleźć najgłębszy węzeł (temp) i węzeł do usunięcia (key_node) while (q.Count != 0) { temp = q.Dequeue(); if (temp.data == klucz) 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; węzeł_klucza.dane = x; DeleteDeepest(root, temp); } zwróć korzeń; } // Przechodzenie przez drzewo Inorder (Lewo – Korzeń – Prawo) public static void InorderTraversal(Node root) { if (root == null) return; InorderTraversal(root.left); Console.Write(root.data + ' '); InorderTraversal(root.right); } // Zamówienie przejścia drzewa w przedsprzedaży (Korzeń - Lewy - Prawy) public static void PreorderTraversal(Korzeń węzła) { if (root == null) return; Console.Write(root.data + ' '); PrzedsprzedażTraversal(root.left); PreorderTraversal(root.right); } // Przechodzenie przez drzewo postorderu (Lewo - Prawo - Korzeń) public static void PostorderTraversal(Korzeń węzła) { if (root == null) return; PostorderTraversal(root.left); PostorderTraversal(root.right); Console.Write(root.data + ' '); } // Funkcja przechodzenia przez drzewo kolejności poziomów public static void LevelorderTraversal(Root węzła) { if (root == null) return; // Kolejka do przejścia kolejności poziomów Kolejkaq = nowa kolejka(); q.Kolejkuj(root); while (q.Count != 0) { Temp. węzła = q.Dequeue(); Console.Write(temp.data + ' '); // Włóż lewe dziecko do kolejki if (temp.left != null) q.Enqueue(temp.left); // Włóż prawe dziecko do kolejki if (temp.right != null) q.Enqueue(temp.right); } } /* Funkcja sterownika sprawdzająca powyższy algorytm. */ public static void Main(string[] args) { Korzeń węzła = null; // Wstawienie węzłów root = Insert(root, 10); root = wstaw(korzeń, 20); root = wstaw(korzeń, 30); root = wstaw(korzeń, 40); Console.Write('Przeglądanie zamówienia w przedsprzedaży: '); Zamów w przedsprzedażyTraversal(root); Console.Write('
Przechodzenie w kolejności: '); InorderTraversal(root); Console.Write('
Przechodzenie po zamówieniu: '); PostorderTraversal(root); Console.Write('
Przechodzenie przez kolejność poziomów: '); LevelorderTraversal(root); // Usuń węzeł z danymi = 20 root = Deletion(root, 20); Console.Write('
Przechodzenie w kolejności po usunięciu: '); 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(root); while (!q.empty()) { Węzeł* temp = q.front(); q.pop(); // Wstaw węzeł jako lewy element podrzędny węzła nadrzędnego if (temp->left == NULL) { temp->left = new Node(data); przerwa; } // Jeśli lewe dziecko nie ma wartości null, włóż je do // kolejki, w przeciwnym razie q.push(temp->left); // Wstaw węzeł jako prawy element podrzędny węzła nadrzędnego if (temp->right == NULL) { temp->right = new Node(data); przerwa; } // Jeśli właściwe dziecko nie ma wartości null, włóż je do // kolejki, w przeciwnym razie q.push(temp->right); } zwróć korzeń; } /* funkcja usuwająca podany najgłębszy węzeł (d_node) w drzewie binarnym */ void deletDeepest(Node* root, Node* d_node) { kolejkaQ; q.push(root); // Wykonaj przechodzenie w kolejności poziomów aż do ostatniego węzła Node* temp; while (!q.empty()) { temp = q.front(); q.pop(); if (temp == d_node) { temp = NULL; usuń (d_node); powrót; } if (temp->right) { if (temp->right == d_node) { temp->right = NULL; usuń (d_node); powrót; } else q.push(temp->right); } if (temp->lewy) { if (temp->lewy == d_node) { temp->lewy = NULL; usuń (d_node); powrót; } else q.push(temp->left); } } } /* funkcja usuwająca element z drzewa binarnego */ Node* deletion(Node* root, int key) { if (!root) return NULL; if (root->left == NULL && root->right == NULL) { if (root->data == klucz) return NULL; w przeciwnym razie zwróć root; } kolejkaQ; q.push(root); temperatura węzła*; Węzeł* węzeł_klucza = NULL; // Wykonaj przechodzenie poziomów, aby znaleźć najgłębszy // węzeł (temp) i węzeł do usunięcia (key_node) while (!q.empty()) { temp = q.front(); q.pop(); if (temp->data == klucz) key_node = temp; if (temp->lewo) q.push(temp->lewo); if (temp->prawo) q.push(temp->prawo); } if (key_node != NULL) { int x = temp->dane; węzeł_klucza->dane = x; deletDeepest(korzeń, temperatura); } zwróć korzeń; } // Przechodzenie przez drzewo w kolejności (w lewo - korzeń - w prawo) void inorderTraversal(Node* root) { if (!root) return; inorderTraversal(root->lewy); cout<< root->dane<< ' '; inorderTraversal(root->Prawidłowy); } // Zamawianie w przedsprzedaży przejścia przez drzewo (Korzeń - Lewo - Prawo) void preorderTraversal(Node* root) { if (!root) return; cout<< root->dane<< ' '; preorderTraversal(root->lewy); preorderTraversal(root->right); } // Przechodzenie przez drzewo postorderu (Lewo - Prawo - Korzeń) void postorderTraversal(Node* root) { if (root == NULL) return; postorderTraversal(root->lewy); postorderTraversal(root->right); cout<< root->dane<< ' '; } // Function for Level order tree traversal void levelorderTraversal(Node* root) { if (root == NULL) return; // Queue for level order traversal queueQ; q.push(root); while (!q.empty()) { Węzeł* temp = q.front(); q.pop(); cout<< temp->dane<< ' '; // Push left child in the queue if (temp->lewy) q.push(temp->lewy); // Wciśnij prawe dziecko w kolejkę if (temp->right) q.push(temp->right); } } /* Funkcja sterownika sprawdzająca powyższy algorytm. */ int main() { Węzeł* root = NULL; // Wstawienie węzłów root = wstaw(root, 10); root = wstaw(korzeń, 20); root = wstaw(korzeń, 30); root = wstaw(korzeń, 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); }> Wyjście
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>
Analiza złożoności operacji na drzewie binarnym
| Operacje | Złożoność czasu | Złożoność przestrzeni |
|---|---|---|
| Wprowadzenie | NA) | NA) |
| Zamów w przedsprzedaży | NA) | NA) |
Przeprawa nieuporządkowana | NA) | NA) |
| Przesyłka pocztowa | NA) | NA) |
| Przechodzenie przez poziom zamówienia | NA) | NA) |
Usunięcie cienki algorytm | NA) | NA) |
Badawczy | NA) | NA) |
Możemy użyć Przejście Morrisa przejść przez wszystkie węzły drzewa binarnego w czasie O(1).
Zalety drzewa binarnego
- Efektywne wyszukiwanie: Drzewa binarne są wydajne przy wyszukiwaniu określonego elementu, ponieważ każdy węzeł ma co najwyżej dwa węzły podrzędne, co pozwala na Wydajność pamięci: Drzewa binarne wymagają mniej pamięci w porównaniu do innych struktur danych drzewiastych, dlatego są wydajne pod względem pamięci.
- Drzewa binarne są stosunkowo łatwe do wdrożenia i zrozumienia, ponieważ każdy węzeł ma co najwyżej dwoje dzieci, lewe i prawe dziecko.
Wady drzewa binarnego
- Ograniczona struktura: Drzewa binarne są ograniczone do dwóch węzłów podrzędnych na węzeł, co może ograniczać ich użyteczność w niektórych zastosowaniach. Na przykład, jeśli drzewo wymaga więcej niż dwóch węzłów podrzędnych na węzeł, bardziej odpowiednia może być inna struktura drzewa.
- Niezrównoważone drzewa: Niezrównoważone drzewa binarne, w których jedno poddrzewo jest znacznie większe od drugiego, mogą prowadzić do nieefektywnych operacji wyszukiwania. Może się to zdarzyć, jeśli drzewo nie jest odpowiednio zrównoważone lub jeśli dane są wstawiane w kolejności nielosowej.
- Nieefektywność przestrzenna: Drzewa binarne mogą być nieefektywne przestrzennie w porównaniu z innymi strukturami danych. Dzieje się tak dlatego, że każdy węzeł wymaga dwóch wskaźników podrzędnych, co w przypadku dużych drzew może powodować znaczne obciążenie pamięci.
- Niska wydajność w najgorszych scenariuszach: W najgorszym przypadku drzewo binarne może ulec zdegenerowaniu lub wypaczeniu, co oznacza, że każdy węzeł ma tylko jedno dziecko. W takim przypadku operacje wyszukiwania mogą spaść do złożoności czasowej O(n), gdzie n jest liczbą węzłów w drzewie.
Zastosowania drzewa binarnego
- Można do tego wykorzystać drzewo binarne reprezentują dane hierarchiczne .
- Drzewa kodujące Huffmana są wykorzystywane w algorytmy kompresji danych .
- Kolejka priorytetowa to kolejne zastosowanie drzewa binarnego służące do wyszukiwania maksimum lub minimum w złożoności czasowej O(1).
- Przydatne przy indeksowaniu segmentowanym w bazie danych, przydatne przy przechowywaniu pamięci podręcznej w systemie,
- Drzewa binarne można wykorzystać do implementacji drzew decyzyjnych, czyli rodzaju algorytmu uczenia maszynowego używanego do klasyfikacji i analizy regresji.
Często zadawane pytania dotyczące drzewa binarnego
1. Co to jest drzewo binarne?
Drzewo binarne to nieliniowa struktura danych składająca się z węzłów, z których każdy ma co najwyżej dwoje dzieci (lewe i prawe dziecko).
2. Jakie są rodzaje drzew binarnych?
Drzewa binarne można podzielić na różne typy, w tym pełne drzewa binarne, kompletne drzewa binarne, doskonałe drzewa binarne, zrównoważone drzewa binarne (takie jak drzewa AVL i drzewa czerwono-czarne) oraz zdegenerowane (lub patologiczne) drzewa binarne.
ciąg Java do tablicy
3. Jaka jest wysokość drzewa binarnego?
Wysokość drzewa binarnego to długość najdłuższej ścieżki od węzła głównego do węzła liścia. Reprezentuje liczbę krawędzi na najdłuższej ścieżce od węzła głównego do węzła liścia.
4. Jaka jest głębokość węzła w drzewie binarnym?
Głębokość węzła w drzewie binarnym to długość ścieżki od węzła głównego do tego konkretnego węzła. Głębokość węzła głównego wynosi 0.
5. Jak wykonać przechodzenie przez drzewo binarne?
Przechodzenie przez drzewo binarne można wykonać na różne sposoby: przechodzenie w kolejności, przechodzenie w kolejności przed zamówieniem, przechodzenie po zamówieniu i przechodzenie w kolejności poziomów (znane również jako przechodzenie wszerz).
6. Co to jest przejście Inorder w drzewie binarnym?
W przechodzeniu Inorder węzły są odwiedzane rekurencyjnie w następującej kolejności: lewe dziecko, korzeń, prawe dziecko. To przechodzenie powoduje, że węzły są odwiedzane w niemalejącej kolejności w drzewie wyszukiwania binarnego.
7. Co to jest przeglądanie zamówienia w przedsprzedaży w drzewie binarnym?
W przypadku przeglądania w przedsprzedaży węzły są odwiedzane rekurencyjnie w następującej kolejności: korzeń, lewe dziecko, prawe dziecko. To przejście powoduje, że węzeł główny jest pierwszym odwiedzanym węzłem.
8. Co to jest przechodzenie postordera w drzewie binarnym?
W trybie Postorder węzły są odwiedzane rekurencyjnie w następującej kolejności: lewe dziecko, prawe dziecko i korzeń. To przejście powoduje, że węzeł główny jest ostatnim węzłem odwiedzanym.
9. Jaka jest różnica pomiędzy drzewem binarnym a drzewem wyszukiwania binarnego?
Drzewo binarne to hierarchiczna struktura danych, w której każdy węzeł ma co najwyżej dwoje dzieci, podczas gdy drzewo poszukiwań binarnych to rodzaj drzewa binarnego, w którym lewe dziecko węzła zawiera wartości mniejsze niż wartość węzła, a prawe dziecko zawiera wartości większa niż wartość węzła.
10. Co to jest zrównoważone drzewo binarne?
Zrównoważone drzewo binarne to drzewo binarne, w którym wysokość lewego i prawego poddrzewa każdego węzła różni się co najwyżej o jeden. Zrównoważone drzewa pomagają w utrzymaniu wydajnych operacji, takich jak wyszukiwanie, wstawianie i usuwanie, przy złożoności czasowej bliskiej O (log n).
Wniosek:
Drzewo jest hierarchiczną strukturą danych. Główne zastosowania drzew obejmują utrzymywanie danych hierarchicznych, zapewnianie umiarkowanego dostępu oraz operacje wstawiania/usuwania. Drzewa binarne to szczególne przypadki drzew, w których każdy węzeł ma co najwyżej dwoje dzieci.
Powiązane artykuły:
- Właściwości drzewa binarnego
- Rodzaje drzew binarnych