[AcWing]49. 二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。

要求不能创建任何新的结点,只能调整树中结点指针的指向。

注意

  • 需要返回双向链表最左侧的节点。

例如,输入下图中左边的二叉搜索树,则输出右边的排序双向链表。

QQ截图20181202052830.png

数据范围

树中节点数量 [0,500]

算法思路

中序遍历的基本代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/

void dfs(TreeNode * cur){
if(!cur) return;

dfs(cur -> left);

cout << cur -> val << " ";

dfs(cur -> right);
}

根据观察,考虑在二叉树的中序遍历的基础上,利用 precur 来进行 双链表的构建。

  1. 先找到双链表的第一个节点,它是中序遍历的第一个节点。
  2. 定义一个指针cur,指向当前处理的节点。
  3. 如果cur的左子树不为空,则递归处理左子树。
  4. cur与其前驱节点(即中序遍历中cur的前一个节点)连接起来。
  5. 更新前驱节点为cur
  6. 处理cur的右子树,重复步骤2-4。

image-20230421222517569

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:

TreeNode * head, * pre;

void dfs(TreeNode * cur){
if(!cur) return;

dfs(cur -> left);

// 先找到中序遍历第一个节点作为双链表的head
// 只有当dfs(cur -> left)压栈全部完毕才可能执行这行if,因此head一定是中序遍历的第一个元素
if(!pre) head = cur;
else{
// 将cur与其前驱节点连接起来
pre -> right = cur;
// 构成双向
cur -> left = pre;
}

// 将当前的节点变成下一次回溯的前驱节点
pre = cur;

dfs(cur -> right);
}

TreeNode* convert(TreeNode* root) {
// 在中序遍历的基础上,做点改变 中序遍历:左根右
dfs(root);
return head;
}
};

复杂度分析

  • 时间复杂度O(n):对于每个节点最多只会被访问两次,因此总的时间复杂度为O(n)
  • 空间复杂度O(n):在最坏情况下,退化成单链表,空间复杂度为O(n)