数据结构学习之线索二叉树(java/c++版)

#include <iostream>
#include <windows.h>
using namespace std;
#pragma warning(disable:4996)

//可不可以利用c++的泛化编程的思想去改边它
typedef int Tree_type; //树中的存储结构的类型(先去掉---用泛化的思想)
//注意枚举和结构体一样的命名和定以方式
typedef enum PoitnterTag
{
    link,
    Thread
} PointerTag;
//注意----当二叉树遇到中序遍历时就自动排好序了
//template<class Tree_type>
typedef struct Tree
{
    Tree_type data;  //要存储的结构
    Tree *Left;     //左孩子
    Tree *Right;    //右孩子
    PointerTag LTag; //左标志位
    PointerTag RTag; //右标志位
} Tree, *PTree;

//template <class Tree_type>
//标志位的定义应该在树形成之后去定义---根据是否有左右结点指针去为其赋值
PTree pre = NULL; //在此定义一个全局变量去保留上一个的结点
bool Threading(PTree &T)
{
    if (T) //还是利用中序遍历去查看是否需要用到标志位
    {
        Threading(T->Left);
        if (!T->Left) //是否T没有左孩子
        {
            T->Left = pre;    //如果它没有左孩子则让它的左指针指向它的上一个结点
            T->LTag = Thread; //并把它的左标志位赋值为1
        }
        if (!pre->Right)
        {
            pre->Right = T;    //如果上一个结点没有右孩子则让它的右指针指向它的下一个结点即T
            pre->RTag = Thread; //并且把它的右标志位赋值为1
        }
        pre = T; //改变上一个结点的值
        Threading(T->Right);
    }
    //写到这里可能会有个疑问--pre一开始还只是个空将T->Left指向空--不是错了吗?
    //因此在这之前我们还需要对pre进行赋值。。。。。。。。。。。。。。
    //而在这里应该把这个pre定义为谁呢?仔细一想就会发现这个pre必须指向一个其他的不属于原来这个树的结点否则就会对其他的结点的线索化造成影响
    return true;
}

//因此在这里必须重新定义一个结点

bool Init_pre(PTree &P, PTree &T)
{
    if (T) //T必须存在才行
    {
        P = new Tree;
        P->Left = T;    //让它指向头结点
        P->LTag = link;  //link表示这个指针有指向
        P->RTag = link;  //有指向的标志位
        P->Right = NULL; //并且将它的值赋值位空
        //在这里pre的初始化就完成了--是不是很简单
        //之后就可以直接调用Threading了
        pre = P;
        Threading(T);
        //在这里有一点要注意当pre的值不断的改变并且到达最后一个结点时要手动对它进行线索化
        pre->Right = P;
        pre->RTag = Thread;
        P->Right = pre; //构成一个相互的指向
    }
    return true;
}

template<class Tree_type>
bool Insert_Tree(PTree &T, Tree_type &elem)
{
    if (T == NULL) //如果树为空就要重新构造
    {
        PTree temp = new Tree;
        temp->data = elem;
        temp->LTag = link; //在这里先假设他们都有结点连接--如果没有到时候在改变它的值
        temp->RTag = link; //初始化=====
        temp->Left = NULL;
        temp->Right = NULL;
        T = temp;
    }
    else if (elem < T->data)
    {
        Insert_Tree(T->Left, elem); //如果elem要小于某个节点的值则让它插入到该节点的左边
    }
    else if (elem > T->data)
    {
        Insert_Tree(T->Right, elem); //如果elem要大于某个节点的值则让它插入到该节点的右边
    }
    //如此的重复的进行知道T为空
    return true;
}

//树的遍历---递归的形式
/* bool Traverse_Tree(PTree& T)
{
    if(T)//如果T不指向空则则继续递归
    {
        Traverse_Tree(T->Left);
        cout << T->data << " ";
        Traverse_Tree(T->Right);//在这里有个巧妙的地方--当从这个点向右遍历时右为空因此又会回到上一个结点
    }
    return true;
} */

//树的遍历---非递归实现中序遍历

bool Traverse_Tree(PTree &T)
{
    PTree temp = T->Left; //T为Root
    while(temp!=T){
        while (temp->LTag == link) //与当初的一直往下走一样,一直走到它的最左边,不同的时此时的我们已经可以回到上一个结点了
        {
            temp = temp->Left;
        }
        cout << temp->data << " "; //循环出来后temp就是最左边的一个结点了--此时应该往上走了
        //temp->RTag的意思是只有当其不能在继续往下走时要利用它的标志位的特点
        while (temp->RTag == Thread && temp->Right != T)//可能在这一部有所疑问--temp->Right!=T的意思是当结点为最后的一个结点时我们不能再继续往下执行了
        {
            temp = temp->Right;
            cout << temp->data << " ";
        }
        //当循环不满足条件的时候会跳出循环,为了让程序继续走完---应该手动的使它跳到下一个结点上去
        temp = temp->Right;   
        //此时T在最左边的结点上//发现好像剩下的左右结点指针都没什么用且到达最右端时无发再回到上一个结点了
        //那么可不可以用那两个没用的结点指针使他们指向上一个结点--变废为宝呢?--线索二叉树的来源
    }
    cout << endl;
    return true;
}

int main()
{
    PTree space = NULL;
    PTree Root = NULL;
    Tree_type data;
    do
    {
        cout << "请输入要进入树的数据:";
        cin >> data;
        if (data == 0)
            break;
        Insert_Tree(space, data);
    } while (1);
    Init_pre(Root, space);
    Traverse_Tree(Root);
    system("pause");
    return 0;
}



java下面展示的是java版本的可供java学习者参考
思想是一样的因此不写注释了 package com.acm; import java.util.Scanner;
class Solution { private class node { private int val; private node left; private node right; private int Ltag; private int Rtag; public node(int val) { this.val=val; Ltag=Rtag=0; } public boolean addNode(int data) { if(data>this.val) { if(this.right==null) this.right=new node(data); else { this.right.addNode(data); } } else if(data<this.val) { if(this.left==null) this.left=new node(data); else { this.left.addNode(data); } } return true; } public boolean showNode() { if(this.left!=null) this.left.showNode(); System.out.print(this.val); if(this.right!=null) this.right.showNode(); return true; } public boolean ThreadTravel() { if(this.left!=null) this.left.ThreadTravel(); if(this.left==null) { this.left=pre; this.Ltag=1; } if(pre.right==null) { pre.right=this; pre.Rtag=1; } pre=this; if(this.right!=null) this.right.ThreadTravel(); return true; } } private node root; private node pre; private node head; public boolean add(int data) { if(root==null) { root=new node(data); root.left=null; root.right=null; } else { root.addNode(data); } return true; } public boolean show() { if(root!=null) { root.showNode(); } return true; } public boolean showThreading() { if(root!=null) root.ThreadTravel(); return true; } public boolean Threading() { if(root!=null) { head=new node(0); head.left=root; pre=head; root.ThreadTravel(); pre.right=head; head.right=pre; pre.Rtag=1; } return true; } public boolean TravelNode() { if(root==null)return true; node temp=root; while(temp!=head) { while(temp.Ltag==0)temp=temp.left; System.out.print(temp.val); while(temp.Rtag==1&&temp.right!=head) { temp=temp.right; System.out.print(temp.val); } temp=temp.right; } return true; } } public class Main { public static void main(String[] args) { Solution space=new Solution(); int val=0; Scanner iner=new Scanner(System.in); do { System.out.println("请输入要进入树的节点:"); val=iner.nextInt(); }while(val!=666&&space.add(val)); System.out.println("输入结束!"); space.Threading(); //space.show(); //此时会进入死循环 space.TravelNode(); iner.close(); } }

猜你喜欢

转载自www.cnblogs.com/z2529827226/p/11802574.html