这道题是将一颗二叉搜索树转换为循环的双向链表。
观察后,发现可以用DFS来做。由于二叉搜索树的有序特性。可以发现,如果将整棵树按照中序遍历进行输出,得到的就是一个有序序列。因为二叉搜索树的左子树都比根节点小,右子树都比根节点大。
中序遍历下,按照 左子树 -> 根节点 -> 右子树 的顺序进行访问。
则第一个访问到的节点是整棵树最左侧的节点,也即是最小的节点。进行模拟可以发现,中序遍历得到的结果是从小到大有序的。
于是我们考虑用DFS进行中序遍历,并按照顺序连接前后的节点即可,我们需要一个pre
变量,来存储前驱节点。当遍历访问当前节点时,将当前节点与前驱节点进行连接即可。另外,由于题目要求得到一个循环链表,则还需要两个变量first
和last
,来记录整个链表的头节点和尾节点,在遍历完成后将这两个节点相连
(回顾后,发现可以不用pre
节点,由于每次都要更新当前节点为last
,其实last
节点在整个过程中是和pre
节点一致的,使用last
节点来代替pre
节点的作用即可)
代码如下
class Solution {
Node first = null;
Node last = null;
Node pre = null;
public Node treeToDoublyList(Node root) {
if (root == null) return null;
dfs(root);
// 将first和last相连
first.left = last;
last.right = first;
return first;
}
// 中序遍历
private void dfs(Node node) {
if (node == null) return;
// 第一个没有左儿子的节点, 就是最左侧的节点, 链表的第一个节点
if (node.left == null && first == null) first = node;
dfs(node.left);
// 访问当前节点
if (pre != null) { // 若存在前驱节点, 则相连
// 因为是中序遍历, 是在遍历完左子树后, 再改变当前节点的左指针, 所以不会有影响
pre.right = node;
node.left = pre;
}
// 更新当前节点为前驱节点
pre = node;
// 用当前节点更新last节点, 一直更新下去, last最终就是最后一个被访问的节点
last = node;
dfs(node.right);
}
}
去掉pre
节点
class Solution {
Node first = null;
Node last = null;
public Node treeToDoublyList(Node root) {
if (root == null) return null;
dfs(root);
// 将first和last相连
first.left = last;
last.right = first;
return first;
}
// 前序遍历
private void dfs(Node node) {
if (node == null) return;
if (node.left == null && first == null) first = node; // 最左侧的节点, 第一个节点
dfs(node.left);
// 访问当前节点
if (last != null) { // 若存在前驱节点, 则相连
last.right = node;
node.left = last;
}
// 更新当前节点为前驱节点
last = node;
dfs(node.right);
}
}