思路
要将一个二叉搜索树转化为升序的循环双向链表,很明显使用中序遍历能获得升序。然后思考怎样改造中序遍历能够构建循环双向链表且不需要新建结点。考虑到双向,则肯定需要保存前驱节点,因此如下设置:
- 新建pre、head两个指针,pre指向前一个工作节点,head指向循环双向链表的头结点。
- 在中序遍历过程中 root.left=pre; pre.right=right; 每次访问一个节点时,为它的前驱设置后继。
- 当pre为null时说明访问到了二叉树的最小节点,应该作为头节点进行保存 head=root;
- 最后中序遍历完了之后。不能够忘记将最后一个结点的后继和head的前驱设置好。而此时pre便是指向最后一个结点的,所以可以直接:head.left=pre; pre.right=head;
代码
package algorithm.jianzhiOffer;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
class Node2 {
public int val;
public Node2 left;
public Node2 right;
public Node2() {}
public Node2(int _val) {
val = _val;
}
public Node2(int _val,Node2 _left,Node2 _right) {
val = _val;
left = _left;
right = _right;
}
};
public class Q36 {
//0ms。改造完的高效率解法
Node2 pre=null,head=null;
public Node2 treeToDoublyList(Node2 root) {
if(root==null) return null;
inOrder(root);
pre.right=head;
head.left=pre;
return head;
}
void inOrder(Node2 root){
if(root==null) return;
inOrder(root.left);
root.left=pre;
if(pre!=null) pre.right=root;
else head=root;
pre=root;
inOrder(root.right);
}
//2ms 未改造的低效率解法
List<Node2> list=new ArrayList();
public Node2 treeToDoublyList2(Node2 root) {
if(root==null) return null;
inOrder2(root);
int size=list.size();
if(size==1) {
root.left=root.right=root;
return root;
}
list.get(0).right=list.get(1);
list.get(0).left=list.get(size-1);
list.get(size-1).left=list.get(size-2);
list.get(size-1).right=list.get(0);
if(size==2){
return list.get(0);
}
for(int i=1;i<size-1;i++){
list.get(i).right=list.get(i+1);
list.get(size-i-1).left=list.get(size-i-2);
}
return list.get(0);
}
void inOrder2(Node2 root){
if(root==null) return;
inOrder2(root.left);
list.add(root);
inOrder2(root.right);
}
}