二叉树的理解
线索化的实质:将二叉链表中的空指针改为指向前驱或后继的线索。由于前驱和后继信息只有在遍历该二叉树时才能得到,所以,线索化的过程就是在遍历的过程中修改空指针的过程。
二叉树的作用:将二叉树线索化后,减少空指针数量,赋予二叉树新的意义。如:在中序线索化后,可以用以近队列存储的方式访问二叉树,加快访问速度和查找效率。
线索化过程:
线索化过程于中序递归遍历没太大区别,先递归调用左子树,递归后执行线索操作,再递归调用右子树。
线索操作:
二叉树的存储结构
结构特点:相较于普通二叉树增加左右标记位,ltag、rtag。
标记位l®tag为0,代表l®child指向当前结点的左(右)孩子;
标记位l®tag为1,代表l®child指向当前结点的前(后)继;
#include <stdio.h>
#include <stdlib.h>
typedef struct LNode{
int data;
struct LNode *leftchild;
struct LNode *rightchild;
int ltag,rtag;
}LNode;
使用排序二叉树方式建立二叉树
void InitThreadTree(LNode **root, int Elem){
*root = (LNode *)malloc(sizeof(LNode));
if( !(*root) ){
printf("Memory allocation for root failed.\n"); return;
}
(*root)->data = Elem;
(*root)->leftchild = NULL;
(*root)->rightchild = NULL;
(*root)->ltag = 0;
(*root)->rtag = 0;
}
void InsertNode(LNode *root,int elem){
LNode *newnode = NULL;
LNode *p = root, *last_p = NULL;
newnode = (LNode*)malloc(sizeof(LNode));
if(!newnode){
printf("Memory allocation for newnode failed.\n");
return;
}
newnode->data = elem;
newnode->leftchild = NULL;
newnode->rightchild = NULL;
newnode->ltag = 0;
newnode->rtag = 0;
while(NULL != p){ //循环让头指针指向它要插入结点的位置
last_p = p;
if(newnode->data < p->data){
p=p->leftchild;
}
else if(newnode->data > p->data){
p=p->rightchild;
}
else{
printf("Node to be inserted has existed.\n");
free(newnode);
return;
}
}
p=last_p;
if(newnode->data < p->data){
p->leftchild=newnode;
}
else{
p->rightchild=newnode;
}
}
线索化过程
void InThreadProcess( LNode *P, LNode **Pre ){ //中序线索化
if(P != NULL){
InThreadProcess(P->leftchild, Pre);
if(P->leftchild == NULL){ //左子树为空,找其前驱结点
P->leftchild = (*Pre);
P->ltag = 1;
}
if((*Pre) != NULL && (*Pre)->rightchild == NULL){
//(*Pre)!=NULL 含义是当前结点P不是第一个结点,第一个结点没有后驱结点
//Pre的右子树为空,为右子树添加后继结点,后继结点为右子树的最左结点
(*Pre)->rightchild = P;
(*Pre)->rtag = 1;
}
(*Pre) = P; //注意理解Pre位置,只有此处修改Pre的值
InThreadProcess(P->rightchild, Pre);
}
}
void InThread( LNode *T ){ //线索化的主函数
LNode *Pre = NULL;
if( T != NULL ){
InThreadProcess(T, &Pre);
Pre->rightchild = NULL;
Pre->rtag = 1;
}
}
树的前序递归遍历
void visit(LNode *p){
printf("%d,",p->data);
}
void PreTreverse(LNode *root){
if(root != NULL){
visit(root);
PreTreverse(root->leftchild);
PreTreverse(root->rightchild);
}
}
树的线索化遍历
LNode *FirstNode(LNode *p){
while(p->ltag == 0){
p = p->leftchild;
}
return p;
}
LNode *NextNode(LNode *p){
if(p->rtag == 0)
return FirstNode(p->rightchild);
else
return p->rightchild;
}
void Inorder(LNode *T){
LNode *p;
for(p=FirstNode(T); p!=NULL; p=NextNode(p)){
visit(p);
}
}
运行主函数
int main(){
LNode *head=NULL;
InitThreadTree(&head, 4);
InsertNode(head, 2);
InsertNode(head, 1);
InsertNode(head, 3);
InsertNode(head, 6);
InsertNode(head, 5);
InsertNode(head, 7); //先序遍历序列为1234567
//PreTreverse(head);
InThread(head);
Inorder(head);
printf("Hello world!\n");
return 0;
}