JAVA递归实现线索化二叉树

JAVA递归实现线索化二叉树

基础理论

首先,二叉树递归遍历分为先序遍历、中序遍历和后序遍历。

先序遍历为:根节点+左子树+右子树

中序遍历为:左子树+根节点+右子树

后序遍历为:左子树+右子树+根节点

(只要记住根节点在哪里就是什么遍历,且都是先左再右)

线索化

现在有这么一棵二叉树,它的数据结构由左节点+权+右节点构成。

可以看到4,5,6,7这几个节点的左右节点空间被浪费了。因此,线索化是指有效利用这些空间。

中序遍历的顺序为:4 2 5 1 6 3 7

现在引入前驱节点以及后继节点。

前驱节点:线索化二叉树时,一个节点的前一个节点

后继节点:线索化二叉树时,一个节点的后一个节点

(例如下图:根据中序遍历,5的前驱节点是2 , 5的后继节点是1)

(中序遍历)实现线索化二叉树

定义数据结构ThreadedNode

    //节点的权
    int value;
    //左儿子
    ThreadedNode leftNode;
    //右儿子
    ThreadedNode rightNode;
    //标识指针类型,其中0,1分别表示有无线索化,默认为0
    int leftType;
    int rightType;

中序遍历

//中序遍历
public void midShow() {
   //左子节点
   if(leftNode!=null) {
      leftNode.midShow();
   }
   //当前节点
   System.out.println(value);
   //右子节点
   if(rightNode!=null) {
      rightNode.midShow();
   }
}

这里使用递归的方式来实现。我们先把问题简单化,只看红圈的部分,如下图

定义一个节点pre用来存储当前节点,类似指针。

从根节点1开始递归,如果当前节点为空,返回,到4,此时4的前驱结点为null,结点5的前驱结点为2

遍历到5的时候指向前驱结点2,前驱结点2为上一层递归的指针,因此指向它的前驱结点就行,再把左指针类型置为1

如果当前节点的前驱结点pre的右指针为null,则将它设置为当前节点,此时即4的后继结点为2,并将右指针类型置为1

每处理一个节点,当前节点是下一个节点的前驱节点

线索化二叉树ThreadedBinaryTree


    //中序线索化二叉树
    public void threadNodes() {
        threadNodes(root);
    }

    public void threadNodes(ThreadedNode node) {
        //当前节点如果为null,直接返回
        if(node==null) {
            return;
        }
        //处理前驱节点
        if(node.leftNode==null){
            //让当前节点的左指针指向前驱节点
            node.leftNode=pre;
            //改变当前节点左指针的类型
            node.leftType=1;
        }
        //处理前驱的右指针,如果前驱节点的右指针是null(没有指下右子树)
        if(pre!=null&&pre.rightNode==null) {
            //让前驱节点的右指针指向当前节点
            pre.rightNode=node;
            //改变前驱节点的右指针类型
            pre.rightType=1;
        }
        //每处理一个节点,当前节点是下一个节点的前驱节点
        pre=node;
    }

现在再把上面这段代码按照中序遍历的方式放在中间,进行递归

        //当前节点如果为null,直接返回
        if(node==null) {
            return;
        }
        //处理左子树
        threadNodes(node.leftNode);
//----------------------------------------------------------
        //处理前驱节点
        if(node.leftNode==null){
            //让当前节点的左指针指向前驱节点
            node.leftNode=pre;
            //改变当前节点左指针的类型
            node.leftType=1;
        }
        //处理前驱的右指针,如果前驱节点的右指针是null(没有指下右子树)
        if(pre!=null&&pre.rightNode==null) {
            //让前驱节点的右指针指向当前节点
            pre.rightNode=node;
            //改变前驱节点的右指针类型
            pre.rightType=1;
        }
        //每处理一个节点,当前节点是下一个节点的前驱节点
        pre=node;
//-----------------------------------------------------------
        //处理右子树
        threadNodes(node.rightNode);
    }

现在编写测试方法

package demo7;

public class TestThreadedBinaryTree {

    public static void main(String[] args) {
        //创建一颗树
        ThreadedBinaryTree binTree = new ThreadedBinaryTree();
        //创建一个根节点
        ThreadedNode root = new ThreadedNode(1);
        //把根节点赋给树
        binTree.setRoot(root);
        //创建一个左节点
        ThreadedNode rootL = new ThreadedNode(2);
        //把新创建的节点设置为根节点的子节点
        root.setLeftNode(rootL);
        //创建一个右节点
        ThreadedNode rootR = new ThreadedNode(3);
        //把新创建的节点设置为根节点的子节点
        root.setRightNode(rootR);
        //为第二层的左节点创建两个子节点
        rootL.setLeftNode(new ThreadedNode(4));
        ThreadedNode fiveNode = new ThreadedNode(5);
        rootL.setRightNode(fiveNode);
        //为第二层的右节点创建两个子节点
        rootR.setLeftNode(new ThreadedNode(6));
        rootR.setRightNode(new ThreadedNode(7));
        //中序遍历树
        binTree.midShow();
        System.out.println("===============");
        //中前线索化二叉树
        binTree.threadNodes();
        binTree.threadIterate();
    }

}

原文地址:https://www.cnblogs.com/senup/p/12417117.html

时间: 2024-12-07 16:45:27

JAVA递归实现线索化二叉树的相关文章

【数据结构】线索化二叉树中序线索化的递归写法和非递归写法

二叉树是一种非线性结构,遍历二叉树几乎都是通过递归或者用栈辅助实现非递归的遍历.用二叉树作为存储结构时,取到一个节点,只能获取节点的左孩子和右孩子,不能直接得到节点的任一遍历序列的前驱或者后继. 为了保存这种在遍历中需要的信息,我们利用二叉树中指向左右子树的空指针来存放节点的前驱和后继信息.所以引入了线索化二叉树.下面我们讲一下线索化二叉树中序线索化的两种实现方法: (1).递归实现中序线索化二叉树 首先我们先看一下线索化二叉树的结构 enum PointerTag{ THREAD, LINK 

java实现线索化二叉树的前序、中序、后续的遍历(完整代码)

java实现线索化二叉树的前序.中序.后续的遍历 比如创建一个二叉树 1 / 3 6 / \ / 8 10 14 线索化二叉树几个概念: n个节点的二叉链表中含有n+1 [公式2n-(n-1)=n+1]个空指针域.利用二叉链表中的空指针域,存放指向该节点在某种遍历次序下的前驱和后继节点的指针(这种附加指针成为线索).如下面的就是6+1=7个空指针域 (8,10,14各有连个指针没有指向 6有一个) 加上了线索的二叉链表称为线索链表,相应的二叉树称为线索二叉树.分为前序线索二叉树.中序线索二叉树.

数据结构与算法---线索化二叉树(Threaded BinaryTree)

先看一个问题 将数列 {1, 3, 6, 8, 10, 14  } 构建成一颗二叉树 问题分析: 当我们对上面的二叉树进行中序遍历时,数列为 {8, 3, 10, 1, 6, 14 } 但是 6, 8, 10, 14 这几个节点的 左右指针,并没有完全的利用上. 如果我们希望充分的利用 各个节点的左右指针, 让各个节点可以指向自己的前后节点,怎么办? 解决方案-线索二叉树 线索二叉树基本介绍 1.n个结点的二叉链表中含有n+1  [公式 2n-(n-1)=n+1] 个空指针域.利用二叉链表中的空

数据--第37课 - 线索化二叉树

第37课 - 线索化二叉树 1. 问题 在一些项目中需要频繁的遍历二叉树,但是二叉树的遍历比单链表的遍历复杂多了,并且递归总是会后额外的开销. 2. 线索化二叉树 线索化二叉树指的是将二叉树中的结点进行逻辑意义上的“重新排列”,使其可以线性的方式访问每一个结点. 二叉树线索化后每个结点都有一个线性下标,用过这个下标可以快速访问结点,而不需要遍历二叉树. 3. 方法1 利用结点中的空指针,使其指向后继结点. 算法思想: 初始化位置指针:p = NULL: 前序遍历二叉树: 若p不为空,将p->le

线索化二叉树

二叉树的遍历运算是将二叉树中节点按一定规律线性化的过程,当二叉链表作为存储结构时,只能找到节点的左.右孩子信息,而不能直接得到节点在遍历序列中的前驱和后继信息.线索化二叉树能够解决这样的问题,将二叉链表中的空指针域填上相应节点的遍历前驱或后继节点的地址,而前驱和后继的地址只能在动态的遍历过程中才能得到.可以按照不同的遍历次序进行线索化,先序遍历.遍历过程中的节点的前驱.后继信息保存下来.下面是线索化二叉树节点结构: 其中,_left和_right表示节点的左.右孩子,_leftTag和_righ

中序线索化二叉树

中序线索化二叉树 1 void Tree::_inTree(Node * root, Node * &pre) { 2 if (root == NULL) { // 结点为空, 1:二叉树为空 2:已到达右子树的最后一个右结点的 rchild 3 return; 4 } 5 _inTree(root->lchild, pre); // 到达当前结点的左子树的底部左结点 6 if (root->lchild == NULL) { 7 root->ltag = nChild; //

数据结构 树的创建(线索化二叉树)

//二叉树的线索化 #include<stdio.h> #include<stdlib.h> #include<string.h> //定义二叉树线索化节点 typedef struct _TreeNode{ char data; char lefttag;//0表示没有线索化,1表示线索化---每次创建节点都会初始化 所以所有节点默认都是0 char righttag; struct _TreeNode * leftchild; struct _TreeNode *

数据结构例程——线索化二叉树(中序)

本文是数据结构基础系列(6):树和二叉树中第14课时线索二叉树的例程. #include <stdio.h> #include <malloc.h> #define MaxSize 100 typedef char ElemType; typedef struct node { ElemType data; int ltag,rtag; //增加的线索标记 struct node *lchild; struct node *rchild; } TBTNode; void Creat

线索化二叉树的构建与先序,中序遍历(C++版)

贴出学习C++数据结构线索化二叉树的过程, 方便和我一样的新手进行测试和学习 同时欢迎各位大神纠正. 不同与普通二叉树的地方会用背景色填充 //BinTreeNode_Thr.h 1 enum PointTag 2 {Link,Thread}; 3 4 template<typename ElemType> 5 struct BinTreeNode 6 { 7 ElemType data; //数据元素 8 PointTag LTag,RTag; //左标志,右标志 9 BinTreeNode