题目
算法思路
将二叉搜索树转化为【排序的循环双向链表】,包括三个方面:
- 【排序】:中序遍历结果就是递增序列
- 【双向】:设前驱节点为
p
r
e
pre
pre,当前节点为
c
u
r
cur
cur,除了执行
pre.right = cur
外,还需要执行cur.left = pre
- 【循环】:设链表头节点为
h
e
a
d
head
head,尾节点为
t
a
i
l
tail
tail,需要执行
head.left = tail
和tail.right = head
综上,我们应该使用中序遍历访问树的各节点 c u r cur cur ,并在访问每一个节点时构建 c u r cur cur 和前驱结点 p r e pre pre 的引用指向关系,整个中序遍历完成后,构建头节点和尾节点的引用指向关系。
算法流程
递归法中序遍历dfs(cur)
:
- 终止条件:当前节点 c u r cur cur 为空
- 递归左子树,
dfs(cur.left)
- 构建引用指向关系:
1.当 p r e pre pre 为空时,说明当前访问的是链表头节点,记为 h e a d head head
2.当 p r e pre pre 非空时,执行pre.right = cur
和cur.left = pre
3.保存当前节点 c u r cur cur ,即,执行pre = cur
- 递归右子树,
dfs(cur.right)
二叉搜索树转链表函数treeToDoublyList(root)
:
- 特例处理:若根节点为空,直接返回
- 初始化:新建一个空节点 p r e pre pre
- 转化为双向链表:调用
dfs(root)
- 构建循环链表:执行
head.left = tail
和tail.right = head
- 返回值:返回链表头节点 h e a d head head
具体代码
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val,Node _left,Node _right) {
val = _val;
left = _left;
right = _right;
}
};
*/
class Solution {
Node pre, head;
public Node treeToDoublyList(Node root) {
if(root == null)return null;
dfs(root);//转化为双向链表
head.left = pre;
pre.right = head;
return head;
}
private void dfs(Node cur){
if(cur == null)return;
dfs(cur.left);//递归左子树
//构建引用指向关系
if(pre == null)head = cur;
else pre.right = cur;
cur.left = pre;
pre = cur;//保存当前节点
dfs(cur.right);//递归右子树
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),n 为二叉树节点总数。
- 空间复杂度: O ( n ) O(n) O(n),最坏情况下,树退化为链表,递归深度达到 n,占用 O ( n ) O(n) O(n) 的栈空间。