[Klassische Frage] Binärer Suchbaum und doppelt verknüpfte Liste

Binärer Suchbaum und doppelt verknüpfter Listenlink

Ideen zur Problemlösung

Idee 1: Traversieren in der richtigen Reihenfolge, Knoten in den Vektor einfügen und dann die Verknüpfungsbeziehung ändern Das ist leicht zu finden und zu lösen, aber es erfüllt offensichtlich nicht den Sinn der Frage.
Bildbeschreibung hier einfügen

Idee 2:
Diese Frage erfordert die Umwandlung eines binären Suchbaums in eine sortierte doppelt verkettete Liste, ohne neue Knoten zu erstellen und nur Zeiger anzupassen.
Das Merkmal des binären Suchbaums besteht darin, dass der Wert des linken Teilbaums kleiner als der Wurzelknoten und der Wert des rechten Teilbaums größer als der Wurzelknoten ist und eine aufsteigende Sequenz durch Traversierung in der Reihenfolge erhalten werden kann.
Daher können wir die Reihenfolge des Durchlaufens in der Reihenfolge verwenden, um den linken Zeiger jedes Knotens auf den vorherigen Knoten zu zeigen und den rechten Zeiger jedes Knotens auf den nächsten Knoten zu zeigen, wodurch eine doppelt verknüpfte Liste gebildet wird.
Wir müssen eine Variable prev verwenden, um den vorherigen Knoten aufzuzeichnen, anfänglich nullptr. Dann durchlaufen wir rekursiv den Binärbaum, und jedes Mal, wenn wir einen Knoten besuchen, ändern wir den Zeiger darauf und prev und aktualisieren prev auf den aktuellen Knoten.
Schließlich beginnen wir beim Wurzelknoten und gehen nach links, finden den Knoten ganz links, der der Kopfknoten der doppelt verknüpften Liste ist, und kehren einfach zurück.
Bildbeschreibung hier einfügen

Nehmen Sie eine Kastanie:
Angenommen, wir haben einen solchen binären Suchbaum:

       10
      /  \
    6    14
    / \   / \
   4   8 12 16

Wir initialisieren zuerst prev so, dass es leer ist, und durchlaufen dann rekursiv den Binärbaum vom Wurzelknoten aus.

Zuerst traversieren wir zum Knoten 4, der keinen linken Unterbaum hat, also ändern wir direkt seinen linken Zeiger so, dass er auf prev zeigt (zu diesem Zeitpunkt leer), und aktualisieren dann prev auf 4.

Dann gehen wir zurück zu Knoten 6, der einen linken Teilbaum hat, also ändern wir seinen linken Zeiger so, dass er auf prev zeigt (was jetzt 4 ist), und den rechten Zeiger von Punkt 4 auf 6. Aktualisieren Sie dann prev auf 6.

Dann traversieren wir zum Knoten 8, der keinen linken Unterbaum hat, also modifizieren wir seinen linken Zeiger so, dass er auf prev (zu diesem Zeitpunkt 6) zeigt, und zeigen den rechten Zeiger von 6 auf 8. Aktualisieren Sie dann prev auf 8.

Dann gehen wir zurück zum Knoten 10, der einen linken Teilbaum hat, also ändern wir seinen linken Zeiger so, dass er auf prev zeigt (was jetzt 8 ist), und den rechten Zeiger von Punkt 8 auf 10. Aktualisieren Sie dann prev auf 10.

Dann traversieren wir zum Knoten 12, der keinen linken Unterbaum hat, also modifizieren wir seinen linken Zeiger so, dass er auf prev (zu diesem Zeitpunkt 10) zeigt, und zeigen mit dem rechten Zeiger von 10 auf 12. Aktualisieren Sie dann prev auf 12.

Dann gehen wir zurück zum Knoten 14, der einen linken Teilbaum hat, also ändern wir seinen linken Zeiger so, dass er auf prev zeigt (zu diesem Zeitpunkt 12), und den rechten Zeiger von Punkt 12 auf 14. Aktualisieren Sie dann prev auf 14.

Dann traversieren wir zum Knoten 16, der keinen linken Unterbaum hat, also modifizieren wir seinen linken Zeiger so, dass er auf prev (zu diesem Zeitpunkt 14) zeigt, und den rechten Zeiger von Punkt 14 auf 16. Aktualisieren Sie dann prev auf 16.

Schließlich gehen wir zurück zum Wurzelknoten 10 und von ihm nach links, um den ganz linken Knoten 4 zu finden, der der Kopfknoten der doppelt verknüpften Liste ist. Geben Sie einfach 4 zurück.

An dieser Stelle wurde der binäre Suchbaum in die folgende doppelt verkettete Liste umgewandelt:

NULL <-> 4 <-> 6 <-> 8 <-> 10 <-> 12 <-> 14 <-> 16 <-> NULL
Bildbeschreibung hier einfügen

Code - Kommentare hinzufügen

/*
struct TreeNode {
    int val; // 节点的值
    struct TreeNode *left; // 左子节点的指针
    struct TreeNode *right; // 右子节点的指针
    TreeNode(int x) : // 构造函数,初始化节点的值和子节点指针
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
    
    
  public:
    void InOrderConvert(TreeNode* cur, TreeNode*& prev) {
    
    
        if (cur == nullptr) // 如果当前节点为空,直接返回
            return;
        InOrderConvert(cur->left, prev); // 递归遍历左子树
        //这里cur出现的顺序就是中序
        cur->left = prev; // 将当前节点的左指针指向前一个节点
        if (prev) // 如果前一个节点不为空,将其右指针指向当前节点
            prev->right = cur;
        prev = cur; // 更新前一个节点为当前节点

        InOrderConvert(cur->right, prev); // 递归遍历右子树
    }
    TreeNode* Convert(TreeNode* pRootOfTree) {
    
    
        TreeNode* prev = nullptr; // 初始化前一个节点为空
        InOrderConvert(pRootOfTree,
                       prev); // 调用辅助函数,中序遍历二叉树,并修改指针

        TreeNode* head = pRootOfTree; // 初始化头节点为根节点
        while (head &&
                head->left) {
    
     // 循环找到最左边的节点,即双向链表的头节点
            head = head->left;
        }


        return head; // 返回头节点
    }
};

Ende dieses Abschnitts

Supongo que te gusta

Origin blog.csdn.net/weixin_62676865/article/details/130414227
Recomendado
Clasificación