剑指 Offer 36. 二叉搜索树与双向链表
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:
思路:
考虑到二叉搜索树的性质“左树上的结点值小于根节点值,根节点值小于右树上的结点值”,对给定二叉树搜索树做中序遍历即可,期间将“打印操作”(一般的中序遍历二叉树流程中的“打印操作”)换成左右指针的连接操作。
下面是我自己的写法:
listH是双向链表的头节点的前一个结点,可视作“虚拟头节点”;
递归函数f(Node root, Node listH)的参数分别表示:
- 目前遍历到搜索二叉树上的结点root,
- 目前双向链表已建成部分的最后结点是listH;
所以,函数内容是 将以root为头节点的子树做中序遍历得到的双向链表 接到 listH后面,并返回 接上之后的结尾结点。
另外,主函数和递归函数内容的设计 保证了 递归函数参数root不为null。
public Node treeToDoublyList(Node root) { // in-order traversal
if(root==null){return null;}
Node listH = new Node();
Node end = f(root,listH);
Node head = listH.right;
end.right=head;// 这两句话是看题意得到的,把新双向链表的收尾连起来
head.left=end;
return head;
}
public Node f(Node root,Node listH){
if(root.left==null&&root.right==null){// root是叶节点 作为 base case
Node newNode = new Node(root.val);// 把 newNode 接到 listH的后面
listH.right = newNode;
newNode.left=listH;
return newNode;// new end
}
Node end = listH;
//二叉树的中序遍历: 左
if(root.left!=null){
end = f(root.left,listH);// update end
}
//二叉树的中序遍历: 中
Node newNode = new Node(root.val);
end.right = newNode;
newNode.left=end;
end = newNode;// update end
//二叉树的中序遍历: 右
if(root.right!=null){
end = f(root.right,end);// update end
}
return end;
}
LeetCode大佬的写法
巧妙地将head,pre设置成了全局变量;
对二叉树做中序遍历时,pre是双向链表已建成部分的最后一个节点,相当于上面的listH。
Node head,pre;
public Node treeToDoublyList1(Node root) { // in-order traversal
if(root==null){
return null;
}
dfs(root);
head.left=pre;
pre.right=head;
return head;
}
public void dfs(Node cur){
if(cur==null){return;}
dfs(cur.left);
if(pre==null){
head=cur;
pre=head;
}else{
pre.right=cur;
}
cur.left=pre;
pre = cur;
dfs(cur.right);
}