思路
要將一個二叉搜索樹轉化爲升序的循環雙向鏈表,很明顯使用中序遍歷能獲得升序。然後思考怎樣改造中序遍歷能夠構建循環雙向鏈表且不需要新建結點。考慮到雙向,則肯定需要保存前驅節點,因此如下設置:
- 新建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);
}
}