La création et le parcours de l'arbre binaire implémenté par C++, la petite fille d'à côté comprend aussi l'ultra-introductif

Table des matières

arbre binaire 

caractéristiques

nature

Création d'arbre binaire

déclaration

créer

Opérateur d'adhésion ->

Création de lots

 Création d'arbre binaire complet

imprimer un arbre binaire

Création d'arbre binaire ordinaire

Parcours d'arbre binaire

parcours de séquence

traversée de précommande

Parcours dans l'ordre

traversée post-commande

méthode récursive

Comparaison des séquences avant, milieu et après

Traversée DFS

Termes liés à l'arbre

arbre binaire spécial

arbre binaire complet

arbre binaire complet


arbre binaire 

Un arbre est un ensemble fini de n(n≥0) nœuds. Dans tout arbre, il n'y a qu'un seul nœud spécifique appelé racine (Root); lorsque n>1, le reste des nœuds peut être divisé en m (m>0) comme un ensemble fini de T1, T2, ..., Tm ; chaque collection elle-même est un arbre, et est appelée le sous-arbre de la racine (SubTree).

Binary Tree (Binary Tree) est une structure arborescente ordonnée spéciale, tous les nœuds ont au plus 2 sous-arbres.

caractéristiques

(1) Chaque nœud a au plus deux sous-arbres ;
(2) Les sous-arbres de l'arbre binaire sont divisés en gauche et à droite ;
(3) L'ordre des sous-arbres ne peut pas être inversé arbitrairement (arbre ordonné).

nature

(1) Il y a au plus 2^(i-1) nœuds (i≥1) sur la ième couche de l'arbre binaire.
(2) Un arbre binaire de profondeur h contient au plus 2^h-1 nœuds (h≥1).
(3) S'il y a n0 nœuds feuilles et n2 nœuds de degré 2 dans tout arbre binaire, alors il doit y avoir n0=n2+1.
(4) Un arbre binaire complet à n nœuds a une profondeur log2n+1.
(5) Si un arbre binaire complet à n nœuds est numéroté séquentiellement (1≤i≤n),
alors, pour un nœud numéroté i (i≥1) : 
  lorsque i=1, le nœud est la racine, Il n'a pas de parent nœuds.
  Lorsque i>1, le numéro de nœud parent du nœud est i/2.
  Si 2i≤n, il y a un nœud gauche numéroté 2i, sinon il n'y a pas de nœud gauche.
  Si 2i+1≤n, il existe un nœud droit numéroté 2i+1, sinon il n'y a pas de nœud droit.


Création d'arbre binaire

déclaration

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

En langage C/C++, NULL est souvent utilisé pour représenter un pointeur nul.

La définition de NULL dans le fichier d'en-tête :

#ifndef NULL
    #ifdef __cplusplus
        #define NULL 0
    #else
        #define NULL ((void *)0)
    #endif
#endif

Autrement dit, en C++, NULL est défini comme une constante entière 0, tandis qu'en C, il est défini comme une constante de pointeur non typée (void*) 0 .

La norme C++11 ajoute un nouveau mot-clé nullptr pour représenter un pointeur nul.

Il est recommandé d'utiliser la déclaration d'arbre binaire suivante pour C++11 et supérieur :

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

créer

#include <iostream>

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

int main() {
	
    TreeNode* root = new TreeNode(1);
    root->left = new TreeNode(2);
    root->right = new TreeNode(3);
    root->right->left = new TreeNode(4);
    root->right->right = new TreeNode(5);

    return 0;
}

 Créer un résultat :

Opérateur d'adhésion ->

Un pointeur vers une structure ou un objet accède à ses membres. Lorsqu'un pointeur pointe vers une structure ou un objet, on l'appelle un pointeur de structure ou un pointeur d'objet. La valeur dans le pointeur de structure ou le pointeur d'objet est la première adresse de la structure ou de l'objet pointé. La structure ou l'objet est accessible via le pointeur de structure ou le pointeur d'objet.

La forme générale de la définition de variable de pointeur de structure est :

struct 结构体类型名 *指针名; //结构体指针
struct 结构体类型名 *指针名 = &一个结构体的名字; //结构体指针并赋初值
struct 结构体类型名 *指针名 = new struct 结构体类型名; //结构体指针并用new申请内存
struct 结构体类型名 *指针名 =(struct 结构体类型名 *)malloc(sizeof(struct 结构体类型名)) 
//结构体指针并用malloc申请内存 使用应包含头文件stdlib.h

Les sous-arborescences root->left, root->right sont également correctes La représentation de l'opération est également un opérateur membre. La différence entre les deux:

Opérateur point .  Le côté gauche doit utiliser l'opérateur d'adressage * pour obtenir la structure ou l'entité objet pointée par la racine du pointeur, telle que (*racine) ; par rapport à l'opérateur de membre en forme de flèche ->  , le côté gauche doit être un pointeur de structure, tel que root.

    TreeNode* root = new TreeNode(1);
    (*root).left = new TreeNode(2);
    (*root).right = new TreeNode(3);
    (*(*root).right).left = new TreeNode(4);
    (*(*root).right).right = new TreeNode(5);

Création de lots

L'exemple ci-dessus ne crée que des nœuds 5. Si vous souhaitez créer plus de nœuds, ajouter des nœuds un par un est compliqué à écrire ; vous pouvez utiliser des types de données itérables tels que des tableaux ou des conteneurs pour les créer par lots.

 Création d'arbre binaire complet

        _______1________
       /                \
    __2__             ___3___
   /     \           /       \
  4       5        _6        _7
 / \     / \      /  \      /  \
8   9   10  11   12   13   14   15

code:

#include <iostream>
#include <vector>
using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTree(vector<int>& nums)
{
	if (nums.empty()) return nullptr;
    TreeNode *root = new TreeNode(nums.front());
    vector<TreeNode*> q = {root};
    int i = 1;
    while(!q.empty() && i < nums.size())
    {
        TreeNode *cur = q.front();
        q.assign(q.begin() + 1, q.end());
        if(i < nums.size())
        {
            cur->left = new TreeNode(nums[i++]);
            q.push_back(cur->left);
        }
        if(i < nums.size())
        {
            cur->right = new TreeNode(nums[i++]);
            q.push_back(cur->right);
        }
    }
    return root;
}

int main()
{
    vector<int> nums = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    TreeNode *root = buildTree(nums);

    return 0;
}

Après la création, vous pouvez utiliser le code pour imprimer l'arbre binaire pour vérification : 

imprimer un arbre binaire

#include <iostream>
#include <vector>
using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTree(vector<int>& nums)
{
	if (nums.empty()) return nullptr;
    TreeNode *root = new TreeNode(nums.front());
    vector<TreeNode*> q = {root};
    int i = 1;
    while(!q.empty() && i < nums.size())
    {
        TreeNode *cur = q.front();
        q.assign(q.begin() + 1, q.end());
        if(i < nums.size())
        {
            cur->left = new TreeNode(nums[i++]);
            q.push_back(cur->left);
        }
        if(i < nums.size())
        {
            cur->right = new TreeNode(nums[i++]);
            q.push_back(cur->right);
        }
    }
    return root;
}

void levelOrderPrint(TreeNode* root)
{
    if(!root) return;
    vector<TreeNode*> q = {root};
    while(!q.empty())
    {
        int size = q.size();
        for(int i = 0; i < size; i++)
        {
            TreeNode *cur = q.front();
            q.assign(q.begin() + 1, q.end());
            cout << cur->val << " ";
            if(cur->left)
                q.push_back(cur->left);
            if(cur->right)
                q.push_back(cur->right);
        }
        cout << endl;
    }
}

int main()
{
    vector<int> nums;
    for (int i = 0; i < 15; i++)
    	nums.push_back(i+1);   
    TreeNode *root = buildTree(nums);
    levelOrderPrint(root);

    return 0;
}

sortir:

1
2 3
4 5 6
7 8 9 10 11 12 13 14 15

Le processus d'impression des nœuds d'arbre binaire un par un est appelé parcours, qui sera discuté plus tard.

Création d'arbre binaire ordinaire

L'arborescence suivante a 3 nœuds de moins que l'arborescence ci-dessus :

        _______1________
       /                \
    __2__             ___3___
   /     \           /       \
  4       5        _6         7
 /       /        /  \         \
8       10      12   13        15

Les nœuds vides sont généralement décrits par null, comme : {1,2,3,4,5,6,7,8,null,10,11,null,13,null,15}.

Afin de ne pas changer la description du tableau, utilisez le plus petit entier négatif pour définir null : #define null INT_MIN

code:

Augmente le jugement des nœuds vides if(i < nums.size() && nums[i] != null )

#include <iostream>
#include <vector>
#include <queue>
#define null INT_MIN
using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTree(vector<int>& nums)
{
    if (nums.empty()) return nullptr;
	TreeNode *root = new TreeNode(nums.front());
    queue<TreeNode*> q;
    q.push(root);
    int i = 1;
    while(!q.empty() && i < nums.size())
    {
        TreeNode *cur = q.front();
        q.pop();
        if(i < nums.size() && nums[i] != null)
        {
            cur->left = new TreeNode(nums[i]);
            q.push(cur->left);
        }
        i++;
        if(i < nums.size() && nums[i] != null)
        {
            cur->right = new TreeNode(nums[i]);
            q.push(cur->right);
        }
        i++;
    }
    return root;
}

void levelOrder(TreeNode* root)
{
    if(!root) return;
    queue<TreeNode*> q;
    q.push(root);
    while(!q.empty())
    {
        int size = q.size();
        for(int i = 0; i < size; i++)
        {
            TreeNode *cur = q.front();
            q.pop();
            cout << cur->val << " ";
            if(cur->left)
                q.push(cur->left);
            if(cur->right)
                q.push(cur->right);
        }
        cout << endl;
    }
}

int main()
{
    vector<int> nums = {1,2,3,4,5,6,7,8,null,10,11,null,13,null,15};
    TreeNode *root = buildTree(nums);
    levelOrder(root);
    
    return 0;
}

sortir: 

1
2 3
4 5 6 7
8 10 11 13 15

Le code ci-dessus utilise directement la file d'attente pour stocker les pointeurs de chaque nœud de l'arbre binaire. La file d'attente a des méthodes intégrées dédiées pop et push pour les opérations de file d'attente, c'est donc un peu plus pratique que l'opération de file d'attente simulée par vecteur dans l'exemple précédent.

Remarque : Le parcours de l'arbre binaire, tel que

Les opérations de file d'attente sont généralement traversées en largeur (BFS, Breath First Search )

L'opération de pile est généralement une traversée en profondeur d'abord (DFS, Depth First Search)


Parcours d'arbre binaire

Fait référence à la façon de patrouiller chaque nœud de l'arborescence selon un certain chemin de recherche, de sorte que chaque nœud soit visité une fois et une seule.
Les méthodes de traversée courantes sont : la traversée d'ordre de niveau, la traversée de pré-ordre, la traversée dans l'ordre et la traversée de post-ordre .

parcours de séquence

Si l'arbre binaire est vide, c'est une opération nulle, sinon l'accès s'effectue hiérarchiquement de haut en bas et de gauche à droite.

Résultats de la traversée : 1 [2 3] [4 5 6 7] [8 9 10 11 12 13 14 15]

Le code BFS pour le parcours de l'ordre des couches a été publié dans le chapitre ci-dessus sur l'impression d'arbres binaires . Voici un parcours de l'ordre des couches d'un arbre binaire écrit par récursivité que j'ai vu :

#include <iostream>
#include <vector>
#include <queue>
#define null INT_MIN
using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTree(vector<int>& nums)
{
    if (nums.empty()) return nullptr;
	TreeNode *root = new TreeNode(nums.front());
    queue<TreeNode*> q;
    q.push(root);
    int i = 1;
    while(!q.empty() && i < nums.size())
    {
        TreeNode *cur = q.front();
        q.pop();
        if(i < nums.size() && nums[i] != null)
        {
            cur->left = new TreeNode(nums[i]);
            q.push(cur->left);
        }
        i++;
        if(i < nums.size() && nums[i] != null)
        {
            cur->right = new TreeNode(nums[i]);
            q.push(cur->right);
        }
        i++;
    }
    return root;
}

int countNodesAtLevel(TreeNode* root, int level)
{
    if(root == nullptr) return 0;
    if(level == 0) return 1;
    return countNodesAtLevel(root->left, level - 1) + countNodesAtLevel(root->right, level - 1);
}

TreeNode* getNodeAtLevel(TreeNode* root, int level, int index)
{
    if(root == nullptr) return nullptr;
    if(level == 0)
    {
        if(index == 0) return root;
        else return nullptr;
    }
    TreeNode *left = getNodeAtLevel(root->left, level - 1, index);
    if(left != nullptr) return left;
    return getNodeAtLevel(root->right, level - 1, index - countNodesAtLevel(root->left, level - 1));
}

void levelOrder(TreeNode* root)
{
    int level = 0;
    while(true)
    {
        int cnt = countNodesAtLevel(root, level);
        if(cnt == 0) break;
        for(int i = 0; i < cnt; i++)
        {
            TreeNode *node = getNodeAtLevel(root, level, i);
            cout << node->val << " ";
        }
        cout << endl;
        level++;
    }
}

int main()
{
    vector<int> nums = {1,2,3,4,5,6,7,8,null,10,11,null,13,null,15};
    TreeNode *root = buildTree(nums);
    levelOrder(root);
    
    return 0;
}

traversée de précommande

Si l'arbre binaire est vide, c'est une opération nulle ;
sinon (1) visitez le nœud racine ; (2) parcourez le sous-arbre de gauche en préordre ; (3) parcourez le sous-arbre de droite en préordre.

Résultats de la traversée : 1 [2 [4 8 9] [5 10 11]] [3 [6 12 13] [7 14 15] "racine gauche et droite "

Parcours dans l'ordre

Si l'arbre binaire est vide, c'est une opération nulle ;
sinon (1) parcourir dans l'ordre le sous-arbre gauche ; (2) visiter le nœud racine ; (3) parcourir dans l'ordre le sous-arbre droit.

Résultat de la traversée : [[8 4 9] 2 [10 5 11]] 1 [[12 6 13] 3 [14 7 15]] "gauche racine droite "

traversée post-commande

Si l'arbre binaire est vide, il s'agit d'une opération nulle ;
sinon (1) parcourez le sous-arbre de gauche en post-ordre ; (2) parcourez le sous-arbre de droite en post-ordre ; (3) visitez le nœud racine.

Résultats de la traversée : [[8 9 4] [10 11 5] 2] [[12 13 6] [14 15 7] 3] 1 "racines gauche et droite "

méthode récursive

#include <iostream>
#include <vector>
#include <queue>
#define null INT_MIN
using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTree(vector<int>& nums)
{
    if (nums.empty()) return nullptr;
	TreeNode *root = new TreeNode(nums.front());
    queue<TreeNode*> q;
    q.push(root);
    int i = 1;
    while(!q.empty() && i < nums.size())
    {
        TreeNode *cur = q.front();
        q.pop();
        if(i < nums.size() && nums[i] != null)
        {
            cur->left = new TreeNode(nums[i]);
            q.push(cur->left);
        }
        i++;
        if(i < nums.size() && nums[i] != null)
        {
            cur->right = new TreeNode(nums[i]);
            q.push(cur->right);
        }
        i++;
    }
    return root;
}

void preOrderTraversal(TreeNode* root) {
    if (root == nullptr) {
	        return;
    }
    cout << root->val << " ";
    preOrderTraversal(root->left);
    preOrderTraversal(root->right);
}

void inOrderTraversal(TreeNode* root) {
    if (root == nullptr) {
	        return;
    }
    inOrderTraversal(root->left);
    cout << root->val << " ";
    inOrderTraversal(root->right);
}

void postOrderTraversal(TreeNode* root) {
    if (root == nullptr) {
	        return;
    }
    postOrderTraversal(root->left);
    postOrderTraversal(root->right);
    cout << root->val << " ";
}

int main()
{
    vector<int> nums;
    for (int i = 0; i < 15; i++)
    	nums.push_back(i+1);
    TreeNode *root = buildTree(nums);
    preOrderTraversal(root);
    cout << endl;
    inOrderTraversal(root);
    cout << endl;
    postOrderTraversal(root);
    cout << endl;
    
    return 0;
}

sortir:

1 2 4 8 9 5 10 11 3 6 12 13 7 14 15 8 4 9 2 10 5 11 1 12 6 13 3 14 7 15 8 9 4 10 11 5 2 12 13 6
14
15 7 3 1

Comparaison des séquences avant, milieu et après

L'ordre du code de base est la clé lors de la traversée, qui consiste à utiliser la mémoire de " gauche et droite ", " gauche et droite " et " racines gauche et droite " comme mentionné ci-dessus , et de comparer les positions de la gauche et de la droite nœuds de sous-arbre du nœud racine :

根左右——前序
    cout << root->val << " " ;
    preOrderTraversal(racine->gauche);
    preOrderTraversal(racine->droite);

左根右——中序
    inOrderTraversal(root->left);
    cout << root->val << " " ;
    inOrderTraversal(racine->droite);

左右根——后序
    postOrderTraversal(root->left);
    postOrderTraversal(racine->droite);
    cout << root->val << " " ;

En plus d'imprimer directement les nœuds, la traversée peut également stocker les champs de valeur de chaque nœud dans un tableau, en prenant inorder comme exemple :

vector<int> inorderTraversal(TreeNode* root) {
    vector<int> res;
    inorderTraversal(root, res);
    return res;
}
void inorderTraversal(TreeNode* root, vector<int>& res) {
    if (root == nullptr) {
        return;
    }
    inorderTraversal(root->left, res);
    res.push_back(root->val);
    inorderTraversal(root->right, res);
}

Traversée DFS

DFS utilisera <stack>, version d'impression directe :

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#define null INT_MIN
using namespace std;

struct TreeNode
{
    int val;
    TreeNode *left, *right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

TreeNode* buildTree(vector<int>& nums)
{
    if (nums.empty()) return nullptr;
	TreeNode *root = new TreeNode(nums.front());
    queue<TreeNode*> q;
    q.push(root);
    int i = 1;
    while(!q.empty() && i < nums.size())
    {
        TreeNode *cur = q.front();
        q.pop();
        if(i < nums.size() && nums[i] != null)
        {
            cur->left = new TreeNode(nums[i]);
            q.push(cur->left);
        }
        i++;
        if(i < nums.size() && nums[i] != null)
        {
            cur->right = new TreeNode(nums[i]);
            q.push(cur->right);
        }
        i++;
    }
    return root;
}

void preOrderTraversal(TreeNode* root) {
    stack<TreeNode*> st;
    TreeNode* node = root;
    while (node != nullptr || !st.empty()) {
        while (node != nullptr) {
            cout << node->val << " ";
            st.push(node);
            node = node->left;
        }
        node = st.top();
        st.pop();
        node = node->right;
    }
}

void inOrderTraversal(TreeNode* root) {
    stack<TreeNode*> st;
    TreeNode* node = root;
    while (node != nullptr || !st.empty()) {
        while (node != nullptr) {
            st.push(node);
            node = node->left;
        }
        node = st.top();
        st.pop();
        cout << node->val << " ";
        node = node->right;
    }
}

void postOrderTraversal(TreeNode* root) {
    stack<TreeNode*> st;
    TreeNode* node = root;
    TreeNode* last = nullptr; // 上一次访问的节点
    while (node != nullptr || !st.empty()) {
        while (node != nullptr) {
            st.push(node);
            node = node->left;
        }
        node = st.top();
        if (node->right == nullptr || node->right == last) { 
			// 右子树为空或已经访问过
            cout << node->val << " ";
            st.pop();
            last = node; // 更新上一次访问的节点
            node = nullptr; // 继续弹出栈顶元素
        } else { // 右子树还未访问
            node = node->right;
        }
    }
}

int main()
{
    vector<int> nums;
    for (int i = 0; i < 15; i++)
    	nums.push_back(i+1);
    TreeNode *root = buildTree(nums);
    preOrderTraversal(root);
    cout << endl;
    inOrderTraversal(root);
    cout << endl;
    postOrderTraversal(root);
    cout << endl;
    
    return 0;
}

Arborescence binaire vers tableau, utilisant respectivement DFS et BFS :

vector<int> DFSinorderTraversal(TreeNode* root) {
    vector<int> res;
    stack<TreeNode*> st;
    while (root != nullptr || !st.empty()) {
        while (root != nullptr) {
            st.push(root);
            root = root->left;
        }
        root = st.top();
        st.pop();
        res.push_back(root->val);
        root = root->right;
    }
    return res;
}

vector<int> BFSinorderTraversal(TreeNode* root) {
    vector<int> res;
    queue<TreeNode*> q;
    if (root != nullptr) {
        q.push(root);
    }
    while (!q.empty()) {
        TreeNode* node = q.front();
        q.pop();
        if (node->left != nullptr) {
            q.push(node->left);
        }
        res.push_back(node->val);
        if (node->right != nullptr) {
            q.push(node->right);
        }
    }
    return res;
}

Termes liés à l'arbre

Node : Contient une donnée et plusieurs branches pointant vers son sous-arbre, et traduites en "Node " (Node) Root : Le degré " vertex " (Root) de l'arbre et du sous-arbre : le nombre de sous-arbres possédés par le noeud est appelé le node's Degree ; le degré d'un arbre fait référence à la valeur maximale du degré d'un nœud dans l'arbre. Branch node : un nœud dont le degré n'est pas 0 Leaf : un nœud sans sous-arbre, c'est-à-dire dont le degré est 0 (Leaf ) nœud enfant : nœud La racine du sous-arbre d'un point est appelée l' enfant du nœud (Child) Nœud parent : le nœud de niveau au-dessus du nœud enfant correspondant est appelé le parent (Parent) nœud frère du nœud : les nœuds enfants d'un même nœud parent s'appellent les uns les autres Ancêtres des nœuds frères : de la racine à tous les nœuds sur les branches du nœud Descendants des nœuds : tous les nœuds du sous-arbre enracinés à un nœud Couche : à partir de la racine, la racine est le première couche , l'enfant de la racine est la deuxième couche... (Niveau) profondeur : le nombre maximum de couches de nœuds dans l'arbre, appelé profondeur ou hauteur de l'arbre (Profondeur ou Hauteur) forêt











: C'est une collection de nombreux arbres disjoints (forêt)

Arbre non ordonné : il n'y a pas de relation d'ordre entre les nœuds enfants d'aucun nœud de l'arbre. Cet arbre est appelé arbre non ordonné, également connu sous le nom d'arbre libre. Arbre ordonné : il existe une relation d'ordre entre les nœuds enfants de n'importe quel
nœud de Un arbre est appelé arbre
maximal (arbre minimal) : un arbre dont la valeur à chaque nœud est supérieure (inférieure) ou égale à la valeur de ses nœuds enfants (le cas échéant)


arbre binaire spécial

arbre binaire complet

Toutes les couches ont un nombre maximum de nœuds, tous les nœuds sauf les feuilles ont deux enfants, toutes les feuilles sont dans la couche inférieure (k) et le nombre est 2^(k - 1). Autrement dit, la profondeur est k et il y a 2 ^ k - 1 nœuds (les feuilles "poussent" pour remplir la dernière couche), ou un arbre binaire parfait (Perfect Binary Tree)

         ______12_______
        /               \
     __3__             __5__
    /     \           /     \
  _7       6        _9       11
 /  \     / \      /  \     /  \
13   8   1   4    10   2   0    14

arbre binaire complet

Si toutes les feuilles de la couche inférieure sont supprimées, il s'agit d'un arbre binaire complet, c'est-à-dire qu'à l'exception de la dernière couche, chaque couche de nœuds atteint le nombre maximum, c'est-à-dire que le nombre de nœuds de profondeur k est fermé sur le gauche et ouvert à droite [2^(k-1)+ 1,2^k-1] intervalle. (Arbre binaire complet)

         ________3______
        /               \
    ___11___           __4__
   /        \         /     \
  14         7       9       13
 /  \      /  \     /   
2    5    8    6   1 

Propriétés complètes de l'arbre binaire :

1. La profondeur d'un arbre binaire complet à N nœuds est [log2 N]+1, où [x] est une fonction gaussienne, tronquée à un entier.
2. Si les nœuds d'un arbre binaire complet à n nœuds sont numérotés dans l'ordre (de la première couche à la dernière couche, chaque couche de gauche à droite), alors pour tout nœud, il y a : (1) Si i =
1 , alors le nœud i est la racine de l'arbre binaire et n'a pas de parents ; si i>1, son nœud parent est [i/2] ; (2)
Si 2i>n, alors le nœud i n'a pas d'enfant gauche ; sinon il est gauche l'enfant est le nœud 2i ;
(3) Si 2i+1>n, le nœud i n'a pas d'enfant droit ; sinon, son enfant droit est le nœud 2i+1.


Je suppose que tu aimes

Origine blog.csdn.net/boysoft2002/article/details/129409557
conseillé
Classement