数据结构之线索二叉树

  线索二叉树的由来:正如因单链表某些功能不足而发明了双链表来弥补,既可往前驱又可往后继遍历。二叉树也是条条路往下走,而且二叉树有很多结点(非双分支结点)有空指针,浪费空间,利用这些空间来构造线索找到前驱和后继。

  那么接下来讨论那种遍历方式能够利用好这些空指针来构造线索二叉树,给出一棵二叉树:

      

  前序遍历:ABDHIECFG        中序遍历:HDIBEAFCG       后序遍历:HIDEBFGCA        层次遍历 :ABCDEFGHI

  加粗的字母为有空指针的结点,只有中序遍历才是能够利用空指针表示所有结点,很好表示前驱和后继。

  如果某一结点的左孩子为空,则让其左孩子指针指向遍历前驱,如果其右孩子为空,则让其右孩子指针指向遍历后继。

  线索二叉树需要加一个标志位来表示指针是指向左右孩子还是前驱后继。

                          

  1.线索二叉树的定义及二叉树建立

#define _CRT_SECURE_NO_DEPRECATE
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
#define BinType BinTree
const int MAXSIZE = 100;//栈和队列的最大容量
typedef char DataType;
typedef enum{Link,Thread}PointerTag;//枚举类型 
//线索存储标志位,Link(0)表示指向左右孩子,Thread(1)表示前驱后继
typedef struct BTNode{
	DataType data;
	struct BTNode *lchild, *rchild;
	PointerTag ltag;//左标志位
	PointerTag rtag;//右标志位
}BiThrNode, *BiThrTree;
//创建一棵二叉树,前序遍历,所有NULL指针用空格代替
void CreateBiThrTree(BiThrTree &T)
{
	char c;
	scanf("%c", &c);
	if (' ' == c)
	{
		T = NULL;
	}
	else
	{
		T = (BiThrNode *)malloc(sizeof(BiThrNode));
		T->data = c;
		T->ltag = Link;
		T->rtag = Link;
		CreateBiThrTree(T->lchild);
		CreateBiThrTree(T->rchild);
	}
}
/*   A
  B     E
C  D      F
*/
//例如这棵树输入ABC空空D空空E空F空空

  2.二叉树线索化

  二叉树线索化在遵循线索二叉树的定义前提下,还增加了一个线索二叉树头结点,作为线索二叉树的开始也具有判断是否遍历完及构成循环的作用。

     

  图中红色线和棕色线分别为前驱线索和后继线索,由于头结点的引入,整棵中序线索二叉树构成循环,具有双向的特点。

  中序线索化代码

BiThrTree Pre;//全局变量始终指向刚刚访问的节点
void InThread(BiThrTree &T)//递归中序线索化
{
	if (T)//非空
	{
		InThread(T->lchild);//线索化左孩子
		//处理节点
		if (!T->lchild)//若左孩子空,设置指向前一个访问结点pre的前驱线索
		{
			T->ltag = Thread;
			T->lchild = Pre;//需要设置一个指向刚刚访问的节点
		}
		if (!Pre->rchild)//若前一个结点的右孩子空,设置一个指向本结点T的后继线索
		{
			Pre->rtag = Thread;
			Pre->rchild = T;
		}
		Pre = T;//记录刚刚访问的结点
		InThread(T->rchild);//线索化右孩子
	}
}
void InOrderThreading(BiThrTree &p,BiThrTree &T)//中序线索化函数
{
	p = (BiThrTree)malloc(sizeof(BiThrNode));//创建线索二叉树头结点
	p->ltag = Link;
	p->rtag = Thread;
	p->rchild = p;
	if (!T)//如果空树
		p->lchild = p;
	else//非空树
	{
		p->lchild = T;
		Pre = p;//设置参量,初始化为线索头结点
		InThread(T);
		Pre->rtag = Thread;
		Pre->rchild = p;//最后一个结点的后继为线索头结点
		p->rchild = Pre;//头结点右孩子指向遍历的最后一个结点,形成循环
	}
}

  3.中序线索二叉树遍历

void visit(char c)//访问函数
{
	printf("%c", c);
}
void InorderThr(BiThrTree head)//中序遍历线索二叉树
{
	BiThrTree p=head->lchild;
	while (p != head)//空树或者完成,完成条件是又回到了head
	{
		while (p->ltag == Link)
			p = p->lchild;
		visit(p->data);
		while (p->rtag == Thread&&p->rchild != head)//是线索的话一直找后继线索
		{
			p = p->rchild;
			visit(p->data);
		}
		p = p->rchild;
	}
}

  4.测试代码

int main()//测试代码
{
	BiThrTree mytree,head;
	CreateBiThrTree(mytree);//输入ABC空空D空空E空F空空  中序CBDAEF    CBDF可以利用线索
	InOrderThreading(head,mytree );
	printf("中序遍历结果:\n");
	InorderThr(head);
	printf("\n");
	system("pause");
	return 0;
}
/*   A
  B     E
C  D      F
*/

  

 

posted @ 2016-01-27 15:12  王毅2016  阅读(419)  评论(0编辑  收藏  举报