慕课讨论区里的大神答案很牛,不过是java的代码,我后面贴上自己方法二的c++代码
讲一点递归的心得:递归是个整体工程,需要做好:1)处理好递归的最后一层,或者说极端情况。2)调用递归函数时,要搞清楚函数的参数和返回值。3)把函数本身当做递归的一层来写。
链接:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5
来源:牛客网方法一:非递归版
解题思路:
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;
}
这里我贴一下自己方法二的C++代码
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree){
if(pRootOfTree == NULL)
return NULL;
if(pRootOfTree->left == NULL && pRootOfTree->right == NULL)
return pRootOfTree;
// 1.将左子树构造成双链表,并返回链表头节点
TreeNode* left = Convert(pRootOfTree->left);
TreeNode* p = left;
// 2.定位至左子树双链表最后一个节点
while(p!=NULL && p->right!=NULL){
p = p->right;
}
// 3.如果左子树链表不为空的话,将当前root追加到左子树链表
if(left!=NULL){
p->right = pRootOfTree;
pRootOfTree->left = p;
}
// 4.将右子树构造成双链表,并返回链表头节点
TreeNode *right = Convert(pRootOfTree->right);
// 5.如果右子树链表不为空的话,将该链表追加到root节点之后
if(right!=NULL){
right->left = pRootOfTree;
pRootOfTree->right = right;
}
return left!=NULL?left:pRootOfTree;
}
};