//2013.7.4
//对线索二叉树有了更深入的理解。过去学习数据结构更注重代码实现。
//现在则更注重对算法思想的理解。因为只要有了思路,代码实现都没有问题(只要有一定程序调试能力)。
//至于线索二叉树以前只注意到线索二字。然而线索终究是给出一定指示即可,是不需要从头指向尾的。
//从头指向尾也没问题,但,二叉树只有左右两个指针。一个根节点如果有两个子节点的话。
//便没有多余的结点来供它来做线索来指向了!
//所以线索也只是对遍历的一种配合,中序线索二叉树,先让其走向最左端,然后按线索走向中间。
//然后再走向右端。
//-------------------二叉树的二叉树线索存储表示----------
typedef enum PointerTag { Link, Thread }; //Link == 0; 指针,Thread == 1;线索
typedef struct BiThrNode {
TElemType data;
struct BiThrNode *lchild, *rchild; //左右孩子指针
PointerTag LTag, RTag; //左右标志
}BiThrNode, *BiThrTree;
Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType e)){
//T指向头结点,头结点的左链lchild指向根结点。
//中序遍历二叉树线索树T的非递归算法,对每个数据元素调用函数Visit
p = T -> lchild; //p指向根节点
while (p != T){ //空树或遍历结束时,p == T
while (p -> LTag == Link) p = p -> lchild;
if (!Visit(p -> data)) return ERROR; //访问其右子树为空的结点
while (p -> RTag == Thread && p -> rchild != T) {
p = p -> rchild; Visit(p -> data); //访问后继结点
}
p = p -> rchild;
}
return OK;
}
Status InOrderThreading (BinThrTree &Thrt, BiThrTree T) {
//中序遍历二叉树T,并将其中序线索化,Thrt指向头结点
if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))exit(OVERFLOW);
Thrt -> LTag = Link; Thrt -> Rtag = Thread; //建立头结点
Thrt -> rchild = Thrt; //右指针回指
if(!T) Thrt -> lchild = Thrt; //若二叉树空,则左指针回指
else{
Thrt -> lchild = T; pre = Thrt;
InThreading(T); //中序遍历进行中序线索化
pre -> rchild = Thrt; pre -> RTag = Thread; //最后一个结点线索化
Thrt -> rchild = pre;
}
return OK;
}
void InThreading(BinThree b) {
if(p) {
InThreading(p -> lchild); //左子树线索化
if(!p -> lchild) {p -> LTag = Thread; p -> lchild = pre; }//前驱线索
if(!p -> rchild) {pre -> RTag = Thread; pre -> rchild = p;} //后继线索化
pre =p; //保持pre指向p的前驱
InThreading(p -> rchild); //右子树线索化
}
}
//2013.2.23
#include <stdio.h>
#include<malloc.h>
#define LEN sizeof(struct ThreadBinTree)
#define NULL 0
enum NodeFlag
{
SubTree,
Thread
}; //枚举值SubTree和Thread分别为0,1
struct ThreadBinTree
{
int data; //元素数据
NodeFlag lflag; //左标志
NodeFlag rflag; //右标志
struct ThreadBinTree *left; //左子树结点指针
struct ThreadBinTree *right; //右子树结点指针
};
ThreadBinTree *Previous;
void BinTreeThreading_LDR(ThreadBinTree *bt) //二叉树按中序线索化
{
if(bt)
{
BinTreeThreading_LDR(bt->left); //递归调用,将左子树线索化
bt->lflag=(bt->left)?SubTree:Thread; //设置左指针域的标志
bt->rflag=(bt->right)?SubTree:Thread; //设置右指针域的标志
if(Previous) //若当前结点的前驱Previous存在
{
if(Previous->rflag==Thread) //若当前结点的前驱右标志为线索
Previous->right=bt; //设Previous的右线索指向后继
if(bt->lflag==Thread) //若当前结点的左标志为线索
bt->left=Previous; //设当前结点的左线索指向中序前驱
}
Previous=bt; //让Previous保存刚访问的结点
BinTreeThreading_LDR(bt->right); //递归调用将右子树线索化
}
}
ThreadBinTree *BinTreeNext_LDR(ThreadBinTree *bt) //求指定结点的后继
{
ThreadBinTree *nextnode;
if(!bt)
return NULL;
if(bt->rflag==Thread) //若当前结点的右子树为空
return bt->right; //返回右线索所指的中序后继
else
{
nextnode=bt->right; //从当前1结点的右子树开始查找
while(nextnode->lflag==SubTree) //循环处理所有左子树不为空的结点
nextnode=nextnode->left;
return nextnode; //返回左下方的结点
}
}
ThreadBinTree *BinTreePrevious_LDR(ThreadBinTree *bt) //求指定结点的前驱
{
ThreadBinTree *prenode;
if(!bt)
return NULL;
if(bt->lflag==Thread) //若当前解结点的左子树为空
return bt->left; //返回左线索所指的中序后继
else
{
prenode=bt->left; //从当前结点的左子树开始查找
while(prenode->rflag==SubTree) //循环处理所有右子树不为空的结点
prenode=prenode->left;
return prenode; //返回左下方结点
}
}
void ThreadBinTree_LDR(ThreadBinTree *bt)
{
if(bt)
{
while(bt->lflag==SubTree) //有左子树
bt=bt->left; //从根往下找最左下结点
do
{
printf("%d",bt->data); //处理结点
bt=BinTreeNext_LDR(bt); //找中序后继结点
}while(bt);
}
}
/*函数功能初始化一个二叉树,建立根节点。*/
ThreadBinTree *InitRoot()
{
ThreadBinTree *node;
node=(struct ThreadBinTree*)malloc(LEN);
printf("请输入根节点的值:");
scanf("%d",&node->data);
node->left=NULL;
node->right=NULL;
return node;
}
/*函数功能:进行查找操作。*/
ThreadBinTree *BinTreeFind(ThreadBinTree *bt,int data) //在二叉树中查找值为data的结点。
{
ThreadBinTree *p;
if(bt==NULL)
return NULL;
else
{
if(bt->data==data)
return bt;
else{
if(p=BinTreeFind(bt->left,data))
return p;
else if(p=BinTreeFind(bt->right,data))
return p;
else
return NULL;
}
}
}
/*添加数据到二叉树*/
int BinTreeAddNode(ThreadBinTree *bt,ThreadBinTree *node,int n)
{
if(bt==NULL)
{
printf("\n父结点不在,请先设置父结点。");
return 0;
}
switch(n)
{
case 1:
if(bt->left)
{
printf("左子树结点不为空。");
return 0;
}
else
bt->left=node;
break;
case 2:
if(bt->right)
{
printf("右子树结点不为空。");
return 0;
}
else
bt->right=node;
break;
default:
printf("参数错误!\n");
return 0;
}
return 1;
}
/*函数功能:添加结点到二叉树。*/
void AddNode(ThreadBinTree *bt)
{
int data;
int select;
ThreadBinTree *node,*parent;
node=(struct ThreadBinTree*)malloc(LEN);
printf("\n输入二叉树结点数据");
scanf("%d",&node->data);
node->left=NULL;
node->right=NULL;
printf("\n输入父结点数据:");
scanf("%d",&data);
parent=BinTreeFind(bt,data);
if(!parent)
{
printf("\n未找到父结点。");
}
printf("\n1.添加到左子树\n2.添加到右子树\n");
do{
scanf("%d",&select);
if(select==1||select==2)
BinTreeAddNode(parent,node,select);
}while(select!=1&&select!=2);
}
int main()
{
ThreadBinTree *root=NULL;
int select;
do
{
printf("\n1.设置二叉树根元素\n2.添加二叉树根节点\n3.生成中序线索二叉树\n4.遍历线索二叉树\n0.退出");
scanf("%d",&select);
switch(select)
{
case 1:
root=InitRoot();
break;
case 2:
AddNode(root);
break;
case 3:
BinTreeThreading_LDR(root);
printf("生成线索二叉树完毕");
break;
case 4:
printf("\n中序线索二叉树遍历的结果");
ThreadBinTree_LDR(root);
break;
case 0:
break;
}
}while(select!=0);
return 0;
}