[Explication détaillée du tutoriel sur l'arbre binaire et implémentation de l'arbre binaire en langage C/C++]

arbre binaire

Un arbre binaire est une structure de données arborescente spéciale dans laquelle chaque nœud a au plus deux nœuds enfants. Un nœud est appelé nœud parent et deux nœuds enfants sont appelés respectivement nœud enfant gauche et nœud enfant droit.

1. Qu'est-ce qu'un arbre binaire

Un arbre binaire est une structure de données arborescente spéciale dans laquelle chaque nœud a au plus deux nœuds enfants. Chaque nœud contient un élément de données et des pointeurs vers ses nœuds enfants gauche et droit. La valeur du nœud enfant gauche est inférieure ou égale à la valeur du nœud parent, et la valeur du nœud enfant droit est supérieure à la valeur du nœud parent. Cette propriété rend les arbres binaires très efficaces pour les opérations de recherche, d'insertion et de suppression.

     A
    / \
   B   C
  / \   \
 D   E   F

Les arbres binaires sont souvent utilisés pour modéliser des données avec une structure hiérarchique. Certaines de ses applications courantes incluent des algorithmes de recherche (tels que des arbres de recherche binaires), des arbres d'expression, des arbres de codage Huffman, etc. Dans un arbre binaire, nous pouvons utiliser différentes méthodes de parcours pour visiter les nœuds, y compris le parcours pré-ordre, le parcours dans l'ordre et le parcours post-ordre .

Deuxièmement, la méthode de parcours d'arbre binaire

1. Traversée de la précommande

À partir du nœud racine, visitez d'abord le nœud racine, puis effectuez de manière récursive une traversée de préordre sur les sous-arbres gauche et droit. Ce parcours peut être utilisé pour répliquer l'intégralité de l'arborescence.

Supposons que nous ayons l'arbre binaire suivant :

     1
    / \
   2   3
  / \   \
 4   5   6

Tout d'abord, nous visitons le nœud racine 1, puis parcourons le sous-arbre de gauche. Le nœud racine du sous-arbre gauche est 2, nous continuons à le visiter, puis traversons son sous-arbre gauche. Le nœud racine du sous-arbre gauche est 4, nous continuons à le visiter, puis constatons qu'il n'a pas de sous-arbres gauche et droit, nous retournons donc au nœud 2, puis traversons son sous-arbre droit.

Le nœud racine du sous-arbre droit est 5, nous continuons à le visiter, puis constatons qu'il n'a pas de sous-arbres gauche et droit, nous retournons donc au nœud 2, puis retournons au nœud racine 1, puis traversons le sous-arbre droit de le nœud racine.

Le nœud racine du sous-arbre droit est 3, nous continuons à le visiter, puis traversons son sous-arbre gauche. Le sous-arbre de gauche est vide, nous retournons donc au nœud 3, puis parcourons son sous-arbre de droite.

Le nœud racine du sous-arbre droit est 6, nous continuons à le visiter, puis constatons qu'il n'a pas de sous-arbres gauche et droit, nous retournons donc au nœud 3, puis retournons au nœud racine 1, et la traversée se termine.

最终的先序遍历结果是:1 2 4 5 3 6

Ce qui suit est un schéma des étapes spécifiques de la traversée de préordre :

     1
    / \
   2   3
  / \   \
 4   5   6
  1. visiter le nœud racine 1
  2. parcourir le sous-arbre de gauche
    • visiter le nœud racine 2
    • parcourir le sous-arbre de gauche
      • visiter le nœud racine 4
      • Si le sous-arbre de gauche est vide, retourne
    • parcourir le sous-arbre de droite
      • visiter le nœud racine 5
      • Si le sous-arbre de gauche est vide, retourne
  3. parcourir le sous-arbre de droite
    • visiter le nœud racine 3
    • Parcourir le sous-arbre de gauche (vide, retour)
    • parcourir le sous-arbre de droite
      • visiter le nœud racine 6
      • Si le sous-arbre de gauche est vide, retourne
最终的先序遍历结果是:1 2 4 5 3 6

2. Parcours dans l'ordre

Le parcours dans l'ordre est un moyen de parcourir un arbre binaire. L'ordre de parcours est : en partant du nœud racine, effectuez d'abord de manière récursive un parcours dans l'ordre sur le sous-arbre gauche, puis visitez le nœud racine, et enfin effectuez de manière récursive un parcours dans l'ordre sur le sous-arbre droit. Pour les arbres de recherche binaires, le parcours dans l'ordre peut obtenir une sortie ascendante.

Voici un exemple d'arbre binaire :

      1
    /   \
   2     3
  / \   / \
 4   5 6   7
中序遍历的结果为:4, 2, 5, 1, 6, 3, 7

Le processus de parcours dans l'ordre peut être implémenté à l'aide de la récursivité ou de la pile. Les deux méthodes sont décrites en détail ci-dessous.

(1) Méthode récursive

La récursivité est le moyen le plus simple de le faire. Les étapes spécifiques sont les suivantes :

  1. Renvoie si le nœud actuel est vide.
  2. Traverser récursivement le sous-arbre gauche du nœud actuel.
  3. Visitez le nœud actuel.
  4. Traverser récursivement le sous-arbre droit du nœud actuel.

Voici un exemple de code pour le parcours dans l'ordre à l'aide de la récursivité :

#include <stdio.h>
#include <stdlib.h>

struct Node {
    
    
    int val;
    struct Node* left;
    struct Node* right;
};

void inorderTraversal(struct Node* root) {
    
    
    if (root == NULL) {
    
    
        return;
    }
    inorderTraversal(root->left);
    printf("%d ", root->val);
    inorderTraversal(root->right);
}

(2) méthode de pile

La méthode de pile utilise une pile pour faciliter le processus de parcours. Les étapes spécifiques sont les suivantes :

  1. Initialise une pile vide et un pointeur vers le nœud racine.
  2. Lorsque la pile n'est pas vide ou que le pointeur n'est pas vide, procédez comme suit :
    • Si le pointeur n'est pas nul, poussez le pointeur sur la pile et pointez le pointeur sur son sous-arbre gauche.
    • Si le pointeur est vide, faites apparaître l'élément supérieur de la pile et accédez-y, puis pointez le pointeur sur son sous-arbre droit.
  3. Lorsque la pile est vide et que le pointeur est vide, le parcours se termine.

Voici un exemple de code pour le parcours dans l'ordre à l'aide de la méthode de pile :

#include <stdio.h>
#include <stdlib.h>

struct Node {
    
    
    int val;
    struct Node* left;
    struct Node* right;
};

void inorderTraversal(struct Node* root) {
    
    
    struct Node* stack[1000];
    int top = -1;
    struct Node* curr = root;
    while (top != -1 || curr != NULL) {
    
    
        if (curr != NULL) {
    
    
            stack[++top] = curr;
            curr = curr->left;
        } else {
    
    
            curr = stack[top--];
            printf("%d ", curr->val);
            curr = curr->right;
        }
    }
}

Qu'il s'agisse de la méthode récursive ou de la méthode de la pile, leur complexité temporelle est O(n), où n est le nombre de nœuds dans l'arbre binaire.

3. Traversée post-commande

La traversée post-ordre (Postorder Traversal) est une méthode de traversée d'arbre binaire. Son ordre de traversée consiste à traverser d'abord le sous-arbre gauche, puis à traverser le sous-arbre droit et enfin à visiter le nœud racine. Cette méthode de parcours est souvent utilisée pour la récupération de mémoire libre et les appels de destructeur .

Voici un exemple d'arbre binaire :

      1
     / \
    2   3
   / \   \
  4   5   6
  

Selon l'ordre de parcours post-ordre, le sous-arbre gauche doit être parcouru en premier, puis le sous-arbre droit et enfin le nœud racine doit être visité. Ainsi, le résultat du parcours post-ordre de l'arbre binaire est :

4 -> 5 -> 2 -> 6 -> 3 -> 1

Ensuite, nous utilisons le langage C pour implémenter le parcours post-ordre de l'arbre binaire.

Tout d'abord, nous devons définir la structure de l'arbre binaire, y compris la valeur du nœud et les pointeurs vers les nœuds enfants gauche et droit.

#include <stdio.h>
#include <stdlib.h>

// 定义二叉树的结构
struct TreeNode {
    
    
    int val;
    struct TreeNode* left;
    struct TreeNode* right;
};

Ensuite, nous avons besoin d'une fonction pour créer un nouveau nœud d'arbre binaire.

// 创建一个新的二叉树节点
struct TreeNode* createNode(int val) {
    
    
    struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
    newNode->val = val;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

Ensuite, implémentons la fonction de parcours post-ordre de l'arbre binaire.

// 后序遍历二叉树
void postorderTraversal(struct TreeNode* root) {
    
    
    if (root == NULL) {
    
    
        return;
    }
    postorderTraversal(root->left);   // 遍历左子树
    postorderTraversal(root->right);  // 遍历右子树
    printf("%d ", root->val);         // 访问根节点
}

Dans la fonction de parcours post-ordre, nous jugeons d'abord si le nœud actuel est vide et le renvoyons s'il est vide. Ensuite, parcourez récursivement le sous-arbre gauche et le sous-arbre droit tour à tour, et visitez enfin le nœud racine.

Enfin, nous pouvons créer un exemple d'arbre binaire dans la fonction principale et appeler la fonction de traversée post-ordre pour la parcourir.

int main() {
    
    
    // 创建示例二叉树
    struct TreeNode* root = createNode(1);
    root->left = createNode(2);
    root->right = createNode(3);
    root->left->left = createNode(4);
    root->left->right = createNode(5);
    root->right->right = createNode(6);

    // 后序遍历二叉树
    printf("后序遍历结果:");
    postorderTraversal(root);
    printf("\n");

    return 0;
}

En exécutant le code ci-dessus, la sortie est :

后序遍历结果:4 5 2 6 3 1

3. Caractéristiques de l'arbre binaire

En plus de la méthode de parcours, l'arbre binaire a quelques autres caractéristiques :

  • Arbre binaire complet : dans un arbre binaire complet, à l'exception de la dernière couche, les nœuds de chaque couche sont remplis et les nœuds de la dernière couche sont remplis dans l'ordre de gauche à droite. Cette structure arborescente peut être efficacement stockée dans un tableau.
  • Arbre binaire complet : Un arbre binaire complet est un arbre binaire dans lequel tous les nœuds ont 0 ou 2 nœuds enfants. Dans un arbre binaire complet, tous les nœuds feuilles sont au même niveau.
  • Arbre binaire équilibré : Dans un arbre binaire équilibré, la différence de hauteur entre le sous-arbre gauche et le sous-arbre droit de n'importe quel nœud est d'au plus 1. Cela maintient l'arborescence équilibrée et améliore l'efficacité des opérations de recherche, d'insertion et de suppression.
  • Arbre de recherche binaire : Un arbre de recherche binaire (BST) est un arbre binaire avec la propriété que pour tout nœud, tous les nœuds de son sous-arbre gauche ont des valeurs inférieures à lui, et tous les nœuds de son sous-arbre droit ont des valeurs inférieures à plus grand qu'il ne l'est. Cette propriété rend les opérations de recherche, d'insertion et de suppression dans un arbre de recherche binaire très efficaces.

Dans l'ensemble, un arbre binaire est une structure de données importante avec un large éventail d'applications. Ses nœuds peuvent avoir jusqu'à deux nœuds enfants, et différentes méthodes de traversée peuvent être utilisées pour accéder aux nœuds et les traiter.

Quatrièmement, implémentation de l'arbre binaire

1. Définir la structure

Tout d'abord, nous définissons une structure représentant les nœuds de l'arbre binaire. Chaque nœud se compose d'une partie de données et de deux parties de pointeur, pointant respectivement vers le nœud enfant gauche et le nœud enfant droit.

typedef struct Node {
    
    
    int data;
    struct Node *left;
    struct Node *right;
} Node;

2. Créer un nouveau nœud

Ensuite, nous implémentons une fonction de création d'un nouveau nœudcreateNode , qui est responsable de l'allocation de mémoire et de l'initialisation de la partie données du nœud. Si l'allocation de mémoire échoue, un message d'erreur est imprimé et le programme se termine.

Node *createNode(int data) {
    
    
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (newNode == NULL) {
    
    
        printf("内存分配失败!\n");
        exit(1);
    }
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

3. Insérer un nœud

Ensuite, nous implémentons une fonction pour insérer des nœudsinsertNode . Cette fonction insère le nouveau nœud dans la position appropriée en fonction de la valeur de données transmise. Si l'arbre est vide, la fonction crée un nouveau nœud et en fait le nœud racine. Sinon, insérez de manière récursive le nœud dans le sous-arbre gauche ou droit, selon la taille de la valeur de données.

Node *insertNode(Node *root, int data) {
    
    
    if (root == NULL) {
    
    
        return createNode(data);
    } else if (data < root->data) {
    
    
        root->left = insertNode(root->left, data);
    } else if (data > root->data) {
    
    
        root->right = insertNode(root->right, data);
    }
    return root;
}

Après cela, nous avons implémenté trois méthodes de parcours : parcours pré-ordre, parcours dans l'ordre et parcours post-ordre. Ces méthodes de parcours consistent à visiter les nœuds de l'arbre binaire dans un ordre spécifique.

4. Traversée de la précommande

La fonction de traversée de préordrepreOrder parcourt l'arbre dans l'ordre du nœud racine, du sous-arbre gauche et du sous-arbre droit, et imprime les valeurs de données des nœuds.

void preOrder(Node *root) {
    
    
    if (root != NULL) {
    
    
        printf("%d ", root->data);
        preOrder(root->left);
        preOrder(root->right);
    }
}

5. Parcours dans l'ordre

La fonction de parcours dans l'ordreinOrder parcourt l'arbre dans l'ordre du sous-arbre gauche, du nœud racine et du sous-arbre droit, et imprime la valeur de données du nœud.

void inOrder(Node *root) {
    
    
    if (root != NULL) {
    
    
        inOrder(root->left);
        printf("%d ", root->data);
        inOrder(root->right);
    }
}

6. Traversée post-commande

La fonction de parcours post-ordrepostOrder parcourt l'arbre dans l'ordre du sous-arbre gauche, du sous-arbre droit et du nœud racine, et imprime la valeur de données du nœud.

void postOrder(Node *root) {
    
    
    if (root != NULL) {
    
    
        postOrder(root->left);
        postOrder(root->right);
        printf("%d ", root->data);
    }
}

7. fonction principale

Enfin, dansmain la fonction, nous créons le nœud racine d'un arbre vide et insertNodeinsérons des données via la fonction. Ensuite, appelez respectivement les trois fonctions de parcours et imprimez les résultats du parcours.

int main() {
    
    
    Node *root = NULL;
    root = insertNode(root, 50);
    insertNode(root, 30);
    insertNode(root, 20);
    insertNode(root, 40);
    insertNode(root, 70);
    insertNode(root, 60);
    insertNode(root, 80);

    printf("先序遍历结果:");
    preOrder(root);

    printf("\n中序遍历结果:");
    inOrder(root);

    printf("\n后序遍历结果:");
    postOrder(root);

    return 0;
}

Ceci est le code détaillé d'une simple implémentation d'arbre binaire, j'espère que cela pourra vous aider à mieux comprendre comment fonctionne un arbre binaire et comment il est implémenté.

Cinq, code complet

#include <stdio.h>
#include <stdlib.h>

// 节点结构
typedef struct Node {
    
    
    int data;
    struct Node *left;
    struct Node *right;
} Node;

// 创建一个新节点
Node *createNode(int data) {
    
    
    Node *newNode = (Node *)malloc(sizeof(Node));
    if (newNode == NULL) {
    
    
        printf("内存分配失败!\n");
        exit(1);
    }
    newNode->data = data;
    newNode->left = NULL;
    newNode->right = NULL;
    return newNode;
}

// 插入节点
Node *insertNode(Node *root, int data) {
    
    
    if (root == NULL) {
    
    
        return createNode(data);
    } else if (data < root->data) {
    
    
        root->left = insertNode(root->left, data);
    } else if (data > root->data) {
    
    
        root->right = insertNode(root->right, data);
    }
    return root;
}

// 先序遍历
void preOrder(Node *root) {
    
    
    if (root != NULL) {
    
    
        printf("%d ", root->data);
        preOrder(root->left);
        preOrder(root->right);
    }
}

// 中序遍历
void inOrder(Node *root) {
    
    
    if (root != NULL) {
    
    
        inOrder(root->left);
        printf("%d ", root->data);
        inOrder(root->right);
    }
}

// 后序遍历
void postOrder(Node *root) {
    
    
    if (root != NULL) {
    
    
        postOrder(root->left);
        postOrder(root->right);
        printf("%d ", root->data);
    }
}

int main() {
    
    
    Node *root = NULL;
    root = insertNode(root, 50);
    insertNode(root, 30);
    insertNode(root, 20);
    insertNode(root, 40);
    insertNode(root, 70);
    insertNode(root, 60);
    insertNode(root, 80);

    printf("先序遍历结果:");
    preOrder(root);

    printf("\n中序遍历结果:");
    inOrder(root);

    printf("\n后序遍历结果:");
    postOrder(root);

    return 0;
}

Je suppose que tu aimes

Origine blog.csdn.net/qq_43884946/article/details/131475790
conseillé
Classement