【问题标题】:converting a binary search tree to doubly linked list将二叉搜索树转换为双向链表
【发布时间】:2012-07-15 17:58:08
【问题描述】:

这个问题是在最近的一次编程面试中提出的。

问:给定一棵二叉树,编写一个程序将其转换为双向链表。双向链表中的节点按锯齿形层序遍历形成的顺序排列

我的方法

我总是可以对树进行之字形级别的顺序遍历并将其存储在一个数组中 然后制作一个双链表。 但问题需要就地解决方案。 任何人都可以帮助解释应该使用递归方法吗?

【问题讨论】:

  • 附带说明,这是一个多么糟糕的面试问题。
  • 首先:执行旋转并拉伸到链表中。第二:设置反向指针。 (也许你可以结合这些步骤,但我懒得做你的功课)而且,确实:这是一个可怕的非问题。
  • @wildplasser 你能详细说明一下吗?谢谢回复
  • @wildplasser - OP 显然有一个采访问题的标签。不是家庭作业。如果我们有时间并且不懒惰,如果不传递它,我们可以更包容,更少刻薄的评论和帮助。
  • @corsika 很糟糕,是的,但是在顶级公司之一中被问到,我们在这里有什么选择?如果我们愿意为他们工作。

标签: binary-search-tree tree-traversal doubly-linked-list


【解决方案1】:

这是递归方法。注意,这里的根将指向形成的列表的一些中间元素。所以,只需从根向后遍历即可获得头部。

#define NODEPTR struct node*

NODEPTR convert_to_ll(NODEPTR root){
    if(root->left == NULL && root->right == NULL)
        return root;
    NODEPTR temp = NULL;
    if(root->left != NULL){
        temp = convert_to_ll(root->left);
        while(temp->right != NULL)
            temp = temp->right;
        temp->right = root;
        root->left = temp;
    }
    if(root->right != NULL){
        temp = convert_to_ll(root->right);
        while(temp->left != NULL)
            temp = temp->left;
        temp->left = root;
        root->right = temp;
    }
    return root;
    }

【讨论】:

  • 我喜欢这个答案,我认为这是我见过的最简单的答案
  • 哇!这不仅仅是优雅和疯狂的直截了当!递归的力量!
  • 复杂度 O(nlogn) ... O(n) 解stackoverflow.com/a/26928591/5947203
  • @Ani 这两种解决方案看起来都与我相似,时间复杂度为 O(n)。
【解决方案2】:

斯坦福图书馆链接中提到的解决方案是 BST 到循环 DLL 的完美解决方案,下面的解决方案并不完全是 BST 到循环 DLL 的转换,而是可以通过连接 DLL 的末端来实现循环 DLL。它也不完全是 zig zag 有序树到 dll 的转换。

注意:这个解决方案不是从 BST 到循环 DLL 的完美转换,而是一个易于理解的 hack

JAVA 代码

public Node bstToDll(Node root ){
        if(root!=null){
            Node lefthead = bstToDll(root.left); // traverse down to left 
            Node righthead = bstToDll(root.right); // traverse down to right
            Node temp = null;
            /*
             * lefthead represents head of link list created in left of node
             * righthead represents head of link list created in right
             * travel to end of left link list and add the current node in end
             */
            if(lefthead != null) {
                temp = lefthead;
                while(temp.next != null){
                    temp = temp.next;
                }
                temp.next = root;
            }else{
                lefthead = root;
            }
            root.prev = temp;
            /*
             *set the next node of current root to right head of right list
             */
            if(righthead != null){
                root.next = righthead;
                righthead.prev = root;
            }else{
                righthead = root;
            }
            return lefthead;// return left head as the head of the list added with current node
        }
        return null;
}

希望对大家有所帮助

【讨论】:

    【解决方案3】:

    C++ 代码:

     Node<T> *BTtoDoublyLLZigZagOrder(Node<T> *root)
     {
            if (root == 0)
                return 0;
            if (root->mLeft == 0 && root->mRight == 0)
                return root;
    
            queue<Node<T> *> q;
            q.push(root);
            Node<T> *head = root;
            Node<T> *prev = 0,*curr = 0;
    
            while(!q.empty())
            {
                curr = q.front();
                q.pop();
                if (curr->mLeft)
                    q.push(curr->mLeft);
                if (curr->mRight)
                    q.push(curr->mRight);
                curr->mRight = q.front();
                curr->mLeft = prev;
                prev = curr;
            }
    
            return head;
     }
    

    【讨论】:

    • 虽然代码可读性很强,但最好添加伪代码版本或技术说明,因为问题与语言无关。
    【解决方案4】:

    我们将使用头和尾两个哨兵节点并按顺序遍历树。第一次我们必须将头部链接到最小节点,反之亦然,并且还将最小节点链接到尾部,反之亦然。在第一次之后,我们只需要重新链接当前节点和尾部,直到遍历完成。遍历后,我们将移除哨兵节点并重新正确链接头部和尾部。

    public static Node binarySearchTreeToDoublyLinkedList(Node root) {
    
        // sentinel nodes
        Node head = new Node();
        Node tail = new Node();
    
        // in-order traversal
        binarySearchTreeToDoublyLinkedList(root, head, tail);
    
        // re-move the sentinels and re-link;
        head = head.right;
        tail = tail.left;
    
        if (head != null && tail != null) {
            tail.right = head;
            head.left = tail;
        }
    
        return head;
    }
    
    /** In-order traversal **/
    private static void binarySearchTreeToDoublyLinkedList(Node currNode, Node head, Node tail) {
        if (currNode == null) {
            return;
        }
    
    
        // go left
        //
    
        binarySearchTreeToDoublyLinkedList(currNode.left, head, tail);
    
        // save right node for right traversal as we will be changing current
        // node's right to point to tail
        //
    
        Node right = currNode.right;
    
        // first time
        //
    
        if (head.right == null) {
    
            // fix head
            //
    
            head.right = currNode;
            currNode.left = head;
    
            // fix tail
            //
    
            tail.left = currNode;
            currNode.right = tail;
    
        } else {
    
            // re-fix tail
            //
    
            Node prev = tail.left;
    
            // fix current and tail
            //
    
            tail.left = currNode;
            currNode.right = tail;
    
            // fix current and previous
            //
    
            prev.right = currNode;
            currNode.left = prev;
        }
    
        // go right
        //
    
        binarySearchTreeToDoublyLinkedList(right, head, tail);
    }
    

    【讨论】:

      【解决方案5】:

      最简单的方法。在单中序遍历中,只需 O(1) 的空间复杂度,我们就可以实现这一点。 保留一个名为 lastPointer 的指针,并在访问每个节点后对其进行跟踪。 左右使用

      public void toll(T n) {
          if (n != null) {
              toll(n.left);
              if(lastPointer==null){
                  lastPointer=n;
              }else{
                  lastPointer.right=n;
                  n.left=lastPointer;
                  lastPointer=n;
              }
              toll(n.right);
          }
      }
      

      【讨论】:

        【解决方案6】:
        node* convertToDLL(node* root, node*& head, node*& tail)
        {
            //empty tree passed in, nothing to do
            if(root == NULL)
                return NULL;
        
            //base case
            if(root->prev == NULL && root->next == NULL)
                return root;
        
            node* temp = NULL;
            if(root->prev != NULL)
            {
                temp = convertToDLL(root->prev, head, tail);
        
                //new head of the final list, this will be the left most
                //node of the tree.
                if(head == NULL)
                {
                    head=temp;
                    tail=root;
                }
        
                //create the DLL of the left sub tree, and update t
                while(temp->next != NULL)
                    temp = temp->next;
                temp->next = root;
                root->prev= temp;
                tail=root;
            }
        
            //create DLL for right sub tree
            if(root->next != NULL)
            {
                temp = convertToDLL(root->next, head, tail);
                while(temp->prev != NULL)
                    temp = temp->prev;
                temp->prev = root;
                root->next = temp;
        
                //update the tail, this will be the node with the largest value in
                //right sub tree
                if(temp->next && temp->next->val > tail->val)
                    tail = temp->next;
                else if(temp->val > tail->val)
                    tail = temp;
            }
            return root;
        }
        
        void createCircularDLL(node* root, node*& head, node*& tail)
        {
            convertToDLL(root,head,tail);
        
            //link the head and the tail
            head->prev=tail;
            tail->next=head;
        }
        
        int main(void)
        {
        
            //create a binary tree first and pass in the root of the tree......
            node* head = NULL;
            node* tail = NULL;
            createCircularDLL(root, head,tail);
        
            return 1;
        }
        

        【讨论】:

          【解决方案7】:
          struct node{
          int value;
          struct node *left;
          struct node *right;
          };
          typedef struct node Node;
          
          Node * create_node(int value){
            Node * temp =  (Node *)malloc(sizeof(Node));
            temp->value = value;
            temp->right= NULL;
            temp->left = NULL;
            return temp;
          }
          Node * addNode(Node *node, int value){
            if(node == NULL){
              return create_node(value);
            }
            else{
              if (node->value > value){
                  node->left = addNode(node->left, value);
              }
              else{
                  node->right = addNode(node->right, value);
              }
            }
            return node;
          }
          
          void treeToList(Node *node){
          
              Queue *queue = NULL;
              Node * last = NULL;
              if(node == NULL)
                      return ;
          
              enqueue(&queue, node);
              while(!isEmpty(queue)){
                 /* Take the first element and put 
                    both left and right child on queue */
                      node = front(queue);
                      if(node->left)
                              enqueue(&queue, node->left);
                      if(node->right)
                              enqueue(&queue, node->right);
                      if(last != NULL)
                              last->right = node;
                      node->left = last;
                      last = node;
                      dequeue(&queue);
                }
            } 
            /* Driver program for the function written above */
           int main(){
              Node *root = NULL;
             //Creating a binary tree
              root = addNode(root,30);
              root = addNode(root,20);
              root = addNode(root,15);
              root = addNode(root,25);
              root = addNode(root,40);
              root = addNode(root,37);
              root = addNode(root,45);
          
              treeToList(root);
          
              return 0;
          }
          

          队列 API 的实现可以在以下位置找到 http://www.algorithmsandme.com/2013/10/binary-search-tree-to-doubly-linked.html

          【讨论】:

            【解决方案8】:

            我们可以使用中序遍历并跟踪之前访问过的节点。对于每个访问过的节点,可以分配前一个节点的右和当前的左节点。

            void BST2DLL(node *root, node **prev, node **head)
            {
                // Base case
                if (root == NULL) return;
            
                // Recursively convert left subtree
                BST2DLL(root->left, prev, head);
            
                if (*prev == NULL) // first iteration
                    *head = root;
                else
                {
                    root->left = *prev;
                    (*prev)->right = root;
                }
                *prev = root; // save the prev pointer 
            
                // Finally convert right subtree
                BST2DLL(root->right, prev, head);
            }
            

            【讨论】:

              【解决方案9】:

              希望对你有帮助。

              class Solution(){
              public:
                  TreeNode* convertBST2DLL(TreeNode* root){
                      TreeNode left, right;
                      convert(root, &left, &right);
                      TreeNode* head = left.right;
                      head->left = NULL;
                      right.left->right = NULL;
                      return head;
                  }   
                  void convert(TreeNode* root, TreeNode* left, TreeNode* right){
                      if(root->left == NULL){
                          left->right = root;
                          root->left = left;
                      }
                      else{
                          convert(root->left, left, root);
                      }
                      if(root->right == NULL){
                          right->left = root;
                          root->right = right;
                      }
                      else{
                          convert(root->right, root, right);
                      }
                  }
              };
              

              【讨论】:

                【解决方案10】:

                我意识到这已经很老了,但我在准备面试时解决了这个问题,我意识到如果你考虑每个递归函数调用接收、更新和返回链表的当前头部,它会简单得多。如果您有兴趣返回头部,最好使用逆序遍历。将头部传递给递归函数也不需要静态或全局变量。这是 Python 代码:

                def convert(n, head=None):
                  if n.right:
                    head = convert(n.right, head)
                  if head:
                    head.left = n
                  n.right = head
                  if n.left:
                    head = convert(n.left, n)
                  else:
                    head = n
                  return head
                

                希望这对某人有用。

                【讨论】:

                  【解决方案11】:

                  这里是 Java 代码。复杂度为 O(N)。我还为这个问题添加了一些测试用例。

                  public class BinaryToDoubleLinkedList {
                  
                      static class Node {
                          int value;
                          Node left;
                          Node right;
                  
                          public Node(int value, Node left, Node right) {
                              this.value = value;
                              this.left = left;
                              this.right = right;
                          }
                      }
                  
                      static class Pair {
                          Node head;
                          Node tail;
                  
                          public Pair(Node head, Node tail) {
                              this.head = head;
                              this.tail = tail;
                          }
                      }
                  
                      static Pair convertToDoubleLinkedList(Node root) {
                          return convert(root);
                      }
                  
                      static Pair convert(Node root) {
                          if (root == null) return new Pair(null, null);
                  
                          Node head, last;
                  
                          Pair left = convert(root.left);
                          if (left.tail != null) {
                              left.tail.right = root;
                              root.left = left.tail;
                              head = left.head;
                          } else {
                              head = root;
                          }
                  
                          Pair right = convert(root.right);
                          if (right.head != null) {
                              right.head.left = root;
                              root.right = right.head;
                              last = right.tail;
                          } else {
                              last = root;
                          }
                  
                          return new Pair(head, last);
                      }
                  
                      static void Print(Node root, boolean fromLeft) {
                          System.out.println("---------");
                          if (fromLeft) {
                              while (root != null) {
                                  System.out.print(root.value + ",");
                                  root = root.right;
                              }
                          } else {
                              while (root != null) {
                                  System.out.print(root.value + ",");
                                  root = root.left;
                              }
                          }
                  
                          System.out.println();
                      }
                  
                      public static void main(String[] args) {
                          test1();
                          test2();
                          test3();
                      }
                  
                      // test 1: normal test case
                      public static void test1() {
                          Node root = new Node(10, null, null);
                          root.left = new Node(12, null, null);
                          root.right = new Node(15, null, null);
                  
                          root.left.left = new Node(25, null, null);
                          root.left.right = new Node(30, null, null);
                          root.right.left = new Node(36, null, null);
                  
                          Pair res = convertToDoubleLinkedList(root);
                          Print(res.head, true);
                          Print(res.tail, false);
                      }
                  
                      // test 2: binary tree as linked list
                      public static void test2() {
                          Node root = new Node(1, null, null);
                          root.left = new Node(2, null, null);
                          root.left.left = new Node(3, null, null);
                          root.left.left.left = new Node(4, null, null);
                  
                          Pair res = convertToDoubleLinkedList(root);
                          Print(res.head, true);
                          Print(res.tail, false);
                      }
                  
                      // test 3: null and single
                      public static void test3() {
                          Node root = new Node(1, null, null);
                          Pair res = convertToDoubleLinkedList(root);
                          Print(res.head, true);
                          Print(res.tail, false);
                  
                          res = convertToDoubleLinkedList(null);
                          Print(res.head, true);
                          Print(res.tail, false);
                      }
                  }
                  

                  【讨论】:

                    【解决方案12】:

                    没有全局变量的反向中序遍历 - 实现。调用时,null 最初会传递给 right 参数。最终返回值为双向链表的head

                    public static Node ToDLL(Node node, Node right)
                    {
                        if (node == null)
                            return null;
                    
                        var rnd = ToDLL(node.Right, right);
                    
                        if (rnd != null)
                        {
                            node.Right = rnd;
                            rnd.Left = node;
                        }
                        else
                        {
                            node.Right = right;
                            if (right!= null)
                                right.Left= node;
                        }
                        return ToDLL(node.Left, node) ?? node;
                    }
                    

                    【讨论】:

                      【解决方案13】:

                      找到有序的前任并将左右指向当前根的前任将为您完成这项工作。运行以下代码的时间复杂度为O(N),并将占用辅助空间O(H),其中H = Height of the Tree,隐式用于递归堆栈。下面的代码是使用Python 3编写的。

                      def convertToDLL(root):
                          # Base check
                          if root is None:
                              return root
                      
                          # Converting left sub-tree to root
                          if root.left:
                      
                              # Convert the left subtree
                              left = convertToDLL(root.left)
                      
                              while left.right:
                                  left = left.right
                      
                              left.right = root
                              root.left = left
                      
                          # Converting right sub-tree to root
                          if root.right:
                      
                              # Convert the right subtree
                              right = convertToDLL(root.right)
                      
                              while right.left:
                                  right = right.left
                      
                              right.left = root
                              root.right = right
                      
                          return root
                      
                      
                      def bToDLL(root):
                          if root is None:
                              return root
                      
                          # Convert to DLL
                          root = convertToDLL(root)
                      
                          while root.left:
                              root = root.left
                      
                          return root
                      
                      
                      def display(head):
                          # Display
                          if head is None:
                              return
                          while head:
                              print(head.data, end=" ")
                              head = head.right
                      

                      【讨论】:

                        【解决方案14】:

                        步骤:

                        1. 树的中序遍历

                        2. 在节点处理步骤中,跟踪head和tail并不断增加tail

                        3. 在最后重新连接头部和尾部

                            def binarysearchtreeToLL(root):  
                               def dfsInorder(node):  
                                   nonlocal head, tail 
                          
                                   if not node:  
                                       return None  
                          
                                   dfsInorder(node.left)  
                          
                                   if tail:  
                                        tail.right = node  
                                         node.left = tail  
                                    else:  
                                         head = node  
                                    tail = node  
                          
                                    dfsInorder(node.right)  
                          
                                if not root:  
                                    return None  
                                head, tail = None, None  
                                dfsInorder(root)  
                                head.left = tail  
                                tail.right = head  
                                return head  
                          

                        时间复杂度:O(n) 空间复杂度:在进行 n 次递归堆栈调用的最坏情况下为 O(n)。

                        【讨论】:

                          猜你喜欢
                          • 2011-04-14
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          • 2017-03-30
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多