488, Morris parcours en ordre et en pré-ordre d'arbres binaires

Insérez la description de l'image ici

Si vous souhaitez voir plus de questions d'algorithme, vous pouvez scanner le code QR ci-dessus et suivre mon compte officiel WeChat " Structure de données et algorithme ". Jusqu'à présent, j'ai mis à jour plus de 500 questions d'algorithme dans le compte officiel , dont certaines ont été triés en documents pdf., À partir de maintenant, il y a plus de 800 pages au total (et continuera d'augmenter), vous pouvez répondre au mot-clé "pdf" dans le compte officiel pour télécharger.


Description du problème

J'ai introduit l'avant, le milieu et l'arrière de l'arbre binaire, ainsi que les méthodes de traversée telles que DFS et BFS, et chacun a écrit des solutions récursives et non récursives. Certains disent que les méthodes de traversée avant, milieu et arrière de l'arbre binaire appartiennent à une sorte de DFS, en fait, cela peut également être compris de cette manière. Pour plus de détails sur ces méthodes de parcours, voir 373, Data Structure-6, Tree .


Pour la traversée de l'arbre binaire, en plus des plusieurs méthodes courantes décrites ci-dessus, il existe trois méthodes de traversée de l'avant, du milieu et de l'arrière de Morris. Pour les différentes méthodes de traversée de l'arbre binaire mentionnées ci-dessus, si la méthode non récursive est utilisée, nous avons besoin d'une pile ou d'une file d'attente pour maintenir la relation entre les nœuds. Si vous utilisez Morris traversal, vous n'en avez pas besoin. Son processus d'implémentation consiste en fait à utiliser le pointeur du nœud feuille, car en général, les nœuds feuilles de l'arbre binaire n'ont pas de nœuds enfants, c'est-à-dire qu'ils pointent vider, ce qui donne toujours l'impression que c'est un peu inutile.Le principe d'implémentation de Morris est en fait d'utiliser le pointeur du nœud feuille. La méthode de traversée de suivi de Morris est un peu plus compliquée, j'en parlerai plus tard.Nous examinons ici principalement les méthodes de traversée de pré-ordre et d'ordre moyen de Morris.


Traversée dans l'ordre de Morris

Pour le parcours dans l'ordre de Morris, vous pouvez considérer cela comme un redressement de l'arbre binaire en une liste chaînée. Jetons un coup d'œil à ses étapes d'implémentation:

Souvenez-vous du nœud actuel en tant que cur et passez à partir du nœud racine.

1. Déterminez si cur est vide et arrêtez de parcourir s'il est vide.

2. Si cur n'est pas vide

1)如果cur没有左子节点,打印cur的值,然后让cur指向他的右子节点,即cur=cur.right

2)如果cur有左子节点,则从左子节点中找到最右边的结点pre。

   1))如果pre的右子节点为空,就让pre的右子节点指向cur,即pre.right=cur,然后cur指向他的左子节点,即cur=cur.left。

  2))如果pre的右子节点不为空,就让他指向空,即pre.right=null,然后输出cur节点的值,并将节点cur指向其右子节点,即cur=cur.right。

3. Répétez l'étape 2 jusqu'à ce que le nœud cur soit vide.

Il y a beaucoup de descriptions ci-dessus, et ceux qui comprennent peuvent le comprendre d'un coup d'œil, et ceux qui ne comprennent pas auront certainement le vertige. Laissez-moi vous expliquer un par un.
1. Tout d'abord, le premier, arrêtez de parcourir si cur est vide, il n'y a rien à dire, bien sûr il ne peut pas être parcouru s'il est vide.
2. Cur n'est pas vide, le nœud enfant gauche de cur est vide, affichez la valeur du nœud actuel cur, puis laissez cur = cur.right, dessinons une image pour voir
Insérez la description de l'image ici

2. Cur n'est pas vide, et son nœud enfant gauche n'est pas vide. Nous devons trouver le nœud enfant le plus à droite pre dans son nœud enfant gauche. En fait, il s'agit du nœud précédent de cur dans la traversée d'ordre du milieu. Nous pouvons dessiner En regardant l'arbre, il est évident de trouver le nœud précédent que le nœud courant traverse dans l'ordre du milieu.

Insérez la description de l'image ici

Ensuite, déterminez si le bon nœud enfant de pre est vide. Cette étape peut être l'endroit le plus douteux pour tout le monde. Est-ce que cela doit encore être jugé? En fait, c'est nécessaire. Lors de la première recherche, le nœud enfant correct de pre doit être vide. Nous le laissons juste pointer vers cur, c'est-à-dire pre.right = cur. Comme indiqué ci-dessous
Insérez la description de l'image ici

Ensuite, laissez cur pointer vers son nœud enfant gauche, comme indiqué dans la figure ci-dessous

image

Bien que le nœud 1 ne soit pas déconnecté de son nœud enfant gauche, nous pouvons le considérer comme déconnecté (en fait pas déconnecté), nous pouvons l'imaginer comme ceci

image

En fin de compte, nous pouvons le considérer comme étant transformé en une liste chaînée (pas réellement).


Si le nœud enfant droit de pre n'est pas vide, il doit pointer vers le nœud cur, ce qui signifie que le nœud enfant gauche du nœud cur a été traversé , seule la valeur cur du nœud actuel doit être affichée, puis cur pointez sur le nœud enfant droit, commencez à traverser le nœud enfant droit avec la même opération.


La description textuelle est plus compliquée, prenons juste un exemple et dessinons une image pour voir

Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici
Insérez la description de l'image ici

Comprenez les principes ci-dessus, le code est beaucoup plus simple

public List<Integer> inorderTraversal(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<>();
    //首先把根节点赋值给cur
    TreeNode cur = root;
    //如果cur不为空就继续遍历
    while (cur != null) {
    
    
        if (cur.left == null) {
    
    
            //如果当前节点cur的左子节点为空,就访问当前节点cur,
            //接着让当前节点cur指向他的右子节点
            res.add(cur.val);
            cur = cur.right;
        } else {
    
    
            TreeNode pre = cur.left;
            //查找pre节点,注意这里有个判断就是pre的右子节点不能等于cur
            while (pre.right != null && pre.right != cur)
                pre = pre.right;
            //如果pre节点的右指针指向空,我们就让他指向当前节点cur,
            //然后当前节点cur指向他的左子节点
            if (pre.right == null) {
    
    
                pre.right = cur;
                cur = cur.left;
            } else {
    
    
                //如果pre节点的右指针不为空,那么他肯定是指向cur的,
                //表示cur的左子节点都遍历完了,我们需要让pre的右
                //指针指向null,目的是把树给还原,然后再访问当前节点
                //cur,最后再让当前节点cur指向他的右子节点。
                pre.right = null;
                res.add(cur.val);
                cur = cur.right;
            }
        }
    }
    return res;
}

Traversée des précommandes de Morris

Le chemin du parcours de pré-ordre et du parcours de niveau intermédiaire est le même, mais le moment d'accès aux nœuds est différent. L'image ne dessine pas, il y a des commentaires dans le code, vous pouvez voir

public List<Integer> preorderTraversal(TreeNode root) {
    
    
    List<Integer> res = new ArrayList<>();
    //首先把根节点赋值给cur
    TreeNode cur = root;
    //如果cur不为空就继续遍历
    while (cur != null) {
    
    
        if (cur.left == null) {
    
    
            //如果当前节点cur的左子节点为空,就访问当前节点cur,
            //接着让当前节点cur指向他的右子节点
            res.add(cur.val);
            cur = cur.right;
        } else {
    
    
            TreeNode pre = cur.left;
            //查找pre节点,注意这里有个判断就是pre的右子节点不能等于cur
            while (pre.right != null && pre.right != cur)
                pre = pre.right;
            //如果pre节点的右指针指向空,我们就让他指向当前节点cur,
            //然后打印当前节点cur的值,最后再让当前节点cur指向他的左子节点
            if (pre.right == null) {
    
    
                pre.right = cur;
                res.add(cur.val);
                cur = cur.left;
            } else {
    
    
                //如果pre节点的右指针不为空,那么他肯定是指向cur的,
                //表示当前节点cur和他的的左子节点都遍历完了,直接
                //让他指向他的右子节点即可。
                pre.right = null;
                cur = cur.right;
            }
        }
    }
    return res;
}

Pour résumer

Ce qui précède est la traversée d'ordre intermédiaire et de pré-ordre de Morris. La traversée suivante est un peu compliquée, et il y a un article séparé plus tard.

J'ai trié quelques questions d'algorithme au format pdf. Si la lecture n'est pas pratique, vous pouvez télécharger et lire. Répondez au mot-clé "pdf" dans le compte officiel pour obtenir l'adresse de téléchargement et le mot de passe. Ci-dessous, une capture d'écran d'une partie du catalogue .

Je suppose que tu aimes

Origine blog.csdn.net/abcdef314159/article/details/112208458
conseillé
Classement