您的位置:首页 > 其它

线索二叉树的建立及其遍历访问操作

2017-04-16 17:04 459 查看
线索二叉树(中序),建立、访问

对于线索二叉树有先序、中序、后序三种,但是只有中序线索二叉树才能获得任意节点的前驱和后继节点(实际上二叉树任意节点的访问均是访问的某一棵树的根节点),那么只有中序遍历生成的中序线索二叉树是先访问左子树,根节点,右子树,而先序线索二叉树,是先访问根节点,所以只能从先序线索二叉树中得到节点的后继结点,同理只能从后序线索二叉树得到节点的前驱结点(最后访问根节点)。

package ccnu.offer.tree;

public class Demo03 {
static ThreadNode pre = null;

public static void main(String[] args) {
ThreadNode root = createBiTreeByPreIn(new int[]{1, 2, 4, 3, 5}, new int[]{2, 4, 1, 5, 3}, 0, 0, 5);
ThreadNode inRoot = createInThreadBiTree(root);
inOrder(inRoot);
System.out.println();
inOrderByReverse(inRoot);
}

public static ThreadNode createBiTreeByPreIn(int[] pre, int[] in, int preBegin, int inBegin, int len){
if(pre == null || in == null || pre.length != in.length || pre.length == 0 || in.length == 0){
return null;
}
if(len <= 0){
return null;
}
ThreadNode root = new ThreadNode(pre[preBegin]);
int rootIndex;
for(rootIndex = 0; in[rootIndex] != pre[preBegin]; rootIndex++);
root.lchild = createBiTreeByPreIn(pre, in, preBegin + 1, inBegin, rootIndex - inBegin);
root.rchild = createBiTreeByPreIn(pre, in, preBegin + (rootIndex - inBegin) + 1, rootIndex + 1, len - (rootIndex - inBegin) - 1);
return root;
}

public static ThreadNode createInThreadBiTree(ThreadNode root){
//      ThreadNode pre = null;
if(root != null){
inThreadBiTree(root);
pre.rtag = 1; // pre指向中序遍历的最后一个节点
pre.rchild = null; // 没有后继节点
}
return root;
}

public static void inThreadBiTree(ThreadNode root){
if(root != null){
inThreadBiTree(root.lchild); // 第一步:线索化当前root的左子树
// 第二步:访问当前root节点,如果当前root节点的左孩子为空,那么root的lchild就应该指向其中序序列前驱结点,同时如果root的前一个访问节点(中序序列)pre的rchild为空,那么pre的rchild就应该指向当前root
if(root.lchild == null){
root.ltag = 1; // root的lchild指向root的中序遍历前驱结点
root.lchild = pre; // 当前节点的中序遍历前驱结点为中序遍历中的上一个访问的节点
}
if(pre != null && pre.rchild == null){ // pre != null 因为第一个访问节点没有前驱
pre.rtag = 1; // 中序遍历上一个访问的节点pre指向其中序遍历的后继节点,即当前节点root
pre.rchild = root;
}
pre = root; // 将刚才访问的节点保存,注意访问最后一个节点时,pre会指向它
inThreadBiTree(root.rchild); // 第三步:线索化当前root的右子树
}
}

public static void inOrder(ThreadNode root){ // 中序线索二叉树中序遍历
if(root == null){
return;
}
ThreadNode firstNode = firstNode(root);
ThreadNode p = firstNode;
while(p != null){
System.out.print(p.data + " ");
p = nextNode(p);
}
}

public static void inOrderByReverse(ThreadNode root){
if(root == null){
return;
}
ThreadNode lastNode = lastNode(root);
ThreadNode p = lastNode;
while(p != null){
System.out.print(p.data + " ");
p = previousNode(p);
}
}

public static ThreadNode firstNode(ThreadNode root){ // 得到中序遍历序列(以root作为根节点的树)的第一个节点--->没有左孩子的root子树就是中序序列的第一个节点
if(root == null){
return null;
}
while(root.ltag == 0){ // 存在左孩子
root = root.lchild;
}
return root;
}

public static ThreadNode lastNode(ThreadNode root){ // 得到中序遍历序列(以root作为根节点的树)的最后一个节点--->没有右孩子的root子树就是中序序列的最后一个节点
if(root == null){
return null;
}
while(root.rtag == 0){ // root.rtag == 0不等价于root.rchild != null(不一定存在右孩子),因为rchild可能指向其后继节点
root = root.rchild;
}
return root; //
}

public static ThreadNode previousNode(ThreadNode p){
if(p == null){
return null;
}
if(p.ltag == 0){ // p存在左孩子
return lastNode(p.lchild);
}else{ // 没有左孩子
return p.lchild; // lchild直接指向其前驱结点
}
}

public static ThreadNode nextNode(ThreadNode p){ // 得到p节点的中序遍历序列的后继节点
if(p == null){
return null;
}
if(p.rtag == 0){ // 存在右孩子,那么找到p的后继节点等价于找到p.rchild的中序遍历的第一个节点
return firstNode(p.rchild);
}else{ // 木有右孩子,那么p节点的rchild直接就指向其后继节点
return p.rchild;
}
}

private static class ThreadNode{
private int data;
private int ltag = 0; // 默认lchild指向左孩子
private int rtag = 0; // 默认rchild指向右孩子
private ThreadNode lchild = null;
private ThreadNode rchild = null;

public ThreadNode(int data){
this.data = data;
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息