题目
来源: Leetcode 剑指 Offer 36. 二叉搜索树与双向链表
问题: 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
DFS旋转 + 一趟遍历维护链表
基本思路
核心: "二叉搜索树的中序遍历是有序的。
我们可以通过左旋转,将每棵子树的右孩子都甩到左边,仍能保持二叉搜索树的性质不变。(当然, 也可以使用右旋转,思路都是一样的)
因此, 只需要递归遍历所有节点,并按照上述方法改造二叉搜索树,即可获得有序的单链表。
最后只需要一趟遍历,维护双向链表和循环链表的性质。
实现代码
class Solution {
public:
// 左旋转,返回新的父节点
Node* left_rotate(Node* n){
Node* root = n->right;
n->right = root->left;
root->left = n;
return root;
}
Node* dfs(Node* n){
if(!n) return nullptr;
// 一直左旋转到没有右孩子
while(n->right)
n = left_rotate(n);
// 更新前驱
n->left = dfs(n->left);
return n;
}
Node* treeToDoublyList(Node* root) {
if(!root) return nullptr;
Node* rear = dfs(root);
Node* pre = rear;
root = rear->left;
// 维护双向链表属性
while(root){
root->right = pre;
pre = root;
root = root->left;
}
// 维护循环列表属性
if(pre != rear){
root = pre;
root->left = rear;
rear->right = root;
}else{
root = rear;
rear->right = rear;
rear->left = rear;
}
return root;
}
};
后序遍历同时构建链表
基本思路
考虑到二叉搜索的特点:
左子树中的所有值 < 根 < 右子树中的所有值
既然如此,若左子树中的值和右子树中的值已经构造成有序的链表时,根只需要链接到左右子树之间就好了,不仅如此该函数从该特性出发就是符合递归的特点的。
为了方便链接,每个节点维护部分区间的链表的头尾节点。
代码实现
#define head(x) get<0>((x))
#define rear(x) get<1>((x))
tuple<Node*, Node*> dfs(Node* root) {
tuple<Node*, Node*> l = make_tuple(root, root);
tuple<Node*, Node*> r = make_tuple(root, root);
tuple<Node*, Node*> res;
if (root->left && root->right) {
l = dfs(root->left);
r = dfs(root->right);
// 根节点与左有序双向链表链接
root->left = rear(l);
rear(l)->right = root;
// 根节点与右有序双向链表链接
root->right = head(r);
head(r)->left = root;
// 维护循环链表特性
head(l)->left = rear(r);
rear(r)->right = head(l);
res = make_tuple(head(l), rear(r));
}
else if (root->left) {
// 根节点与左有序双向链表链接
l = dfs(root->left);
root->left = rear(l);
rear(l)->right = root;
// 维护循环链表特性
head(l)->left = root;
root->right = head(l);
res = make_tuple(head(l), root);
}
else if (root->right) {
// 根节点与右有序双向链表链接
r = dfs(root->right);
root->right = head(r);
head(r)->left = root;
// 维护循环链表特性
root->left = rear(r);
rear(r)->right = root;
res = make_tuple(root, rear(r));
}
else {
root->left = root;
root->right = root;
res = make_tuple(root, root);
}
return res;
}
Node* treeToDoublyList(Node* root) {
if (!root) return nullptr;
return head(dfs(root));
}