目錄
輸入一棵二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。
方法一:非遞歸版
解題思路:
1
.核心是中序遍歷的非遞歸算法。
2
.修改當前遍歷節點與前一遍歷節點的指針指向。
import java.util.Stack;
public TreeNode ConvertBSTToBiList(TreeNode root) {
if(root==null)
return null;
Stack<TreeNode> stack = new Stack<TreeNode>();
TreeNode p = root;
TreeNode pre = null;// 用於保存中序遍歷序列的上一節點
boolean isFirst = true;
while(p!=null||!stack.isEmpty()){
while(p!=null){
stack.push(p);
p = p.left;
}
p = stack.pop();
if(isFirst){
root = p;// 將中序遍歷序列中的第一個節點記爲root
pre = root;
isFirst = false;
}else{
pre.right = p;
p.left = pre;
pre = p;
}
p = p.right;
}
return root;
}
方法二:遞歸版
解題思路:
1
.將左子樹構造成雙鏈表,並返回鏈表頭節點。
2
.定位至左子樹雙鏈表最後一個節點。
3
.如果左子樹鏈表不爲空的話,將當前root追加到左子樹鏈表。
4
.將右子樹構造成雙鏈表,並返回鏈表頭節點。
5
.如果右子樹鏈表不爲空的話,將該鏈表追加到root節點之後。
6
.根據左子樹鏈表是否爲空確定返回的節點。
public TreeNode Convert(TreeNode root) {
if(root==null)
return null;
if(root.left==null&&root.right==null)
return root;
// 1.將左子樹構造成雙鏈表,並返回鏈表頭節點
TreeNode left = Convert(root.left);
TreeNode p = left;
// 2.定位至左子樹雙鏈表最後一個節點
while(p!=null&&p.right!=null){
p = p.right;
}
// 3.如果左子樹鏈表不爲空的話,將當前root追加到左子樹鏈表
if(left!=null){
p.right = root;
root.left = p;
}
// 4.將右子樹構造成雙鏈表,並返回鏈表頭節點
TreeNode right = Convert(root.right);
// 5.如果右子樹鏈表不爲空的話,將該鏈表追加到root節點之後
if(right!=null){
right.left = root;
root.right = right;
}
return left!=null?left:root;
}
方法三:改進遞歸版
解題思路:
思路與方法二中的遞歸版一致,僅對第
2
點中的定位作了修改,新增一個全局變量記錄左子樹的最後一個節點。
// 記錄子樹鏈表的最後一個節點,終結點只可能爲只含左子樹的非葉節點與葉節點
protected TreeNode leftLast = null;
public TreeNode Convert(TreeNode root) {
if(root==null)
return null;
if(root.left==null&&root.right==null){
leftLast = root;// 最後的一個節點可能爲最右側的葉節點
return root;
}
// 1.將左子樹構造成雙鏈表,並返回鏈表頭節點
TreeNode left = Convert(root.left);
// 3.如果左子樹鏈表不爲空的話,將當前root追加到左子樹鏈表
if(left!=null){
leftLast.right = root;
root.left = leftLast;
}
leftLast = root;// 當根節點只含左子樹時,則該根節點爲最後一個節點
// 4.將右子樹構造成雙鏈表,並返回鏈表頭節點
TreeNode right = Convert(root.right);
// 5.如果右子樹鏈表不爲空的話,將該鏈表追加到root節點之後
if(right!=null){
right.left = root;
root.right = right;
}
return left!=null?left:root;
}