1:题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2:题目分析
解题思路:对于二叉排序树而言,其中序遍历输出就是升序排序。那我们怎么将其做成双向链表尼?着手点肯定是中序遍历;在遍历的迭代逻辑中,我们要将前次迭代和本次迭代处理的节点,按照双向链表的要求进行处理。怎么处理尼?通过一个全局变量保存上次遍历的节点,然后再本次遍历的节点处理中进行如下操作:
preNode.right = curNode;
curNode.left = preNode;
当所有节点都这样处理后我们看

其原本是一个二叉排序树,遍历处理后,root指向尾部,我们这是只需要将head和tail相连就可以构成一个完整的双向链表了。root再处理后就是尾部,然而head我们可以通过循环的方式
Node newHead = root;
while(true){
if(newHead.left == null){
break;
}
newHead = newHead.left;
}
一直向左子节点取寻找,直到为null,就到达了最小的节点了,当然也可以再中序遍历中进行操作,因为中序遍历第一个遍历的就是最左子节点,这里把其保存下来就可以了。
这里的递归操作如下:
- 本轮递归终止条件:当前节点为null时,终止本轮递归,归来即可。在二叉树的体现就是遇到了子节点为null的节点处就不会继续深入递归了。
- 递归逻辑设计:借用中序遍历,在遍历操作用将preNode.rigth = curNode,curNode.left = preNode,这里要注意的是,第一次遍历到左下节点时,此时preNode为null,curNode为最小节点。无法进行上述操作,所以在处理开始情况时,要处理好,在第二次遍历的时才操作。
- 递归返回值:void
3:代码示例
package JianZhiOffer36;
/**
* @author :dazhu
* @date :Created in 2020/3/23 9:11
* @description: 二叉搜索树与双向链表
* @modified By:
* @version: $
*/
public class Main {
public static void main(String[]args){
}
}
class Solution {
public Node preNode = null;
public Node newHead = null;
public Node treeToDoublyList(Node root) {
//边界条件
if(root == null){
return root;
}
middleOrder(root);
//将处理后的双向链表的首尾相连
newHead.left = preNode;
preNode.right = newHead;
return newHead;
}
//算法思路:因为二叉排序树的中序遍历的输出就是有序的列表,
//我们改写中序遍历,通过定义一个preNode的全局变量保留当前节点的前一个节点。
//preNode.right = curNode,curNode.left = preNode.
public void middleOrder(Node root){
//如果当前节点为null,则return null
if(root == null){
return ;
}
//中序遍历,
middleOrder(root.left);
//中序遍历,第一个遍历的节点就是最左下的最小节点。
//即第一个访问的节点就为左下角节点。
//如果出preNode,则指向此时root,即为最左下节点。用来第一次遍历时,初始化
//第一次进入这里是最左子节点时,初始化所需节点指引。
if(preNode == null){
newHead = root;
preNode = root;
}//否则,
else{
//以preNode始终指向前一个节点,正好是比当前节点小的节点,
//进行以下操作,将其转成双向链表。
preNode.right = root;
root.left = preNode;
preNode = root;
}
middleOrder(root.right);
}
}
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
来源:https://www.cnblogs.com/dazhu123/p/12552985.html