线索二叉树
- 在遍历二叉树时都没有把遍历时得到的结点的后继结点信息和前驱结点信息保存下来,因此,不能像操作双向链表那样操作二叉树。当按某种规则遍历二叉树时,保存遍历时得到的结点的后继结点信息和前驱结点信息的最常用的方法是建立线索二叉树。
1.线索二叉树的概念和存储结构
- 对二叉链存储结构的二叉树分析可知,在有n个结点的二叉树中必定存在n+1个空链域。我们希望能利用这些空链,建立起相应结点的前驱结点信息和后继结点信息。我们做如下规定:当某结点的左指针为空时,令该指针指向按某种方法遍历二叉树时得到的该结点的前驱结点;当某结点的右指针为空时,令该指针指向按某种方法遍历二叉树时得到的该结点的后继结点。但是,仅仅这样做,会使我们不能区分:左指针指向的结点到底是左孩子结点还是前驱结点,右指针指向的结点到底是右孩子结点还是后继结点。因此,需要在结点中再增加两个线索标志位来区分这两种情况。线索标志位定义如下:
每个结点的存储结构
三种线索方式
头文件
/*
中序线索二叉树节点
*/
typedef struct Node{
DataType data;
int leftThread; //左线索
struct Node*leftChild; //左指针
struct Node*rightChild; //右指针
int rightThread; //右线索
}ThreadBiNode;
/*
*/
void InThread(ThreadBiNode *current, ThreadBiNode **pre){
if(current!=NULL){
InThread(current->leftChild,pre); //中序线索化左子树
if(current->leftChild==NULL){
current->leftThread=1;//建立做索引标记
current->leftChild = *pre;//建立做索引指针
}else{
current->leftThread=0;
}
if(current->rightChild!=NULL){
current->rightThread=0;
}else{
current->rightThread=1;
}
if((*pre)->rightChild==NULL){
(*pre)->rightThread=1;//建立右索引标记
(*pre)->rightChild=current;//建立右索引指针
}else{
current->rightThread=0;
}
*pre=current;
InThread(current->rightChild,pre);
}
}
/*
创建中序线索化二叉树
*/
void CreatInThread(ThreadBiNode **root){
ThreadBiNode *t=*root; //保存原来二叉树的根节点
ThreadBiNode *current,*pre=*root;
*root = (ThreadBiNode*)malloc(sizeof(ThreadBiNode));
if(t==NULL){
(*root)->leftThread = 0;
(*root)->rightThread = 1;
(*root)->leftChild = *root;
(*root)->rightChild = *root;
}else{
current = t;
(*root)->rightThread=0;
(*root)->leftChild=t;
InThread(current,&pre);
pre->rightChild=*root;
pre->rightThread = 1;
(*root)->rightThread=1;
(*root)->rightChild=pre;
}
}
/*
中序线索二叉树循环操作
*/
typedef struct{
ThreadBiNode *root;
ThreadBiNode *current;
int nextComplete; //遍历结束标记
}ThreadBiTree;
/*初始化中序线索二叉树函数*/
void ThreadInitiate(ThreadBiTree *tree, ThreadBiNode *root){
tree->root = root;
tree->current=root;
if(root == NULL){
tree->nextComplete = 1;
}else{
tree->nextComplete = 0;
}
}
/*
是中序线索二叉树tree的当前结点指针指向中序遍历的第一个节点
*/
void First(ThreadBiTree *tree){
tree->current=tree->root;
while(tree->current->leftThread==0){
tree->current = tree->current->leftChild;
}
if(tree->current==tree->root){
tree->nextComplete=1;
}else{
tree->nextComplete=0;
}
}
void Next(ThreadBiTree *tree){
ThreadBiNode *p = tree->current->rightChild;
if(tree->nextComplete==1) return;
if(tree->current->rightThread==0){
while(p->leftThread==0){
p=p->leftChild;
}
tree->current = p;
if(tree->current==tree->root){
tree->nextComplete=1;
}
}
}
/*判断是否已经到中序线索二叉树的尾部*/
int EndOfNext(ThreadBiTree *tree){
return tree->nextComplete;
}
测试
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
typedef char DataType;
#include "InThreadIterator.h"
ThreadBiNode *GetTreeNode(DataType item,ThreadBiNode *left,ThreadBiNode *right){
//创建二叉树节点函数
ThreadBiNode *p;
p = (ThreadBiNode *)malloc(sizeof(ThreadBiNode));
p->data = item;
p->leftChild = left;
p->rightChild = right;
return p;
}
void MakeCharTree(ThreadBiNode **root){
ThreadBiNode *b,*c,*d,*e,*f,*g;
g = GetTreeNode('G',NULL,NULL);
d = GetTreeNode('D',NULL,g);
b = GetTreeNode('B',d,NULL);
e = GetTreeNode('E',NULL,NULL);
f = GetTreeNode('F',NULL,NULL);
c = GetTreeNode('C',e,f);
*root = GetTreeNode('A',b,c);
}
void main(void){
ThreadBiNode *root;
ThreadBiTree tree;
MakeCharTree(&root);//构建二叉树
CreatInThread(&root);//创建中序线索二叉树
getch();
printf("二叉树中序正向遍历序列为:");
getch();
ThreadInitiate(&tree,root);//循环初始化
for(First(&tree);!EndOfNext(&tree);Next(&tree)){
//循环遍历访问
printf("%c",tree.current->data);
}
system("pause");
}