Trægennemløbsteknikker omfatte forskellige måder at besøge alle træets noder på. I modsætning til lineære datastrukturer (Array, Linked List, Queue, Stacks osv.), som kun har én logisk måde at krydse dem på, kan træer krydses på forskellige måder. I denne artikel vil vi diskutere om alle trægennemløbsteknikker sammen med deres anvendelser.
arraylist sortering
Indholdsfortegnelse
- Betydning af trægennemgang
- Trægennemkørselsteknikker
- Inorder Traversal
- Forudbestil gennemkørsel
- Postordregennemgang
- Level Order Traversal
- Andre trægennemgange
- Ofte stillede spørgsmål (FAQ) om trægennemføringsteknikker
Trægennemgang betyder:
Trægennemgang refererer til processen med at besøge eller få adgang til hver knude i træet nøjagtigt én gang i en bestemt rækkefølge. Trægennemløbsalgoritmer hjælper os med at besøge og behandle alle træets noder. Da træet ikke er en lineær datastruktur, er der flere noder, som vi kan besøge efter at have besøgt en bestemt node. Der er flere trægennemløbsteknikker, som bestemmer rækkefølgen, hvori træets noder skal besøges.
Trægennemløbsteknikker:
En trædatastruktur kan krydses på følgende måder:
- Depth First Search eller DFS
- Inorder Traversal
- Forudbestil gennemkørsel
- Postordregennemgang
- Level Order Traversal eller Breadth First Search eller BFS
Inorder Traversal :
Inorder-gennemgang besøger noden i rækkefølgen: Venstre -> Rod -> Højre
Algoritme for Inorder Traversal:
Inorder (træ)
- Gå gennem det venstre undertræ, dvs. kald Inorder(venstre->undertræ)
- Besøg roden.
- Gå gennem det højre undertræ, dvs. kald Inorder(højre->undertræ)
Anvendelser af Inorder Traversal:
- I tilfælde af binære søgetræer (BST), giver Inorder traversal noder i ikke-faldende rækkefølge.
- For at få noder af BST i ikke-stigende rækkefølge, kan en variation af Inorder traversal, hvor Inorder traversal er reverseret, bruges.
- Inorder-gennemgang kan bruges til at evaluere aritmetiske udtryk gemt i udtrykstræer.
Kodestykke til gennemkørsel af ordrer:
C++ // Given a binary tree, print its nodes in inorder void printInorder(struct Node* node) { if (node == NULL) return; // First recur on left child printInorder(node->venstre); // Udskriv derefter dataene for node cout<< node->data<< ' '; // Now recur on right child printInorder(node->højre); }> C // Given a binary tree, print its nodes in inorder void printInorder(struct node* node) { if (node == NULL) return; // First recur on left child printInorder(node->venstre); // Udskriv derefter dataene for node printf('%d ', node->data); // Gentager nu på højre underordnede printInorder(node->right); }> Java void printInorder(Node node) { if (node == null) return; // First recur on left child printInorder(node.left); // Then print the data of node System.out.print(node.key + ' '); // Now recur on right child printInorder(node.right); }> Python3 # A function to do inorder tree traversal def printInorder(root): if root: # First recur on left child printInorder(root.left) # Then print the data of node print(root.val, end=' '), # Now recur on right child printInorder(root.right)>
C# // Given a binary tree, print // its nodes in inorder void printInorder(Node node) { if (node == null) return; // First recur on left child printInorder(node.left); // Then print the data of node Console.Write(node.key + ' '); // Now recur on right child printInorder(node.right); }> Javascript // Given a binary tree, print its nodes in inorder function printInorder(node) { if (node == null) return; // First recur on left child */ printInorder(node.left); // Then print the data of node console.log(node.key + ' '); // Now recur on right child printInorder(node.right); }> Produktion
Inorder traversal of binary tree is 4 2 5 1 3>
Tidskompleksitet: PÅ)
Hjælpeplads: Hvis vi ikke overvejer størrelsen af stakken for funktionskald, så O(1) ellers O(h), hvor h er højden af træet.
Forudbestil gennemkørsel :
Gennemgang af forudbestilling besøger noden i rækkefølgen: Rod -> Venstre -> Højre
Algoritme for Preorder Traversal:
Forudbestil (træ)
- Besøg roden.
- Gå gennem det venstre undertræ, dvs. kald Preorder (venstre->undertræ)
- Gå gennem det højre undertræ, dvs. kald Preorder (højre->undertræ)
Brug af Preorder Traversal:
- Preorder traversal bruges til at oprette en kopi af træet.
- Preorder traversal bruges også til at få præfiksudtryk på et udtrykstræ.
Kodestykke til gennemkørsel af forudbestilling:
C++ // Given a binary tree, print its nodes in preorder void printPreorder(struct Node* node) { if (node == NULL) return; // First print data of node cout << node->data<< ' '; // Then recur on left subtree printPreorder(node->venstre); // Nu igen på højre undertræ printPreorder(node->right); }> C // Given a binary tree, print its nodes in preorder void printPreorder(struct node* node) { if (node == NULL) return; // First print data of node printf('%d ', node->data); // Gentag derefter i venstre undertræ printPreorder(node->venstre); // Nu igen på højre undertræ printPreorder(node->right); }> Java // Given a binary tree, print its nodes in preorder void printPreorder(Node node) { if (node == null) return; // First print data of node System.out.print(node.key + ' '); // Then recur on left subtree printPreorder(node.left); // Now recur on right subtree printPreorder(node.right); }> Python3 # A function to do preorder tree traversal def printPreorder(root): if root: # First print the data of node print(root.val, end=' '), # Then recur on left child printPreorder(root.left) # Finally recur on right child printPreorder(root.right)>
C# // Given a binary tree, print // its nodes in preorder void printPreorder(Node node) { if (node == null) return; // First print data of node Console.Write(node.key + ' '); // Then recur on left subtree printPreorder(node.left); // Now recur on right subtree printPreorder(node.right); }> Javascript // Given a binary tree, print its nodes in preorder function printPreorder(node) { if (node == null) return; // First print data of node document.write(node.key + ' '); // Then recur on left subtree printPreorder(node.left); // Now recur on right subtree printPreorder(node.right); }> Produktion
Preorder traversal of binary tree is 1 2 4 5 3>
Tidskompleksitet: PÅ)
Hjælpeplads: Hvis vi ikke overvejer størrelsen af stakken for funktionskald, så O(1) ellers O(h), hvor h er højden af træet.
Postordregennemgang :
Postordre-gennemgang besøger noden i rækkefølgen: Venstre -> Højre -> Rod
Algoritme for postordergennemgang:
Algoritme Postordre (træ)
- Gå gennem det venstre undertræ, dvs. kald Postorder(venstre->undertræ)
- Gå gennem det højre undertræ, dvs. kald Postorder (højre->undertræ)
- Besøg roden
Anvendelser af Mailorder Traversal:
- Postordre-gennemgang bruges til at slette træet. Se spørgsmålet om sletning af et træ for detaljer.
- Postorder-gennemgang er også nyttig for at få postfix-udtrykket for et udtrykstræ.
- Postordre-gennemkørsel kan hjælpe med algoritmer til indsamling af affald, især i systemer, hvor manuel hukommelsesstyring bruges.
Kodestykke til postordregennemgang:
C++ // Given a binary tree, print its nodes according to the // 'bottom-up' postorder traversal. void printPostorder(struct Node* node) { if (node == NULL) return; // First recur on left subtree printPostorder(node->venstre); // Så går igen på højre undertræ printPostorder(node->højre); // Håndter nu nodecout<< node->data<< ' '; }> C // Given a binary tree, print its nodes according to the // 'bottom-up' postorder traversal. void printPostorder(struct node* node) { if (node == NULL) return; // First recur on left subtree printPostorder(node->venstre); // Så går igen på højre undertræ printPostorder(node->højre); // Håndter nu noden printf('%d ', node->data); }> Java // Given a binary tree, print its nodes according to the // 'bottom-up' postorder traversal. void printPostorder(Node node) { if (node == null) return; // First recur on left subtree printPostorder(node.left); // Then recur on right subtree printPostorder(node.right); // Now deal with the node System.out.print(node.key + ' '); }> Python3 # A function to do postorder tree traversal def printPostorder(root): if root: # First recur on left child printPostorder(root.left) # The recur on right child printPostorder(root.right) # Now print the data of node print(root.val, end=' '),>
C# // Given a binary tree, print its nodes according to // the 'bottom-up' postorder traversal. void printPostorder(Node node) { if (node == null) return; // First recur on left subtree printPostorder(node.left); // Then recur on right subtree printPostorder(node.right); // Now deal with the node Console.Write(node.key + ' '); }> Javascript // Given a binary tree, print its nodes according // to the 'bottom-up' postorder traversal function printPostorder(node) { if (node == null) return; // First recur on left subtree printPostorder(node.left); // Then recur on right subtree printPostorder(node.right); // Now deal with the node console.log(node.key + ' '); }> Produktion
Postorder traversal of binary tree is 4 5 2 3 1>
Level Order Traversal :
Level Order Traversal besøger alle noder, der er til stede på samme niveau, fuldstændigt, før du besøger det næste niveau.
Algoritme for niveauordregennemgang:
LevelOrder(træ)
- Opret en tom kø Q
- Sæt træets rodknude i kø til Q
- Loop mens Q ikke er tom
- Sæt en node i kø fra Q og besøg den
- Sæt det venstre underordnede knude i kø, hvis det findes
- Sæt det rigtige underordnede knudepunkt i kø, hvis det findes
Brug af niveaurækkefølge:
- Level Order Traversal bruges hovedsageligt som Breadth First Search til at søge eller behandle noder niveau-for-niveau.
- Level Order traversal bruges også til Træserialisering og deserialisering .
Kodestykke til niveauordregennemgang:
C++ // Iterative method to find height of Binary Tree void printLevelOrder(Node* root) { // Base Case if (root == NULL) return; // Create an empty queue for level order traversal queueq; // Sæt Root i kø og initialiser højden q.push(root); while (q.empty() == false) { // Udskriv forsiden af køen og fjern den fra køen Node* node = q.front(); cout<< node->data<< ' '; q.pop(); // Enqueue left child if (node->venstre != NULL) q.push(node->venstre); // Enqueue right child if (node->right != NULL) q.push(node->right); } }> C // Given a binary tree, print its nodes in level order // using array for implementing queue void printLevelOrder(struct node* root) { int rear, front; struct node** queue = createQueue(&front, &rear); struct node* temp_node = root; while (temp_node) { printf('%d ', temp_node->data); // Enqueue left child if (temp_node->left) enQueue(queue, &rear, temp_node->venstre); // Enqueue right child if (temp_node->right) enQueue(queue, &rear, temp_node->right); // Dequeue node og gør den temp_node temp_node = deQueue(queue, &front); } }> Java // Given a binary tree. Print // its nodes in level order // using array for implementing queue void printLevelOrder() { Queuekø = ny LinkedList(); queue.add(rod); mens (!queue.isEmpty()) { // poll() fjerner det nuværende hoved. Node tempNode = queue.poll(); System.out.print(tempNode.data + ' '); // Enqueue left child if (tempNode.left != null) { queue.add(tempNode.left); } // Enqueue right child if (tempNode.right != null) { queue.add(tempNode.right); } } }> Python3 # Iterative Method to print the # height of a binary tree def printLevelOrder(root): # Base Case if root is None: return # Create an empty queue # for level order traversal queue = [] # Enqueue Root and initialize height queue.append(root) while(len(queue)>0): # Udskriv forrest i køen og # fjern det fra køen print(queue[0].data, end=' ') node = queue.pop(0) # Sæt venstre underordnet i kø, hvis node.left ikke er Ingen: queue.append(node.left) # Sæt højre underord i kø, hvis node.right ikke er Ingen: queue.append(node.right)>
C# // Given a binary tree. Print // its nodes in level order using // array for implementing queue void printLevelOrder() { Queuekø = ny kø(); kø.Enqueue(rod); while (queue.Count != 0) { Node tempNode = queue.Dequeue(); Console.Write(tempNode.data + ' '); // Enqueue left child if (tempNode.left != null) { queue.Enqueue(tempNode.left); } // Enqueue right child if (tempNode.right != null) { queue.Enqueue(tempNode.right); } } }> JavaScript // Function to perform level order traversal of a binary tree function printLevelOrder(root) { // Create a deque to store nodes for traversal const queue = new Deque(); // Add the root node to the queue queue.enqueue(root); // Continue traversal until the queue is empty while (!queue.isEmpty()) { // Remove and get the first node from the queue const tempNode = queue.dequeue(); // Print the data of the current node console.log(tempNode.data + ' '); // Enqueue the left child if it exists if (tempNode.left !== null) { queue.enqueue(tempNode.left); } // Enqueue the right child if it exists if (tempNode.right !== null) { queue.enqueue(tempNode.right); } } }> Andre trægennemgange:
- Grænseoverskridelse
- Diagonal gennemkørsel
1. Grænseoverskridelse :
Grænseoverskridelse af et træ inkluderer:
- venstre grænse (knuder til venstre ekskl. bladknuder)
- blade (består kun af bladknuderne)
- højre grænse (knuder til højre ekskl. bladknuder)
Algoritme for grænseoverskridelse:
BoundaryTraversal(træ)
- Hvis root ikke er null:
- Udskriv roots data
- PrintLeftBoundary(rod->venstre) // Udskriv de venstre grænseknuder
- PrintLeafNodes(rod->venstre) // Udskriv bladknuderne i venstre undertræ
- PrintLeafNodes(root->right) // Udskriv bladknuderne i højre undertræ
- PrintRightBoundary(root->right) // Udskriv de rigtige grænseknuder
Brug af grænseoverskridelse:
- Grænseoverskridelse hjælper med at visualisere den ydre struktur af et binært træ, hvilket giver indsigt i dets form og grænser.
- Grænseoverskridelse giver mulighed for at få adgang til og ændre disse knudepunkter, hvilket muliggør operationer såsom beskæring eller omplacering af grænseknuder.
2. Diagonal gennemkørsel
I den diagonale gennemgang af et træ vil alle noderne i en enkelt diagonal blive udskrevet én efter én.
Algoritme for diagonal gennemløb:
DiagonalTraversal(træ):
- Hvis root ikke er null:
- Opret et tomt kort
- DiagonalTraversalUtil(rod, 0, M) // Kaldhjælperfunktion med indledende diagonalniveau 0
- For hvert nøgle-værdi-par (diagonalt niveau, noder) i M:
- For hver node i noder:
- Udskriv nodens data
DiagonalTraversalUtil(node, diagonalLevel, M):
- Hvis noden er null:
- Vend tilbage
- Hvis diagonalLevel ikke er til stede i M:
- Opret en ny liste i M for diagonalLevel
- Føj nodens data til listen på M[diagonalLevel]
- DiagonalTraversalUtil(node->venstre, diagonalLevel + 1, M) // Kør venstre barn med øget diagonalniveau
- DiagonalTraversalUtil(node->right, diagonalLevel, M) // Kør højre barn med samme diagonale niveau
Anvendelser af diagonal gennemkørsel:
- Diagonal traversal hjælper med at visualisere den hierarkiske struktur af binære træer, især i træbaserede datastrukturer som binære søgetræer (BST'er) og heap trees.
- Diagonal traversering kan bruges til at beregne stisummer langs diagonaler i et binært træ.
Ofte stillede spørgsmål (FAQ) om trægennemføringsteknikker:
1. Hvad er trægennemløbsteknikker?
Trægennemløbsteknikker er metoder, der bruges til at besøge og behandle alle noder i en trædatastruktur. De giver dig mulighed for at få adgang til hver node nøjagtigt én gang på en systematisk måde.
2. Hvad er de almindelige typer af trækrydsning?
De almindelige typer af trægennemgang er: Inorder traversal, Preorder traversal, Postorder traversal, Level order traversal (Bredth-First Search)
efterfølgende datatyper
3. Hvad er Inorder traversal?
Inorder traversal er en dybde-først traversal metode, hvor noder besøges i rækkefølgen: venstre undertræ, nuværende knudepunkt, højre undertræ.
4. Hvad er preorder traversal?
Preorder traversal er en dybde-først traversal metode, hvor noder besøges i rækkefølgen: nuværende node, venstre undertræ, højre undertræ.
5. Hvad er postordregennemkørsel?
Postorder traversal er en dybde-først traversal metode, hvor noder besøges i rækkefølgen: venstre undertræ, højre undertræ, nuværende knude.
6. Hvad er niveauordregennemgang?
Gennemgang af niveaurækkefølge, også kendt som Breadth-First Search (BFS), besøger noder niveau for niveau, startende fra roden og bevæger sig til næste niveau, før du krydser dybere.
7. Hvornår skal jeg bruge hver traversalteknik?
Inorder traversal bruges ofte til binære søgetræer for at få noder i sorteret rækkefølge.
Gennemgang af forudbestilling er nyttig til at oprette en kopi af træet.
Postorder traversal bruges almindeligvis i udtrykstræer til at evaluere udtryk.
Gennemgang af niveaurækkefølge er nyttig til at finde den korteste vej mellem noder.
8. Hvordan implementerer jeg trægennemløbsalgoritmer?
Trægennemløbsalgoritmer kan implementeres rekursivt eller iterativt, afhængigt af de specifikke krav og programmeringssprog, der bruges.
9. Kan trægennemløbsalgoritmer anvendes på andre trælignende strukturer?
Ja, trægennemløbsalgoritmer kan tilpasses til at krydse andre trælignende strukturer såsom binære dynger, n-ære træer og grafer repræsenteret som træer.
10. Er der nogen præstationsovervejelser, når man vælger en traversalteknik?
Ydeevneovervejelser afhænger af faktorer såsom træets størrelse og form, tilgængelig hukommelse og specifikke handlinger, der udføres under gennemkøring. Generelt kan valget af gennemløbsteknik påvirke effektiviteten af visse operationer, så det er vigtigt at vælge den bedst egnede metode til din specifikke brug.
Nogle andre vigtige tutorials:
- DSA Tutorial
- Tutorial til systemdesign
- Softwareudvikling køreplan
- Køreplan for at blive produktchef
- Lær SAP
- Lær SEO