剑指 36 二叉搜索树与双向链表
全部刷题与学习记录
原题目
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
4
/ \
2 5
/ \
1 3
考查知识点
分治法、中序遍历
好的解法
首先是剑指上的解法在代码上没怎么看懂,在力扣上找了这篇题解。
思路:二叉搜索树每个节点有left
与right
两个子节点,并且满足left->val
< root->val
< right->val
。在双向链表中每个节点具有pre
与next
两个指针,因为题目规定**“排序”**的原因,同样满足pre->val
< root->val
< right->val
。因此将left
作为pre
,将right
作为next
。
因为满足左-根-右
,所以必然和中序遍历建立关系。
规定头结点head
与尾指针tail
,head
一定是双向链表中最左端的节点,tail
一定是最右端的节点。在中序遍历开始后,root会一直走到二叉搜索树的左下端(即1处),即双向链表的头结点,此时tail=nullptr
,有head=root
, 我们再让tail=root
。然后root会返回到父节点2处(此时root=2,tail=1),这时我们就写 tail -> right = root;
和 root -> left = tail;
然后再更新tail=root
,一直重复。
只看文字描述还是太抽象,一定要结合程序在纸上画一下
注意递归函数inorder
的调用顺序与函数的实际处理部分(不包含递归的部分)就是体现中序遍历的地方
//题解:https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/solution/zi-jie-ti-ku-jian-36-zhong-deng-er-cha-sou-suo-shu/
class Solution {
private:
Node* head, *tail;
public:
Node* treeToDoublyList(Node* root) {
if(!root) {
return nullptr;
}
inorder(root); // 构造出链表的所有结构,除了头连尾和尾连头的两个指针
head -> left = tail; // 补上头连尾
tail -> right = head; // 补上尾连头
return head; // 返回头
}
void inorder(Node* root) {
if(!root) {
return;
}
inorder(root -> left); // 左
if(!tail) {
head = root; // 当tail还不存在,也就是root此时在整个BST的最左边的节点,这个节点就是head
}
else {
tail -> right = root; // 前一个节点的right是当前节点
root -> left = tail; // 当前节点的left是前一个节点
}
tail = root; // 将前一个节点更新为当前节点(所以到最后,tail就会挪到整个BST的最右边的节点,这个节点就是链表的尾节点)
inorder(root -> right); // 右
}
};
l就会挪到整个BST的最右边的节点,这个节点就是链表的尾节点)
inorder(root -> right); // 右
}
};