#include<iostream>
#include<iomanip> //iomanip格式控制库
using namespace std;
typedef char eleData; //eleData定义数据类型
//作者:一贰柒一肆
//内容:树的构建、中序非递归遍历、中序线索树、中序线索遍历
//与书本略有不同,可以用作参考
/* 树的结构
a
/ \
b e
/ \ / \
c d f g
*/
static string data="abc##d##ef##g##"; //data存储数据
static int index=0; //index用来检索数据
typedef enum flog{link,node}childFlog; //childFlog结点孩子标记,link代表线索,node代表结点
typedef struct node{
eleData treeData; //treeData树存储的数据类型
node* leftChild; //leftChild树的左孩子
node* rightChild; //rightChild树的右孩子
childFlog left; //left左孩子标记
childFlog right; //right有孩子标记
}*treePre,treeNode; //treePre树的指针-------treeNode树的结点
void creatBiTree(treePre &T) //creatBiTree创建二叉树C/C++存在指针变量、传递结构体与对象时要采用引用
{
if(index==data.length()) //data内的数据检索完成,不再执行后续步骤
{
return;
}
if(data[index]=='#') //遇到#表示没有数据是空结点index++继续读下一位
{
index++;
return;
}
T=(treePre)malloc(sizeof(treeNode)); //创建结点空间
T->left=T->right=node; //初始化左右孩子标记域为结点
T->leftChild=T->rightChild=NULL; //初始化左右孩子指针域为NULL
T->treeData=data[index++]; //初始化当前结点数据域为data[index],之后index++读后续数据
creatBiTree(T->leftChild); //创建左孩子
creatBiTree(T->rightChild); //创建右孩子
}
void coutTreeMid(treePre T) //普通树中序非递归遍历
{
treePre sk[data.length()]; //设置栈,栈容量是数据长度
int top=-1; //仅使用栈顶,初值设为-1表示栈空
while(T||top!=-1) //T代表访问的结点,top表示栈是否为空
{
if(T) //如果结点存在
{
sk[++top]=T; //结点入栈
T=T->leftChild; //结点向左孩子下移
}
else //否则就是结点不存在的时候,该不存在结点为栈顶的左孩子
{
cout<<setw(2)<<left<<sk[top]->treeData; //先输出栈顶的数据,栈顶是该不存在结点的父结点--->对该父结点中序遍历:左子树为空、就要先输出数据、再检查右子树
T=sk[top--]->rightChild; //top--先检查右子树,再把该父结点退栈
}
}
}
void creatLinkBiTree(treePre &T,treePre &pre) //创造中序线索二叉树
{
if(!T) return; //如果结点不存在,直接回复、不进行后续操作
creatLinkBiTree(T->leftChild,pre); //先线索化左子树
if(!T->leftChild) //如果该结点左孩子不存在
{
T->left=link; //把左孩子标志域设置为线索link
T->leftChild=pre; //左孩子指针域指向前驱pre
}
if(!pre->rightChild) //前驱结点若无右孩子
{
pre->right=link; //把右孩子标志域设置为线索link
pre->rightChild=T; //右孩子指针域指向后继T
}
pre=T; //当前结点已经线索化,前驱要改变,变为当前结点
creatLinkBiTree(T->rightChild,pre); //开始线索化右孩子
}
static void lookForNext(treePre &T,treePre treeHead) //寻找下一个结点,多次使用设为静态
{
if(T->right==link) //如果当前结点的右标记域是线索
{
T=T->rightChild; //则直接记录当前节点的右孩子即可
}
else //如果当前结点的右标记是结点
{
T=T->rightChild; //则要在右子树寻找后继
while(T!=treeHead&&T->left==node) //当T记录的不是头结点而且左孩子是结点时
{
T=T->leftChild; //T就要向左孩子方向下移动
} //结束时T的左孩子不是结点而是指向了前驱,T就是前驱的后继
}
}
void coutLinkTree(treePre treeHead) //线索树的遍历
{
treePre T=treeHead->rightChild; //T储存中序遍历第一个元素的位置
while(T!=treeHead) //当T不指向头结点时就继续循环,因为中序遍历最后一个元素的后继是头结点
{
cout<<setw(2)<<left<<T->treeData; //输出当前数据
lookForNext(T,treeHead); //找到下一个数据用T记录
}
}
treePre coutMidFirst(treePre T) //找到中序遍历的第一个数据
{
while(T->leftChild) //第一个左孩子为空的结点就是中序遍历的第一个结点
{
T=T->leftChild; //指针沿左孩子方向向下移动
}
return T; //循环结束时就是第一个左孩子为空的结点,将该结点回复,因为该结点就是中序遍历的第一个结点
}
int main()
{
treePre tree; //树根
cout<<"\t***创造二叉树***"<<endl;
creatBiTree(tree); //调用函数创造二叉树
cout<<"\t***创造树成功***"<<endl;
cout<<"中序非递归遍历:";
coutTreeMid(tree); //调用函数遍历普通二叉树
cout<<endl<<"\t***将树线索化***"<<endl;
treePre treeHead=(treePre)malloc(sizeof(treeNode)); //为线索树添加头结点
treeHead->left=node; //初始化左孩子标记域为结点
treeHead->right=link; //初始化右孩子标记域为线索
treeHead->leftChild=tree; //初始化左孩子指针域记录根结点
treeHead->rightChild=coutMidFirst(tree); //初始化右线索指向中序遍历的第一个结点
treePre pre=treeHead; //设置前驱,初始指向头节点
creatLinkBiTree(tree,pre); //调用函数创建线索二叉树
pre->rightChild=treeHead; //最后一个结点的后继指向头结点
cout<<"\t***线索化成功***"<<endl;
cout<<"线索化遍历:";
coutLinkTree(treeHead); //调用函数进行线索化遍历
return 0;
}
直接上代码,大家看看不懂可以留言--有空就回复