题目描述:
输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
树节点定义如下:
public class TreeNode {
int val = 0;
TreeNode left = null;
TreeNode right = null;
public TreeNode(int val) {
this.val = val;
}
}
对于一棵二叉搜索树如:
转换为双向链表后将如下:
可以看到,二叉搜索树转换为双向链表后的节点顺序,正是其二叉树的中序遍历,所以我们可以通过对中序遍历的加工来改造二叉树,使其变为双向链表,递归方法代码如下:
//递归方法解决
//用来记录要返回的链表头
public TreeNode resHead = null;
//记录前驱节点,这样才能形成双向链表
public TreeNode pre = null;
public TreeNode ConvertSub(TreeNode pRoot) {
//若输入的树为空,则直接退出
if (pRoot == null) return null;
//中序遍历的顺序,先遍历左节点
ConvertSub(pRoot.left);
//第一次访问
if (resHead == null) {
resHead = pRoot;
pre = pRoot;
} else {
//使前驱节点的右指针指向下一个节点
pre.right = pRoot;
//使下一个节点的左指针指向前驱节点
pRoot.left = pre;
//更新前驱节点
pre = pRoot;
}
//中序遍历的顺序,再遍历右节点
ConvertSub(pRoot.right);
//返回头结点
return resHead;
}
当然,既然是用中序遍历就能做出来的,那么自然就有通过非递归的中序遍历改造来的解决方法,这里如果对二叉树的非递归遍历不熟悉的,可以看我的另外一篇博客 数据结构------二叉树的遍历(递归与非递归方法)。
import java.util.Stack;
public TreeNode ConvertSub(TreeNode pRoot) {
//利用栈来实现非递归的中序遍历
Stack<TreeNode> stack = new Stack<>();
TreeNode pre = null, resHead = null;
while (true) {
//当前节点入栈后,不停遍历左节点,直到左节点为空的位置
while (pRoot != null) {
stack.push(pRoot);
pRoot = pRoot.left;
}
//唯一出口,栈为空时就return
if (stack.empty()) return resHead;
//出栈一个节点
pRoot = stack.pop();
//根据题目改造成双向链表
if (resHead == null) {
pre = pRoot;
resHead = pRoot;
} else {
pre.right = pRoot;
pRoot.left = pre;
pre = pRoot;
}
//因为中序遍历左根右的顺序,这里相当于再对其右子树进行中序遍历
pRoot = pRoot.right;
}
}
递归方法虽然好理解,但递归总是要耗费更多的内存空间来完成,能循环还是尽量使用循环的方法吧。