题目描述
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
解题思路
本题很容易想到用中序遍历,但是中序遍历只能访问当前的节点,如果需要连成链表,我们需要知道当前节点需要连在那个节点的后面。因此,我们在中序遍历的时候,再增加一个参数,代表当前节点需要连接在那个节点后面。因此是递归调用,所以我们要传递引用
// 定义函数 cnvert 将 cur 转变成 双向链表
void convert(Node* cur, Node*& last){
if(cur == nullptr) return nullptr;
// 中序遍历 的 套路
convert(cur->left,last);
cur->right = last;
if(last!=nullptr) last->right = cur;
last = cur;
// cur 右边得到的结果要挂在 cur 的右边
convert(cur->right,last);
}
完整代码
本题还要求是循环链表,因此我们在转换之后,还需要找到头和尾,进行连接。
class Solution {
public:
// 如果要原地, 就要使用中序遍历,同时要有一个可以连接的节点
// root 是遍历的当前节点 last 记录遍历的上一个节点
void convert(Node* root, Node*& last){
if(root == nullptr) return ;
convert(root->left,last);
root->left = last;
if(last!=nullptr){
last->right = root;
}
last = root;
convert(root->right,last);
}
Node* treeToDoublyList(Node* root) {
if(root==nullptr) return nullptr;
Node* last = nullptr;
convert(root,last);
// 往前找到head, 往后找到tail
Node* head = root, *tail = root;
while(head->left!=nullptr){
head = head->left;
}
while(tail->right!=nullptr){
tail = tail->right;
}
// 首尾相连
head->left = tail;
tail->right =head;
return head;
}
};
二叉树的递归套路
- 假设 以 X 节点为头,假设可以向X 的左子树 和 X 的右子树要任何信息。
- 在上一步假设下,套路以X为头结点,得到答案的可能性。
- 列出所有可能性后,确定到底需要向左子树和右子树要什么样的信息。
- 把左子树的信息和右子树的信息全采集,即任何一棵子树都需要返回的信息 S.
- 递归函数都返回S, 每颗子树都这么要求
- 写代码,在代码中考虑如何把左子树的信息和右子树的信息整合出整棵树的信息。
- 来源左神,多多实践,方能融会贯通.
大家一起加油!!!!