思路:我们不难发现二叉搜索树的中序遍历实际上就是一个排序的序列。
中序遍历:左子树 ,根, 右子树
我们可以将节点的 left 指向比它小的的节点,right 指向 比它大的节点。
由于题目提供的节点类并没有指向父节点的引用,所以我们必须要保存好上一个比它小的节点,否则 left 就没有办法引用了。
所以我们将 pre 也就是比它小的节点引用定义为全局变量。
由于是一个双向链表,那么我们就要把最后一个访问的节点也要保存起来,最后用来指向头节点。我们把最后一个访问的节点定义为 tail。
所以我们也要将 tail 定义为全局变量去储存下来。
最后就是我们的head,链表的头指针,由于我们中序遍历到左子树的最左节点时(最小节点),我们需要把head指向它。但是树的递归中我们之后再也不会用到 head 引用,所以我们也可以把它定义为全局变量,再方法用只运用一次即可。
所以第一步,我们要中序遍历,当遍历到最左节点时,我们就需要把 head 指向 当前的节点。
第二步,中序遍历时,保存当前最后的访问节点,也就是tail,当遍历结束时我们就清楚哪一个节点是最大值。
第三步:中序遍历结束后,我们要把tail 指向 head 而 head.pre,要指向tail,
最后返回head即可。
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;
}
}
private Node head = null;
private Node pre = null;
private Node tail = null;
public Node treeToDoublyList(Node root) {
if(root == null) return null;
inorder(root);
//当中序遍历链接过程结束,那么就将改变引用指向,形成真正的双向环形链表
head.left = tail;
head = tail.right;
return head;
}
public void inorder(Node root){
//当前节点
Node current = root;
//遍历左子树
if(current.left != null)
inorder(current.left);
//当第一次左子树为空时,也就是pre为null时,我们将head指向最左节点
if(pre == null) {
head = current;
}
else{
//证明此时的节点不是最左节点。那么就让前一个节点的right指向当前节点。
pre.right = current;
current.left = pre;
}
//当前的节点。
//保存当前最后访问的一个节点
tail = current;
//进入到右子树时上一个节点就是pre,也就是当前的节点了。
pre = current;
//遍历右子树
if(current.right != null)
inorder(current.right);
}