方法一:
public void flatten(TreeNode root) {
if(root == null){
return ;
}
//将根节点的左子树变成链表
flatten(root.left);
//将根节点的右子树变成链表
flatten(root.right);
TreeNode temp = root.right;
//把树的右边换成左边的链表
root.right = root.left;
//记得要将左边置空
root.left = null;
//找到树的最右边的节点
while(root.right != null) root = root.right;
//把右边的链表接到刚才树的最右边的节点
root.right = temp;
}
方法二:逆序的先序遍历
前序遍历是:打印根节点-左节点-右节点 这样的顺序,如果是:右节点-左节点-打印根节点,这样遍历完之后,正好跟前序遍历是相反的。
前序遍历完是1,2,3,4,5,6,按照这种新的方式遍历其结果是:6,5,4,3,2,1。
private TreeNode pre = null;
public void flatten(TreeNode root) {
if (root == null)
return;
flatten(root.right);
flatten(root.left);
root.right = pre;
root.left = null;
pre = root;
}
方法三:
public void flatten(TreeNode root) {
while (root != null) {
//左子树为 null,直接考虑下一个节点
if (root.left == null) {
root = root.right;
} else {
// 找左子树最右边的节点
TreeNode pre = root.left;
while (pre.right != null) {
pre = pre.right;
}
//将原来的右子树接到左子树的最右边节点
pre.right = root.right;
// 将左子树插入到右子树的地方
root.right = root.left;
root.left = null;
// 考虑下一个节点
root = root.right;
}
}
}
方法四:栈
思路:借用先序遍历的思想。
正常的先序遍历非递归代码:如果在这里加入记录前一个结点的pre,将pre的左右子结点改成null和当前结点,等到再出栈的时候,它的右结点已经变了,无法再继续遍历。
public static void preOrderStack(TreeNode root) {
if (root == null) {
return;
}
Stack<TreeNode> s = new Stack<TreeNode>();
while (root != null || !s.isEmpty()) {
while (root != null) {
System.out.println(root.val);
s.push(root);
root = root.left;
}
root = s.pop();
root = root.right;
}
}
因此将之前的先序遍历算法进行修改,先将左右子结点入栈,然后再改变当前结点的左右子结点。
public void flatten(TreeNode root){
if(root==null) return;
Stack<TreeNode> stack=new Stack<>();
stack.push(root);
TreeNode pre=null;
while(!stack.isEmpty()){
TreeNode node=stack.pop();
if(pre!=null){
pre.right=node;
pre.left=null;
}
if(node.right!=null){
stack.push(node.right);
}
if(node.left!=null){
stack.push(node.left);
}
pre=node;
}
}