从零学算法(剑指 Offer 36)

123.输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:从零学算法(剑指 Offer 36)_第1张图片
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

  • 他人题解:首先中序遍历模板如下
  •   dfs(Node cur){
      	if(cur==null)return;
      	dfs(cur.left);  //前
      	solve cur...	//中
      	dfs(cur.right); //后
      }
    
  • 首先为了构建双向连接,我们肯定要定义当前遍历节点的前一个节点 pre。由于最后要返回链表头结点,所以定义一个头结点 head。我们在 dfs 的当前节点处理部分,根据题意很容易想到,无非就是连接前后(当前节点与左节点,或当前节点和右结点)两个节点,然后更新 pre 为当前节点,也就是 cur.left=pre, pre.right=cur, cur=pre。但是在递归时第一次处理当前节点时,也就是头节点时,是没有 pre 给他连接的(按道理应该连接尾结点,可这时刚开始操作,还没拿到尾结点),所以就特判一下,如果 pre 为 null 说明此时在处理的是头结点,就不让 pre 连接它了,而是让 head = cur,这也正好,我们最后要返回的 head 在这一步就得到了。dfs 结束后,pre 此时是指向尾结点的,这时就可以完成之前没连接的,让 head.left = pre(此时为尾结点),然后 pre.right=head。
  •   Node pre, head;
      public Node treeToDoublyList(Node root) {
          if(root == null) return null;
          dfs(root);
          head.left = pre;
          pre.right = head;
          return head;
      }
      void dfs(Node cur) {
          if(cur == null) return;
          dfs(cur.left);
          // 有 pre 就连,否则说明为头节点
          if(pre != null) pre.right = cur;
          else head = cur;
          // cur 为头节点时先连个 null 也无所谓,反正 dfs 结束后会连正确的尾结点
          // 在其他情况下就能正确连接当前节点和他的前一个节点了
          cur.left = pre;
          pre = cur;
          dfs(cur.right);
      }
    

你可能感兴趣的:(算法学习,#,树,算法)