只移动树的左右指针将二叉树转换成双向链表,链表遍历和二叉树中序遍历一致

题目要求:

只移动树的左右指针将二叉树转换成双向链表,链表遍历和二叉树中序遍历一致。过程不能创建新的对象。

思路:

将一棵树的都抽象为父节点,左节点,右节点。中序遍历的遍历顺序是 左中右。所以:

1. 从根节点开始先检索左子树,一直检索到某个节点A的子节点是叶子节点(C、D)。对A的左以下操作:

  • 将C的右节点指向其父节点A
  • 将D的左指针指向A

2. 将CAD作为一个整体即一个节点1,节点1的右指针是D 的右指针。节点1的做指针就是C的做指针。

同时将原来A 的兄弟节点做以上同样的操作得到节点2(acd)。同样将1、2和他们的父节点k做以上的两个步骤。

以下是代码实现:

假设二叉树对象是:

public class TestObject {
    private int data;
    private TestObject left;
    private TestObject right;
}

实现是: 

  /**
     * 二叉树变为双向链表
     * @param last 双向链表的最后一个元素,初始为null;
     * @param tree 当前解析的左中右  的中节点 初始为树的根节点
     * @return
     */
/**
     * 二叉树变为双向链表
     * @param last 双向链表的最后一个元素,初始为null;
     * @param tree 当前解析的左中右  的中节点 初始为树的根节点
     * @return
     */
    public static TestObject testMethod1(TestObject last, TestObject tree) {
        if (tree == null) {
            return null;
        }
        TestObject left = tree.getLeft();
        TestObject right = tree.getRight();

        //左边的元素已经是变化过的 左中右的  左
        if (left != null) {
            //子节点是叶子节点时 就是链表的最后一个节点
            if(left.getLeft() == null && left.getRight() == null){
                if(last != null){
                    last.setRight(left);
                    left.setLeft(last);
                }
                last = left;
            } else {
                //非叶子节点,获取节点的左边序列  leftTreeLast为左边序列的最后一个元素
                TestObject leftTreeLast = testMethod1(last, left);
                //最后一个节点中加入左边的节点
                if (last != null) {
                    if (leftTreeLast != null) {
                        last.setRight(leftTreeLast);
                        leftTreeLast.setLeft(last);
                        leftTreeLast.setRight(null);
                        last = leftTreeLast;
                    }
                } else {
                    if (leftTreeLast != null) {
                        leftTreeLast.setRight(last);
                        last = leftTreeLast;
                        last.setRight(null);
                    }
                }
            }
        }

        //序列的最后一个元素直线当前节点,即左中右的  中
        if(last != null) {
            last.setRight(tree);
            //根节点的左指针指向双向链表的最后节点
            tree.setLeft(last);
            last = last.getRight();
            last.setRight(null);
        } else {
            //走到这里表示,左边没有子节点
            last = tree;
        }

        //序列的最后一个元素直线当前节点,即左中右的  右
        TestObject rightTreeLast = null;
        //获取右节点
        if (right != null) {
            //子节点是叶子节点时 就是链表的最后一个节点
            if(right.getLeft() == null && right.getRight() == null){
                if(last != null){
                    last.setRight(right);
                    right.setLeft(last);
                }
                last = right;
            } else {
                //非根节点,获取右边的序列
                last = testMethod1(last, right);
            }
        }

        last.setRight(null);
        return last;
    }

上面的代码还是太复杂,优化之后是:

/**
     * 二叉树变为双向链表
     * @param last 双向链表的最后一个元素,初始为null;
     * @param tree 当前解析的左中右  的中节点 初始为树的根节点
     * @return
     */
    public static TestObject testMethod(TestObject last, TestObject tree) {
        if (tree == null) {
            return null;
        }

        TestObject left = tree.getLeft();
        TestObject right = tree.getRight();

        //子节点是叶子节点时,则设置双向链表最新的元素时该元素
        if(left == null && right == null){
            if(last != null){
                last.setRight(tree);
                tree.setLeft(last);
            }
            last = tree;
            return last;
        }

        //左中右的  左
        //获取左节点的
        if (left != null) {
            //非根节点,获取左边的序列
            last = testMethod(last, left);
        }

        //即左中右的  中
        //序列的最后一个元素直线当前节点,即左中右的  中
        if(last != null) {
            last.setRight(tree);
            //根节点的左指针指向双向链表的最后节点
            tree.setLeft(last);
            last = last.getRight();
            last.setRight(null);
        } else {
            //走到这里表示,左边没有子节点
            last = tree;
        }

        即左中右的  右
        if (right != null) {
            //非根节点,获取右边的序列
            last = testMethod(last, right);
        }
        last.setRight(null);
        return last;
    }

接下来就可以使用测试方法了:

package com.zhong.demo.usultestdemo.testdemo.demo_3;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * @author yi xiangxuehai
 * @date 2021/3/30-14:28
 */
public class TestMethod {

    public static void main(String[] args) {

        InputStreamReader isr = new InputStreamReader(System.in);
        BufferedReader br = new BufferedReader(isr);

        System.out.println("根节点值:");
        try {
            String value = br.readLine();
            if(!value.equals("0")) {
                TestObject testObject = new TestObject();
                testObject.setData(Integer.valueOf(value));
                inputTree(testObject, br);
                System.out.print("中序遍历 ");
                centerScan(testObject);
                System.out.println();
                TestObject linked = testMethod(null, testObject);
                System.out.print("链表 ");
                linkedScan(linked);
                System.out.println();

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //输入二叉树,先中再左,再右。以0表示不需要子节点
    public static void inputTree(TestObject testObject,  BufferedReader br){

        try {
                System.out.println("请输入"+ testObject.getData() +"的左节点值(0表示无):");
                String value = br.readLine();
                if(!value.equals("0")) {
                    TestObject left = new TestObject();
                    testObject.setLeft(left);
                    left.setData(Integer.valueOf(value));
                    inputTree(left, br);
                }

                System.out.println("请输入"+ testObject.getData() +"的右节点值(0表示无):");
                value = br.readLine();
                if(!value.equals("0")) {
                    TestObject right = new TestObject();
                    right.setData(Integer.valueOf(value));
                    testObject.setRight(right);
                    inputTree(right, br);
                }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //中序遍历
    public static void centerScan(TestObject tree) {
        if (tree.getLeft() != null) {
            centerScan(tree.getLeft());
        }
        System.out.print(tree.getData() + " ");

        if (tree.getRight() != null) {
            centerScan(tree.getRight());
        }
    }

//遍历链表
    public static void linkedScan(TestObject tree){
        TestObject testObject = tree;
        while(testObject.getLeft() != null){
            testObject = testObject.getLeft();
        }

        while (testObject != null){
            System.out.print(testObject.getData()+ " ");
            testObject = testObject.getRight();
        }
    }

}

测试结果如下:

根节点值:
5
请输入5的左节点值:
4
请输入4的左节点值:
2
请输入2的左节点值:
0
请输入2的右节点值:
0
请输入4的右节点值:
3
请输入3的左节点值:
0
请输入3的右节点值:
0
请输入5的右节点值:
6
请输入6的左节点值:
7
请输入7的左节点值:
0
请输入7的右节点值:
0
请输入6的右节点值:
0
中序遍历:2 4 3 5 7 6 
链表:2 4 3 5 7 6 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值