【Fiche d'apprentissage de la structure des données 14】 —— Arbre et arbre binaire

Zéro. Avant-propos

Il aurait dû y avoir le dernier chapitre 稀疏矩阵的十字链表存储et 广义表.
Mais le tableau généralisé est plus biaisé vers le sujet, comprend le concept et peut le calculer. Dans une certaine mesure, le tableau généralisé peut être considéré comme un arbre.

1. Arbre

1. Définition

L'arbre est un ensemble fini de n (> = 0) nœuds.

2. Nature

Dans n'importe quel arbre non vide:

  1. Il existe un et un seul nœud spécifique appelé根结点root
  2. Lorsque n>1, les nœuds restants peuvent être divisés en m>0ensembles finis disjoints T. 1 ...... T m . Parmi eux, chaque ensemble lui-même est un arbre, et s'appelle la racine 子树.

Par conséquent, la définition de la structure arborescente doit être une définition récursive.

3. Représentation

En plus de notre représentation d'arborescence commune, il existe:

  1. Notation des ensembles imbriqués (a)
  2. Notation de table généralisée (b)
  3. Notation encastrée ©
    Insérez la description de l'image ici

4. Terminologie de base

  1. L'arbre 结点contient un élément de données et plusieurs branches qui pointent vers ses sous-arbres.
  2. 结点Le sous-arbre possédé est appelé 结点的度(Degree).
  3. Un nœud avec un degré de 0 est appelé un 叶子OR 终端结点.
  4. Le nœud dont le degré n'est pas 0 est appelé 分支结点ou非终端结点
  5. 树的度Est le degré maximum de chaque nœud de l'arborescence.
  6. La racine du sous-arbre d'un nœud est appelée le nœud 孩子; en conséquence, le nœud est un enfant 双亲.
  7. Les nœuds du même parent, ils s'appellent les uns les autres兄弟
  8. Le niveau du nœud est défini à partir de la racine, la racine est le premier niveau et les enfants de la racine sont dans le deuxième niveau. Si un nœud est au niveau n, alors la racine de son sous-arbre est au niveau n + 1. Les nœuds dont les parents sont au même niveau sont appelés 堂兄弟.
  9. Le plus grand niveau de nœuds de l'arborescence est appelé l'arbre 深度或高度.
  10. Si les sous-arbres sont considérés comme ordonnés de gauche à droite, alors on dit que l'arbre est 有序树, sinon c'est le cas 无序树.
  11. Dans un arbre ordonné, la racine du sous-arbre le plus à gauche est appelée 第一个孩子, et la plus à droite est appelée最后一个孩子
  12. 森林C'est m>=0une collection d'arbres disjoints. Pour chaque nœud de l'arborescence, la collection de ses sous-arbres devient la forêt.

En termes de structure logique, tout arbre est un arbre à deux tuples = (racine, F), où racine est un élément de données, appelé le nœud racine de l'arbre; F est une forêt de m> = 0 arbres, F = ( T . 1 ...... T m ), où T i = (R & lt i , F. i appelé i-ième racine de sous - arbre de racine.
Insérez la description de l'image ici

Deux. Arbre binaire

1. Petite introduction

Si vous étudiez un arbre, vous devez commencer par le cas le plus simple. Lorsque chacun de nos nœuds a un enfant, n'est-ce pas une liste chaînée? Ainsi, lorsque nous étudions les arbres, nous utilisons généralement un arbre avec deux enfants au nœud, appelé arbre binaire.

2. Nature

Voici quelques propriétés sans preuve. C'est aussi facile à prouver (probablement).

  1. Il iy a au plus 2 nœuds i-1 au premier niveau de l' arbre binaire .
  2. Un arbre binaire de profondeur k a au plus 2 k -1 nœuds (k> = 1).
  3. Pour tout arbre binaire. Si le nombre de nœuds terminaux est m et le nombre de nœuds de degré 2 est n, alors m = n + 1.
  4. Un arbre binaire avec une profondeur de k et 2 k -1 nœuds est appelé 满二叉树.
  5. L'arbre binaire complet est numéroté et il est convenu que la numérotation commence à partir du nœud racine, de haut en bas et de gauche à droite. Lorsque chaque nœud d'un arbre correspond à l'arbre binaire complet de cette manière, il est appelé 完全二叉树. Il a deux caractéristiques: a) Les nœuds feuilles ne peuvent apparaître que sur les deux plus grands niveaux. b) Pour tout nœud, le niveau maximum de descendants sous la branche droite est l, puis le niveau maximum de descendants sous la branche inférieure gauche doit être l ou l + 1.
  6. La profondeur d'un arbre binaire complet avec n nœuds est log 2 n +1
  7. S'il existe un arbre binaire complet avec n nœuds, et suivant la méthode de numérotation qui vient d'être décrite, pour tout nœud i (1 <= i <= n), il y a: a) Si i = 1, alors le nœud i est un arbre binaire Les racines, sans parents. Si i> 1, le numéro du nœud parent est i / 2. b) Si 2i> n, le nœud n'a pas d'enfant gauche, sinon son enfant gauche est le nœud 2i. c) Si 2i + 1> n, alors le nœud i n'a pas d'enfant droit, sinon le numéro de son enfant droit est le nœud 2i + 1.
    Insérez la description de l'image ici

3. La structure de stockage de l'arborescence binaire

3.1 Stockage de séquence

Insérez la description de l'image ici

Le stockage séquentiel est généralement utilisé pour les arbres binaires complets. S'il est utilisé dans un arbre binaire incomplet, il peut causer beaucoup de perte d'espace.

3.2 Liste liée binaire

Insérez la description de l'image ici

Du point de vue de la structure, un nœud a des champs de pointeur gauche et droit en plus du champ de données. Ensuite, la liste chaînée la plus simple contient ces trois parties. Il peut être compris comme une seule liste X2 liée.

3.3 Liste chaînée à trois volets

Dans une liste chaînée à trois volets, elle a un pointeur de nœud parent de plus qu'une liste chaînée à deux volets. C'est très similaire à une liste à double chaînage.

4. Traversée de l'arbre binaire

4.1 Définition

Dans certaines applications d'arbres binaires, il est souvent nécessaire de trouver des points avec certaines caractéristiques dans l'arbre, ou d'effectuer certains traitements sur tous les nœuds de l'arbre un par un. Cela soulève une 遍历二叉树question. Patrouillez chaque nœud de l'arborescence selon un certain chemin de recherche, de sorte que chaque nœud ne soit visité qu'une seule fois. Supposons que nous ayons un arbre binaire complet de 1234567 comme exemple des trois prochains parcours. La traversée est basée sur des opérations sur des nœuds non vides.

4.2 Parcours de précommande

  1. Visitez le nœud racine.
  2. Traversez d'abord le sous-arbre gauche.
  3. Traversez d'abord le sous-arbre droit.
  4. Résultats de traversée: 1245367

4.3 Traversée dans l'ordre

  1. Traversez le sous-arbre gauche dans l'ordre du milieu.
  2. Visitez le nœud racine.
  3. Traversez le sous-arbre droit dans l'ordre du milieu.
  4. Résultats de traversée: 4251637

4.4 Traversée post-ordre

  1. Traversez le sous-arbre gauche en post-ordre.
  2. Le sous-arbre droit est parcouru en post-ordre.
  3. Visitez le nœud racine.
  4. Traverser le résultat 4526731

Trois. Principes de programmation

1. Structure de stockage

Dans cet article, nous utilisons la plus simple implémentation de liste chaînée binaire + traversée. Tout d'abord, nous créons toujours une structure de domaine de données, puis une structure de nœuds, qui contient deux pointeurs vers les nœuds fils gauche et droit et une structure de domaine de données.

2. Stockage (parcours du premier ordre)

Nous lisons dans un arbre et construisons cet arbre binaire grâce à la méthode de traversée de pré-commande. Bien entendu, pour connaître le nœud terminal de chaque arbre, il faut représenter les fils du nœud terminal par un nœud virtuel, un caractère aléatoire. L'accord ici est #, par exemple, pour ABCcet arbre avec une profondeur de 2, nous devons entrer AB##C##.
Notre parcours doit être parcouru jusqu'au nœud virtuel, si le caractère est #alors, la valeur du nœud est NULL, sinon #, le champ de données du nœud est stocké dans le caractère, et le nœud fils est créé.

3. Traversez la sortie

Si nous avons un #nœud, alors arrêtez la récursivité, c'est la récursivité de nos frontières.
Sinon, suivez simplement une certaine méthode de traversée pour parcourir et afficher les caractères du nœud.

4. Mise en œuvre du code

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

#define         OK      1
#define         ERROR   0

typedef struct dataType{
    
    
    char data;
}dataType;

typedef struct Btree{
    
    
    dataType node;
    struct Btree *lc;
    struct Btree *rc;
}Btree;

int BtreeCreat(Btree **TreePtr);    // 通过先序遍历的方式创建二叉树
int BtreeShowDLR(Btree *root);      // 三种遍历
int BtreeShowLDR(Btree *root);
int BtreeShowLRD(Btree *root);

int main()
{
    
    
    Btree *root = NULL;
    printf("\nplase input the tree as DLR:\n");
    BtreeCreat(&root);
    printf("\nDLR is: ");
    BtreeShowDLR(root);
    printf("\nLDR is: ");
    BtreeShowLDR(root);
    printf("\nLRD is: ");
    BtreeShowLRD(root);
    return 0;
}

int BtreeCreat(Btree **TreePtr)
{
    
    
    // 因为会对传入的结点的地址进行修改,所以需要用到二重指针
    char ch;
    ch = getchar();  //读入字符
    if (ch == '#')
    {
    
    
        *TreePtr = NULL;    // 如果这个字符是#,则将这个结点的地址赋为空
    }
    else    //非空
    {
    
    
        *TreePtr = (Btree*)malloc(sizeof(Btree));   // 创建结点
        if (!*TreePtr) return ERROR;        // 创建失败退出
        (*TreePtr)->node.data = ch;         // 将结点的值赋值为字符
        BtreeCreat(&((*TreePtr)->lc));      // 遍历创建左结点
        BtreeCreat(&((*TreePtr)->rc));      // 遍历创建右结点
    }

    return OK;
}

int BtreeShowDLR(Btree *root)   // 因为遍历不会对结点地址进行改变,所以不需要二重指针
{
    
    
    if (root != NULL)   // 如果结点不为空,说明它有值
    {
    
    
        printf("%c", root->node.data);  // 输出根结点
        BtreeShowDLR(root->lc);         // 遍历左结点
        BtreeShowDLR(root->rc);         // 遍历右结点
    }
    // 为空没有任何操作
    return OK;
}

int BtreeShowLDR(Btree *root)
{
    
    
    if (root != NULL)   // 遍历顺序不一样
    {
    
    
        BtreeShowLDR(root->lc);
        printf("%c", root->node.data);
        BtreeShowLDR(root->rc);
    }
    return OK;
}

int BtreeShowLRD(Btree *root)
{
    
    
    if (root != NULL)   // 遍历顺序不一样
    {
    
    
        BtreeShowLRD(root->lc);
        BtreeShowLRD(root->rc);
        printf("%c", root->node.data);
    }
    return OK;
}

Je suppose que tu aimes

Origine blog.csdn.net/u011017694/article/details/109859754
conseillé
Classement