问题描述:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。
要求不能创建任何新的结点,只能调整树中结点指针的指向。
注意:
需要返回双向链表最左侧的节点。例如,输入下图中左边的二叉搜索树,则输出右边的排序双向链表。
2021-5-7 晚上21:20 牛客网
巧妙地利用二叉搜索树的特点,二叉搜索树是树的中序遍历,就在中序递归遍历的基础上改了一点点,用一个pre指针保存中序遍历的前一个结点。因为是中序遍历,遍历顺序就是双线链表的建立顺序;
每一个结点访问时它的左子树肯定被访问过了,所以放心大胆的改它的left指针,不怕树断掉;同理,pre指向的结点保存的数肯定小于当前结点,所以其左右子树肯定都访问过了,所以其right指针也可以直接改。最后需要一直向左找到双向链表的头结点。
class Solution {
public:
TreeNode* pre=NULL;
TreeNode* convert(TreeNode* root) {
dfs(root);
while(root && root->left) root = root->left;
return root;
}
void dfs(TreeNode* root){
if(!root) return;
dfs(root->left);
root->left = pre;
if(pre) pre->right = root;
pre = root;
dfs(root->right);
}
};
二叉搜索树转化为有序的链表,采用的遍历方式是中序遍历,要求是调整节点指针的指向,只需要考虑如果是两个节点的话该如何调整指针的指向,前面节点的右指针指向后面的节点,后面的节点左指针指向前面的节点。更新时需要更新 tail 指针作为下一次的前面的节点。
考虑时不要把一整棵树考虑进去,太复杂了。参考链接
class Solution {
private:
TreeNode* head=nullptr;//双链表的头结点
TreeNode* tail=nullptr;//上一次遍历到的尾节点
public:
void dfs(TreeNode* root)
{
if(!root) return;
dfs(root->left);
if(!tail) head=root;
else
{
tail->right=root;
root->left=tail;
}
tail= root;
dfs(root->right);
}
TreeNode* Convert(TreeNode* root) {
if(!root) return nullptr;
dfs(root);
return head;
}
};
题目描述
剑指 Offer 36. 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
与上一题不同的是需要首尾链表相连,因此需要在中序遍历中过程中记录头结点和尾节点,头结点就是一开始遍历的时候的节点也就是pre节点为空的时候,尾节点是中序遍历末尾的节点,也就是遍历结束的节点指向的pre节点。
采用中序遍历递归,需要修改的是left节点和right节点,因为是中序遍历,那么遍历到root节点时,left节点已经遍历过了,pre指向的结点保存的数肯定小于当前结点,所以其左右子树肯定都访问过了,所以其right指针也可以直接改。
class Solution {
public:
Node* pre=nullptr,*head;
Node* treeToDoublyList(Node* root) {
if(!root) return root;
dfs(root);
head->left = pre;
pre->right = head;
return head;
}
void dfs(Node* root)
{
if(!root) return;
dfs(root->left);
root->left = pre;
if(pre) pre->right = root;
else head=root;
pre = root;
dfs(root->right);
}
};