树的三种遍历三种查找, 还有顺序存储, 中序线索化以及线索化之后如何遍历

在这里插入图片描述
树: 能提高数据的存储, 读取的效率
例如二叉排序树
既可以保证数据的检索速度, 还能保证数据的插入, 删除, 修改的速度

遍历二叉树的三种方式
看父节点的输出顺序
有前序, 中序, 和后序
前序: 先输出父节点, 再遍历左子树和右子树
中序: 先遍历右子树, 在输出父节点, 最后遍历右子树
后序: 先遍历左子树, 再遍历右子树, 最后输出父节点
在这里插入图片描述
示例
手动创建一个这样的二叉树, 并遍历
在这里插入图片描述

public class ErChaShuTest {
    
    
    public static void main(String[] args) {
    
    
        //手动创建二叉树
        NBA root = new NBA(3, "韦德");
        root.left = new NBA(1, "麦迪");
        root.right = new NBA(13, "哈登");
        root.right.left = new NBA(6, "詹姆斯");
        root.right.right = new NBA(24, "科比");
        //创建二叉树对象
        NbaErChaShu nbaErChaShu = new NbaErChaShu(root);
        //分别使用前序, 中序后序进行遍历
        nbaErChaShu.qianxu();
        nbaErChaShu.zhongxu();
        nbaErChaShu.houxu();

    }
}


//树节点
class NBA{
    
    
    public int id;
    public String name;
    public NBA left;
    public NBA right;

    public NBA(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "NBA{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    //前序遍历
    public void qianxu(){
    
    
        System.out.println(this);
        if (this.left!= null){
    
    
            this.left.qianxu();
        }
        if (this.right!= null){
    
    
            this.right.qianxu();
        }
    }
    //中序
    public void zhongxu(){
    
    
        if (this.left!= null){
    
    
            this.left.zhongxu();
        }
        System.out.println(this);
        if (this.right!= null){
    
    
            this.right.zhongxu();
        }
    }
    //后序
    public void houxu(){
    
    
        if (this.left!= null){
    
    
            this.left.houxu();
        }if (this.right!= null){
    
    
            this.right.houxu();
        }
        System.out.println(this);
    }


}

//二叉树
class NbaErChaShu{
    
    
    private NBA root;

    public NbaErChaShu(NBA root) {
    
    
        this.root = root;
    }



    //前序遍历
    public void qianxu(){
    
    
        if (this.root == null){
    
    
            System.out.println("空树");
            return;
        }
        System.out.println("前序遍历结果如下: ");
        root.qianxu();
    }
    //中序遍历
    public void zhongxu(){
    
    
        if (this.root == null){
    
    
            System.out.println("空树");
            return;
        }
        System.out.println("中序遍历结果如下: ");
        root.zhongxu();
    }
    //后序遍历
    public void houxu(){
    
    
        if (this.root == null){
    
    
            System.out.println("空树");
            return;
        }
        System.out.println("后序遍历结果如下: ");
        root.houxu();
    }

}
前序遍历结果如下: 
NBA{
    
    id=3, name='韦德'}
NBA{
    
    id=1, name='麦迪'}
NBA{
    
    id=13, name='哈登'}
NBA{
    
    id=6, name='詹姆斯'}
NBA{
    
    id=24, name='科比'}
中序遍历结果如下: 
NBA{
    
    id=1, name='麦迪'}
NBA{
    
    id=3, name='韦德'}
NBA{
    
    id=6, name='詹姆斯'}
NBA{
    
    id=13, name='哈登'}
NBA{
    
    id=24, name='科比'}
后序遍历结果如下: 
NBA{
    
    id=1, name='麦迪'}
NBA{
    
    id=6, name='詹姆斯'}
NBA{
    
    id=24, name='科比'}
NBA{
    
    id=13, name='哈登'}
NBA{
    
    id=3, name='韦德'}

查找
三种查找方式
前序中序后序
并分析各种查找分别比较了多少次

public class ErChaShuTest {
    
    
    public static void main(String[] args) {
    
    
        //手动创建二叉树
        NBA root = new NBA(3, "韦德");
        root.left = new NBA(1, "麦迪");
        root.right = new NBA(13, "哈登");
        root.right.left = new NBA(6, "詹姆斯");
        root.right.right = new NBA(24, "科比");
        //创建二叉树对象
        NbaErChaShu nbaErChaShu = new NbaErChaShu(root);
        //分别使用前序, 中序后序进行查找
        nbaErChaShu.qianxuchazhao(6);
        nbaErChaShu.zhongxuchazhao(6);
        nbaErChaShu.houxuchazhao(6);

    }
}


//树节点
class NBA{
    
    
    public int id;
    public String name;
    public NBA left;
    public NBA right;

    public NBA(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }

    @Override
    public String toString() {
    
    
        return "NBA{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    //前序查找
    public NBA qianxuchazhao(int no){
    
    
        System.out.println("次数");
        if (this.id == no){
    
    
            return this;
        }
        NBA res = null;
        if (this.left != null){
    
    
             res = this.left.qianxuchazhao(no);
        }
        if (res != null){
    
    
            return res;
        }
        if (this.right != null){
    
    
            res = this.right.qianxuchazhao(no);
        }
        return res;
    }
    //中序查找
    public NBA zhongxuchazhao(int no){
    
    
        NBA res = null;
        if (this.left != null){
    
    
            res = this.left.zhongxuchazhao(no);
        }
        if (res != null){
    
    
            return res;
        }
        System.out.println("次数");
        if (this.id == no){
    
    
            return this;
        }
        if (this.right != null){
    
    
            res = this.right.zhongxuchazhao(no);
        }
        return res;
    }
    //后序查找
    public NBA houxuchazhao(int no){
    
    
        NBA res = null;
        if (this.left != null){
    
    
            res = this.left.houxuchazhao(no);
        }
        if (res != null){
    
    
            return res;
        }
        if (this.right != null){
    
    
            res = this.right.houxuchazhao(no);
        }
        if (res != null){
    
    
            return res;
        }
        System.out.println("次数");
        if (this.id == no){
    
    
            res = this;
        }
        return res;
    }

}

//二叉树
class NbaErChaShu{
    
    
    private NBA root;

    public NbaErChaShu(NBA root) {
    
    
        this.root = root;
    }

    //前序查找
    public void qianxuchazhao(int no){
    
    
        if (root == null){
    
    
            System.out.println("空树");
            return;
        }
        NBA res = root.qianxuchazhao(no);
        if (res == null){
    
    
            System.out.println("树中没有该球员");
            return;
        }
        System.out.println("号码为"+no+"的球员是"+res);
        return;
    }
    //中序查找
    public void zhongxuchazhao(int no){
    
    
        if (root == null){
    
    
            System.out.println("空树");
            return;
        }
        NBA res = root.zhongxuchazhao(no);
        if (res == null){
    
    
            System.out.println("树中没有该球员");
            return;
        }
        System.out.println("号码为"+no+"的球员是"+res);
        return;
    }
    //后序查找
    public void houxuchazhao(int no){
    
    
        if (root == null){
    
    
            System.out.println("空树");
            return;
        }
        NBA res = root.houxuchazhao(no);
        if (res == null){
    
    
            System.out.println("树中没有该球员");
            return;
        }
        System.out.println("号码为"+no+"的球员是"+res);
        return;
    }

}

删除节点
顺序存储二叉树
在这里插入图片描述
线索化二叉树
在这里插入图片描述
将如图所示的二叉树使用中序的方式线索化

public class XiansuohuaTest {
    
    
    public static void main(String[] args) {
    
    

        //测试中序线索化: 4,2,5,1,6,3
        Nnode nnode1 = new Nnode(1, "科比");
        Nnode nnode2 = new Nnode(2, "詹姆斯");
        Nnode nnode3 = new Nnode(3, "韦德");
        Nnode nnode4 = new Nnode(4, "波什");
        Nnode nnode5 = new Nnode(5, "大鸟");
        Nnode nnode6 = new Nnode(6, "乔丹");
        nnode1.setLeft(nnode2);
        nnode1.setRight(nnode3);
        nnode2.setLeft(nnode4);
        nnode2.setRight(nnode5);
        nnode3.setLeft(nnode6);

        XiansuohuaErchashu xiansuohuaErchashu = new XiansuohuaErchashu(nnode1);
        xiansuohuaErchashu.zhongxuXiansuohua(nnode1);

        System.out.println("4号节点的前驱和后继节点是");
        System.out.println(nnode4.getLeft());
        System.out.println(nnode4.getRight());
        System.out.println("5号节点的前驱和后继节点是");
        System.out.println(nnode5.getLeft());
        System.out.println(nnode5.getRight());
        System.out.println("6号节点的前驱和后继节点是");
        System.out.println(nnode6.getLeft());
        System.out.println(nnode6.getRight());
        System.out.println("3号节点的后继节点是");
        System.out.println(nnode3.getRight());
        System.out.println("中序遍历的最后一个节点的righttype是不会等于1的");
        System.out.println(nnode3.getRighttype());


    }
}
//实现了线索化的二叉树:
class XiansuohuaErchashu{
    
    
    public Nnode root;
    public Nnode pre = null; //为了实现线索化而创建的一个辅助指针指向前驱节点

    public XiansuohuaErchashu(Nnode root) {
    
    
        this.root = root;
    }

    //中序线索化
    /**
     * 这个nnode就是当前需要线索化的节点
     * @param nnode
     */
    public void zhongxuXiansuohua(Nnode nnode){
    
    
        //如果nnode是null, 不能线索化, 直接return
        if (nnode == null){
    
    
            return;
        }
        //1. 先线索化左子树
        zhongxuXiansuohua(nnode.getLeft());
        //2. 再线索化当前节点
        if (nnode.getLeft() == null){
    
    
            nnode.setLeft(pre);
            nnode.setLefttype(1);
        }
        if (pre != null && pre.getRight() == null){
    
    
            pre.setRight(nnode);
            pre.setRighttype(1);
        }
        pre = nnode;
        //3. 再线索化右子树
        zhongxuXiansuohua(nnode.getRight());
    }

}

//树节点
class Nnode{
    
    
    public int id;
    public String name;
    public Nnode left;
    public Nnode right;

    //设置前继节点和后继节点的判断哪标识
    public int lefttype = 0;
    public int righttype = 0;

    //构造器
    public Nnode(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }
    //getandset
    public int getId() {
    
    
        return id;
    }

    public void setId(int id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public Nnode getLeft() {
    
    
        return left;
    }

    public void setLeft(Nnode left) {
    
    
        this.left = left;
    }

    public Nnode getRight() {
    
    
        return right;
    }

    public void setRight(Nnode right) {
    
    
        this.right = right;
    }
    public int getLefttype() {
    
    
        return lefttype;
    }

    public void setLefttype(int lefttype) {
    
    
        this.lefttype = lefttype;
    }

    public int getRighttype() {
    
    
        return righttype;
    }

    public void setRighttype(int righttype) {
    
    
        this.righttype = righttype;
    }

    @Override
    public String toString() {
    
    
        return "Nnode{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
4号节点的前驱和后继节点是
null
Nnode{
    
    id=2, name='詹姆斯'}
5号节点的前驱和后继节点是
Nnode{
    
    id=2, name='詹姆斯'}
Nnode{
    
    id=1, name='科比'}
6号节点的前驱和后继节点是
Nnode{
    
    id=1, name='科比'}
Nnode{
    
    id=3, name='韦德'}
3号节点的后继节点是
null
中序线索化的最后一个节点的righttype是不会等于10

遍历线索化的二叉树
由于经过线索化之后, 原本的三种遍历方式已经不能用了, 所以必须有新的遍历方式来遍历线索化之后的二叉树, 这个新的方法不是使用的递归, 而是使用的线性的方式. 所以提高了效率
前面这个数是使用的中序的方式进行的线索化, 所以遍历出来的结果也应当是中序遍历的结果
中序遍历中序线索化的二叉树代码

public class XiansuohuaTest {
    
    
    public static void main(String[] args) {
    
    

        //测试中序线索化: 4,2,5,1,6,3
        Nnode nnode1 = new Nnode(1, "科比");
        Nnode nnode2 = new Nnode(2, "詹姆斯");
        Nnode nnode3 = new Nnode(3, "韦德");
        Nnode nnode4 = new Nnode(4, "波什");
        Nnode nnode5 = new Nnode(5, "大鸟");
        Nnode nnode6 = new Nnode(6, "乔丹");
        nnode1.setLeft(nnode2);
        nnode1.setRight(nnode3);
        nnode2.setLeft(nnode4);
        nnode2.setRight(nnode5);
        nnode3.setLeft(nnode6);

        XiansuohuaErchashu xiansuohuaErchashu = new XiansuohuaErchashu(nnode1);
        xiansuohuaErchashu.zhongxuXiansuohua(nnode1);

        xiansuohuaErchashu.zhongxuXiansuohuaList();


    }
}
//实现了线索化的二叉树:
class XiansuohuaErchashu{
    
    
    public Nnode root;
    public Nnode pre = null; //为了实现线索化而创建的一个辅助指针指向前驱节点

    public XiansuohuaErchashu(Nnode root) {
    
    
        this.root = root;
    }

    //中序线索化
    /**
     * 这个nnode就是当前需要线索化的节点
     * @param nnode
     */
    public void zhongxuXiansuohua(Nnode nnode){
    
    
        //如果nnode是null, 不能线索化, 直接return
        if (nnode == null){
    
    
            return;
        }
        //1. 先线索化左子树
        zhongxuXiansuohua(nnode.getLeft());
        //2. 再线索化当前节点
        if (nnode.getLeft() == null){
    
    
            nnode.setLeft(pre);
            nnode.setLefttype(1);
        }
        if (pre != null && pre.getRight() == null){
    
    
            pre.setRight(nnode);
            pre.setRighttype(1);
        }
        pre = nnode;
        //3. 再线索化右子树
        zhongxuXiansuohua(nnode.getRight());
    }

    //遍历中序线索化之后的二叉树
    public void zhongxuXiansuohuaList(){
    
    
        Nnode cur = root;
        while(cur != null){
    
     //当前节点若为空了, 直接退出
            while (cur.getLefttype() == 0){
    
      //一直向左找到中序遍历的第一个节点
                cur = cur.getLeft();
            }
            System.out.println(cur);  //直接打印当前节点
            while(cur.getRighttype() == 1){
    
      //当前节点若有后继节点, 直接跳过去并打印, 如果没有进这个while说明当前节点有右节点, 也是直接跳过去
                cur = cur.getRight();
                System.out.println(cur);
            }
            cur = cur.getRight(); //直接跳过去右节点, 但是这里就要重新开始判断, 是不是null, 表示最后了退出, 不是最后是不是有左子树, 有得先进左子树
        }
    }
}
Nnode{
    
    id=4, name='波什'}
Nnode{
    
    id=2, name='詹姆斯'}
Nnode{
    
    id=5, name='大鸟'}
Nnode{
    
    id=1, name='科比'}
Nnode{
    
    id=6, name='乔丹'}
Nnode{
    
    id=3, name='韦德'}

猜你喜欢

转载自blog.csdn.net/weixin_45032905/article/details/121321778
今日推荐