头文件:head.h
#ifndef _HEAD_1_H_
#define _HEAD_1_H_
#include<string.h>
#include<ctype.h>
#include<malloc.h> /* malloc()等 */
#include<limits.h> /* INT_MAX等 */
#include<stdio.h> /* EOF(=^Z或F6),NULL */
#include<stdlib.h> /* atoi() */
#include<io.h> /* eof() */
#include<math.h> /* floor(),ceil(),abs() */
#include<process.h> /* exit() */
/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
/* #define OVERFLOW -2 因为在math.h中已定义OVERFLOW的值为3,故去掉此行 */
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
typedef int Boolean; /* Boolean是布尔类型,其值是TRUE或FALSE */
#define CHAR //定义字符型
//#define INT //定义整型(二选一)
#ifdef CHAR
typedef char TElemType;
//TElemType Nil = ' '; //字符型以空格为空
#define form "%c" //输出输出的格式为%c
#endif
#ifdef INT
typedef int Elemtype;
//TElemType Nil = 0; //整型以0为空
#define form "%d" //输入输出格式为%d
#endif
typedef enum PointerTag{Link, Thread}PointerTag; //Link==0代表指针;Thread==1代表线索
typedef struct BiThrNode{
TElemType data;
struct BiThrNode *lchild, *rchild; //左右孩子指针
PointerTag LTag, RTag; //左右标志
}BiThrNode, *BiThrTree;
Status InitBiThrTree(BiThrTree *T);
Status CreateBiThrTree(BiThrTree *T);
void InThreading(BiThrTree p);
Status InOrderThreading(BiThrTree *Thrt, BiThrTree T);
Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType));
#endif
算法实现:
#include"head.h"
#ifdef CHAR
TElemType Nil = ' ';
#else
TElemType Nil = 0;
#endif
Status InitBiThrTree(BiThrTree *T)
{
*T = NULL;
return OK;
}
Status CreateBiThrTree(BiThrTree *T)
{
//按照先序输入二叉树线索中结点的值,构造二叉线索数T
//0(整型)/空格(字符型)表示空节点
TElemType h;
#ifdef CHAR
scanf_s("%c", &h);
#else
scanf_s("%d", &h);
#endif
if (h == Nil)
*T = NULL;
else
{
*T = (BiThrTree)malloc(sizeof(BiThrNode));
if (!(*T))
{
printf("建立二叉树失败!");
system("pause");
exit(-1);
}
(*T)->data = h;
CreateBiThrTree(&(*T)->lchild); //构造左子树
if ((*T)->lchild) //左子树存在
(*T)->LTag = Link;
CreateBiThrTree(&(*T)->rchild);
if ((*T)->rchild) //右孩子存在
(*T)->RTag = Link;
}
return OK;
}
BiThrTree pre; //全局变量,始终指向刚刚访问过的结点
/*
由于线索化的实质是将二叉链表中的空指针改为指向前驱或后继的线索,而前驱或后继的信息只有在遍历事才
看得到,因此线索化的过程即为在遍历的过程中修改空指针的过程。为了几下遍历过程中访问节点的先后关系,
附设一个指针pre始终指向刚刚访问过的结点,若指针p指向当前访问的结点,则pre指向它的前驱。
*/
void InThreading(BiThrTree p)
{
//中序遍历进行中序线索化
if (p)
{
InThreading(p->lchild); //递归左子树线索化
if (!p->lchild) //没有左孩子
{
p->LTag = Thread; //前驱线索
p->lchild = pre; //左孩子指针指向前驱,pre代表刚刚访问过的结点,即前驱
}
if (!p->rchild) //没有右孩子
{
pre->RTag = Thread; //后继线索
pre->rchild = p; //前驱右孩子指针指向后继(当前结点p)
}
pre = p; //保持pre指向p的前驱
InThreading(p->rchild); //递归右子树线索化
}
}
Status InOrderThreading(BiThrTree *Thrt, BiThrTree T)
{
//中序遍历二叉树T,并将其中序线索化,Thrt是头指针,其指向头结点
*Thrt = (BiThrTree)malloc(sizeof(BiThrNode));
if (!(*Thrt))
{
printf("中序遍历线索化失败!");
system("pause");
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;
}
Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType))
{
//T指向头结点,头结点的左链lchild指向根节点,
//中序遍历二叉树线索树T的非递归算法,对每个数据元素调用函数visit
BiThrTree p;
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;
}
测试文件:
#include"head.h"
Status vi(TElemType c)
{
#ifdef CHAR
printf("%c ", c);
#else
printf("%d ", c);
#endif
return OK;
}
void main()
{
BiThrTree H, T;
#ifdef CHAR
printf("请按先序输入二叉树(如:ab三个空格表示a为根结点,b为左子树的二叉树)\n");
#else
printf("请按先序输入二叉树(如:1 2 0 0 0表示1为根结点,2为左子树的二叉树)\n");
#endif
CreateBiThrTree(&T); /* 按先序产生二叉树 */
InOrderThreading(&H, T); /* 中序遍历,并中序线索化二叉树 */
printf("中序遍历(输出)二叉线索树:\n");
InOrderTraverse_Thr(H, vi); /* 中序遍历(输出)二叉线索树 */
printf("\n");
system("pause");
}
运行结果:
请按先序输入二叉树(如:ab三个空格表示a为根结点,b为左子树的二叉树)
abdg e c f
中序遍历(输出)二叉线索树:
g d b e a c f
请按任意键继续. . .