Attraversamenti degli alberi (in ordine, preordine e postordine) con esempi

Cos'è l'attraversamento degli alberi?

Nella struttura ad albero dei dati, attraversamento significa visitare i nodi in un modo specifico. Esistono nodi2 tipi di attraversamenti. Generalmente questo tipo di attraversamento si basa sull'albero binario. Un albero binario significa che ogni nodo può avere un massimo di 2 nodi.

Un albero binario è una struttura dati ben nota. C'è anche un albero di ricerca binaria (BST). Questo tipo di attraversamento viene utilizzato per vari scopi. L'attraversamento dell'ordine di livello viene utilizzato per calcolare la profondità tra due nodi. Esiste un altro tipo di albero chiamato “AVL”, dove è necessario calcolare l'altezza di un nodo. Possiamo rappresentare un albero binario nell'array, ma per l'ottimizzazione della memoria utilizzeremo la struttura e il puntatore per fare riferimento al nodo successivo.

Tipi di attraversamento degli alberi

Come abbiamo discusso alberi binari, ora discutiamo i singoli tipi di attraversamenti. A seconda dei tipi, esistono due tipi di attraversamento. In precedenza abbiamo menzionato la necessità dell'ordine dei livelli o dell'attraversamento in ampiezza. Ora Traversata in profondità così come l'ordine post viene utilizzato per l'eliminazione di un nodo (ne parleremo più avanti), il preordine viene utilizzato per copiare un albero binario e "inorder" attraverserà l'albero in modo non decrescente.

  • Traversata in ampiezza
  • Traversata in profondità
  • Viaggio in preordine
  • Attraversamento post-ordine
  • Attraversamento in ordine

Traversata in ampiezza

È anche noto come attraversamento level-order. Consideriamo il seguente albero per dimostrare l'attraversamento level-order.

Traversata in ampiezza

Quindi, inizieremo dal nodo radice “1”. Verrà contrassegnato come livello 1. Quindi l'algoritmo andrà a tutti i figli del nodo corrente. Visiteremo ora i nodi 2 e 3. Saranno contrassegnati come livello 2.

Dopodiché, poiché abbiamo 2 nodi nel livello 2, visiteremo anche i loro figli. Quindi visiteremo 5,6,8,7 e li contrassegneremo come livello 3. Ecco una cosa di cui non parlo,

Livello del nodo = livello del nodo genitore + 1

Livello 1: 1

Livello 2: 2 3

Livello 3: 5 6 8 7

Un algoritmo simile viene utilizzato per il BFS (Prima ricerca in ampiezza).

Ecco lo pseudocodice per l'attraversamento dell'ordine di livello:

level_order(node)
Q → Queue()
Q.push(node)
while !Q.empty():
    current_node = Q.pop()
    print current_node.value
# Checking if the current node have any child or not
if current_node.left is not NULL:
    Q.push(current_node.left)
if current_node.right is not NULL:
    Q.push(current_node.right)

Albero Bianry trasversale in ordine

Facciamo lo stesso esempio di prima. In questo tipo di attraversamento visitiamo prima il sottoalbero sinistro, poi la radice e infine il sottoalbero destro. Per facilità di ricordare, possiamo dire che l'ordine va come sinistra-radice-destra.

Albero Bianry trasversale in ordine

Per l'intero albero, diciamo che la radice è 1. Ora seguirà l'algoritmo:

  • Visita il sottoalbero sinistro del nodo 1.
  • Il nodo corrente è 2 (poiché è il sottoalbero sinistro di 1)

Albero Bianry trasversale in ordine

  • Visita il sottoalbero sinistro di 2. Il nodo corrente questa volta sarà 5.
  • Passando a 5, non ha figli, quindi il nodo 5 verrà contrassegnato come visitato. Tornerà al nodo genitore; che è 2.
  • Quando viene visitato il sottoalbero sinistro di 2, ora verrà visitato anche 2.
  • algoritmo sposterà il nodo corrente nel sottoalbero destro del nodo 2, che è il nodo 6. Dopo aver visitato il nodo 6. Si sposterà al nodo genitore 2.
  • Una volta visitato il nodo 2, ora visiteremo il genitore di 2; che è il nodo 1.
  • Successivamente visiteremo il sottoalbero destro.

Quindi la traversata finale sarà simile a questa:

In ordine: 5 → 2 → 6 → 1 → 8 → 3 → 7

Ecco lo pseudocodice per l'attraversamento in ordine:

InOrder(node):
  if node is not null:
    InOrder(node.left)
  print node.value
    InOrder(node.right)

Questo è l'algoritmo ricorsivo per l'attraversamento in ordine. Per il Albero di ricerca binario (BST), L'attraversamento in ordine fornisce la matrice ordinata di valori.

Attraversamento post-ordine

In questo attraversamento, attraverseremo prima il sottoalbero più a sinistra, poi quello più a destra dopo la radice. Tutti gli attraversamenti saranno in Post-Order. Dimostriamo un esempio:

Attraversamento post-ordine

Qui per root = 1,

  • Andremo prima al sottoalbero di sinistra. Quindi la radice diventerà 2.
  • Quindi 2 ha lasciato il sottoalbero, quindi andremo al nodo 5. Ora la radice è 5.
  • Non ha un sottoalbero sinistro, né ha un sottoalbero destro. Quindi, ora contrassegneremo il nodo 5 come visitato e andremo al suo nodo genitore.

Attraversamento post-ordine

  • Ora la radice è 2 e il suo sottoalbero sinistro è completamente visitato. Ci sposteremo ora al sottoalbero destro. Quindi la radice diventa 6.
  • Poiché il nodo 6 non ha sottoalberi sinistro e destro, contrassegneremo il nodo 6 visitato e ci sposteremo al nodo genitore 2.
  • Ora, sia il sottoalbero sinistro che quello destro vengono visitati per il nodo 2. Anche questo verrà contrassegnato come visitato.
  • Ci sposteremo al genitore del nodo 2, che è il nodo 1.
  • Il sottoalbero di sinistra viene visitato per la radice 1. Ora, analogamente, visiteremo il sottoalbero di destra.

Attraversamento post-ordine

Il cerchio contrassegnato è il sottoalbero destro. Ora visiteremo il sottoalbero di destra come abbiamo visitato quello di sinistra. Successivamente visiteremo il nodo. Quindi la traversata finale sarà:

PostOrdine: 5 → 6 → 2 → 8 → 7 → 3 → 1

Ecco lo pseudocodice per l'attraversamento post-ordine:

PostOrder(node):
    if node is not null:
       PostOrder(node.left)
       PostOrder(node.right)
       print node.value

Traversata del preordine

Per l'attraversamento del preordine, l'algoritmo visiterà prima il nodo radice, dopodiché si sposterà rispettivamente nel sottoalbero sinistro e destro. Per facilità di comprensione, possiamo pensare a visite trasversali di preordine come radice → sinistra-destra.

Traversata del preordine

Quindi, selezioniamo il nodo 1 come radice.

  • Secondo l'algoritmo, verrà scoperta prima la radice, poi quella sinistra e infine quella destra.
  • Quindi visiteremo la radice 1. Quindi ci sposteremo al sottoalbero sinistro. La radice diventa 2.
  • Visiteremo il nodo 2 e ci sposteremo al suo sottoalbero sinistro. Quindi la radice diventa 3.
  • Visitiamo il nodo 3, quindi ci spostiamo al suo nodo genitore. Ora vengono visitati il ​​nodo 2 e il suo sottoalbero sinistro. È ora di visitare il sottoalbero giusto.
  • Ci sposteremo sul sottoalbero destro, la radice diventa 4. Visiteremo 4. Poiché 4 non ha un nodo figlio, ci sposteremo sul suo genitore.
  • Ora la radice è 2 e viene visitata insieme ai suoi sottoalberi sinistro e destro. Quindi, ci sposteremo al suo nodo genitore. Ora la radice diventa 1.
  • Allo stesso modo, visiteremo il sottoalbero destro.

Preordine: 1 → 2 → 3 → 4 → 5 → 6 → 7

Ecco lo pseudocodice per l'attraversamento post-ordine:

PreOrder(node):
   if node is not null:
     print node.value
         PreOrder(node.left)
         PreOrder(node.right)

implementazione in Python

class Node:
    def __init__(self, item):
    self.left = None
self.right = None
self.val = item
# creating a tree data structure
def inorder(root):
#checking if the root is null or not
if root:
    inorder(root.left)
# recursively calling left subtree
print(str(root.val) + " ", end = '')
inorder(root.right)
# recursively calling right subtree
def postorder(root):
    if root:
    postorder(root.left)
postorder(root.right)
print(str(root.val) + " ", end = '')
def preorder(root):
    if root:
    print(str(root.val) + " ", end = '')
preorder(root.left)
preorder(root.right)
def levelOrder(root):
    queue = list()
queue.append(root)
while len(queue) & gt;
0:
    current = queue[0]
queue = queue[1: ]
print(str(current.val) + " ", end = "")
if current.left:
    queue.append(current.left)
if current.right:
   queue.append(current.right)
root = Node(1)
root.left = Node(2)
root.right = Node(3)
root.left.left = Node(4)
root.left.right = Node(5)
root.right.left = Node(6)
root.right.right = Node(7)
print("\nLevelOrder traversal:\t", end = " ")
levelOrder(root)
print("\nInorder traversal:\t", end = " ")
inorder(root)
print("\nPreorder traversal:\t", end = " ")
preorder(root)
print("\nPostorder traversal:\t", end = " ")
postorder(root)

Produzione:

LevelOrder traversal:  1 2 3 4 5 6 7
Inorder traversal:     4 2 5 1 6 3 7
Preorder traversal:    1 2 4 5 3 6 7
Postorder traversal:   4 5 2 6 7 3 1

Implementazione in C

#include <stdio.h>
#include <stdlib.h>
struct node {
   int value;
   struct node* left;
   struct node* right;
};
// Inorder traversal
void InOrder(struct node* root) {
   if (root == NULL) return;
   InOrder(root->left);
   printf("%d ", root->value);
   InOrder(root->right);
}
// PreOrder traversal
void PreOrder(struct node* root) {
  if (root == NULL) return;
  printf("%d ", root->value);
  PreOrder(root->left);
  PreOrder(root->right);
}
// PostOrder traversal
void PostOrder(struct node* root) {
  if (root == NULL) return;
  PostOrder(root->left);
  PostOrder(root->right);
  printf("%d ", root->value);
}
// Create a new Node
struct node* createNode(int value) {
  struct node* newNode = malloc(sizeof(struct node));
  newNode->value = value;
  newNode->left = NULL;
  newNode->right = NULL;
  return newNode;
}
int main() {
  struct node* root = createNode(1);
  root->left = createNode(2);
  root->right = createNode(3);
  root->left->left = createNode(4);
  root->left->right = createNode(5);
  root->right->left = createNode(6);
  root->right->right = createNode(7);
  printf("Inorder traversal:\t");
  InOrder(root);
  printf("\PreOrder traversal:\t");
  PreOrder(root);
  printf("\nPostOrder traversal:\t");
  PostOrder(root);
}

Produzione:

Inorder traversal: 4 2 5 1 6 3 7
Preorder traversal: 1 2 4 5 3 6 7
Postorder traversal: 4 5 2 6 7 3 1

Implementazione di C++ (Utilizzando std:queue per l'ordine dei livelli)

#include <stdio.h>
#include <stdlib.h>
#include<queue>
typedef struct node {
  int value;
  struct node* left;
  struct node* right;
}node;
// Inorder traversal
void InOrder(struct node* root) {
  if (root == NULL) return;
  InOrder(root->left);
  printf("%d ", root->value);
  InOrder(root->right);
}
// PreOrder traversal
void PreOrder(struct node* root) {
  if (root == NULL) return;
  printf("%d ", root->value);
  PreOrder(root->left);
  PreOrder(root->right);
}
// PostOrder traversal
void PostOrder(struct node* root) {
  if (root == NULL) return;
  PostOrder(root->left);
  PostOrder(root->right);
  printf("%d ", root->value);
}
void LevelOrder(struct node* root){
   std::queue<struct node*> Q;
   Q.push(root);
   while(!Q.empty()){
   struct node* current = Q.front();
   Q.pop();
   printf("%d ",current->value);
 if(current->left)
   Q.push(current->left);
 if(current->right)
   Q.push(current->right);
  }
}
// Create a new Node
struct node* createNode(int value) {
  struct node* newNode = new node();
  newNode->value = value;
  newNode->left = NULL;
  newNode->right = NULL;
  return newNode;
}
int main() {
  struct node* root = createNode(1);
  root->left = createNode(2);
  root->right = createNode(3);
  root->left->left = createNode(4);
  root->left->right = createNode(5);
  root->right->left = createNode(6);
  root->right->right = createNode(7);
  printf("Level Order traversal:\t");
  LevelOrder(root);
  printf("\nInorder traversal:\t");
  InOrder(root);
  printf("\nPreOrder traversal:\t");
  PreOrder(root);
  printf("\nPostOrder traversal:\t");
  PostOrder(root);
}
LevelOrder traversal:  1 2 3 4 5 6 7
Inorder traversal:     4 2 5 1 6 3 7
Preorder traversal:    1 2 4 5 3 6 7
Postorder traversal:   4 5 2 6 7 3 1