线索化是为了能够像链表一样遍历树。
线索化概念
1、前言
普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得。
若可将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快“顺藤摸瓜”而遍历整个树了。
二叉线索树思想是干什么的?
中序遍历这棵树===》转换成链表访问
2线索化思想
结论:线索化过程就是在遍历过程(假设是中序遍历)中修改空指针的过程:
将空的lchild改为结点的直接前驱;
将空的rchild改为结点的直接后继。
3线索化思想训练
请将此树线索化。
1)右空指针线索化:
2)左空指针线索化
3)总结
线索化的实现
1)线索化树结点
typedef struct BiThrNode /* 二叉线索存储结点结构 */
{
char data; /* 结点数据 */
struct BiThrNode *lchild, *rchild; /* 左右孩子指针 */
int LTag;
int RTag; /* 左右标志 */
} BiThrNode, *BiThrTree;
2)线索化思想分析
线索化的本质:让前后结点,建立关系;
1)两个辅助指针变量形成差值后:后继结点的左孩子指向前驱结点,前驱结点的右孩子指向后继结点。
2)赋值指针变量和业务操作的逻辑关系
二叉树线索化树的遍历 /* 中序遍历二叉线索树T(头结点)的非递归算法 */ int InOrderTraverse_Thr(BiThrNode* T) { BiThrNode* p; p = T->lchild; /* p指向根结点 */ while (p != T) { /* 空树或遍历结束时,p==T */ while (p->LTag == Link) p = p->lchild; printf("%c ", p->data); while (p->RTag==Thread && p->rchild!=T) { p = p->rchild; printf("%c ", p->data); } p=p->rchild; } return 0; }
创建树:
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <string.h> #include <stdio.h> typedef struct BiTNode { int data; struct BiTNode *lchild, *rchild; }BiTNode; typedef struct BiTNode * BiTree; void InOrder(BiTNode *T) { if (T == NULL) { return ; } if (T->lchild != NULL) { InOrder(T->lchild); } printf("%c ", T->data); // if (T->rchild != NULL) { InOrder(T->rchild); } } // "1##" // 124###3## //创建树 用先序 BiTNode *BiTree_Creat() { BiTNode *tmp = NULL; char ch; scanf("%c", &ch); if (ch == '#') { return NULL; } else { tmp = (BiTNode *) malloc(sizeof(BiTNode)); //创建结点 if (tmp == NULL) { return NULL; } tmp->data = ch; tmp->lchild = NULL; tmp->rchild = NULL; //在创建结点的左子树 tmp->lchild = BiTree_Creat(); tmp->rchild = BiTree_Creat(); return tmp; } } //释放树 选释放左子树 在释放右子树 在释放根结点 void BiTree_Free(BiTNode *T) { if (T == NULL) { return ; } if (T->lchild != NULL) { BiTree_Free(T->lchild); //释放左子树 把左子树的根结点 传给释放函数 T->lchild = NULL; } if (T->rchild != NULL) { BiTree_Free(T->rchild); T->rchild = NULL; } free(T); // } void main() { BiTNode *T = NULL; printf("#号法创建树 请输入字符串 ( 124###3## ): "); T = BiTree_Creat(); InOrder(T); BiTree_Free(T); printf("hello... "); system("pause"); return ; }
树的线索化:
#define _CRT_SECURE_NO_WARNINGS #include "string.h" #include "stdio.h" #include "stdlib.h" /* Link==0表示指向左右孩子指针, */ /* Thread==1表示指向前驱或后继的线索 */ #define Thread 1 #define Link 0 typedef struct BiThrNode /* 二叉线索存储结点结构 */ { char data; /* 结点数据 */ struct BiThrNode *lchild, *rchild; /* 左右孩子指针 */ int LTag; int RTag; /* 左右标志 */ } BiThrNode, *BiThrTree; char Nil='#'; /* 字符型以空格符为空 */ /* 按前序输入二叉线索树中结点的值,构造二叉线索树T */ BiThrNode* CreateBiThrTree() { BiThrNode *tmp = NULL; char ch; scanf("%c",&ch); if (ch == '#') { return NULL; } else { tmp = (BiThrNode *)malloc(sizeof(BiThrNode)); if (tmp == NULL) { return NULL; } memset(tmp, 0, sizeof(BiThrNode)); tmp->data = ch; tmp->lchild = CreateBiThrTree(); /* 递归构造左子树 */ tmp->rchild = CreateBiThrTree(); } return tmp; } BiThrNode *pre; /* 全局变量,始终指向刚刚访问过的结点 */ /* 中序遍历进行中序线索化 */ void InThreading(BiThrNode *p) { if(p) { InThreading(p->lchild); // 递归左子树线索化 if(p->lchild == NULL) // 没有左孩子 { p->LTag = Thread; p->lchild = pre; //前驱线索 左孩子指针指向前驱 } if(pre->rchild == NULL) // 前驱没有右孩子 { pre->RTag = Thread; pre->rchild = p; // 后继线索 前驱右孩子指针指向后继(当前结点p) } pre = p; // 保持pre指向p的前驱 InThreading(p->rchild); // 递归右子树线索化 } } /* 中序遍历二叉树T,并将其中序线索化,Thrt指向头结点 */ BiThrNode* InOrderThreading(BiThrTree T) { BiThrNode *Thrt = NULL; Thrt = (BiThrNode *)malloc(sizeof(BiThrNode)); //建头结点 if (Thrt == NULL) { return NULL; } memset(Thrt, 0, sizeof(BiThrNode)); Thrt->LTag = Link; //左孩子为孩子指针 Thrt->RTag = Thread; //右孩子为线索化的指针 Thrt->rchild = Thrt; // 右指针回指 */ //步骤2和4 if(T == NULL) // 若二叉树空,则左指针回指 { Thrt->lchild = Thrt; //步骤1和3 } else { Thrt->lchild = T; //步骤1 pre = Thrt ; InThreading(T); // 中序遍历进行中序线索化 pre->rchild = Thrt; //步骤4 pre->RTag = Thread; // 最后一个结点线索化 Thrt->rchild = pre; //步骤2 } return Thrt; } /* 中序遍历二叉线索树T(头结点)的非递归算法 */ int InOrderTraverse_Thr(BiThrNode* T) { BiThrNode* p; p = T->lchild; /* p指向根结点 */ while (p != T) { /* 空树或遍历结束时,p==T */ while (p->LTag == Link) p = p->lchild; printf("%c ", p->data); //如果中序遍历的最后一个结点的 右孩子 == T 说明到最后一个结点 ,遍历结束.. while (p->RTag==Thread && p->rchild!=T) { p = p->rchild; printf("%c ", p->data); } p = p->rchild; } return 0; } /* 中序遍历二叉线索树T(头结点)的非递归算法 */ int InOrderTraverse_Thr2(BiThrNode* T) { BiThrNode* p; p = T->rchild; /* p指向根结点 */ while (p != T) { /* 空树或遍历结束时,p==T */ while (p->RTag == Link) p = p->rchild; printf("%c ", p->data); //如果中序遍历的最后一个结点的 右孩子 == T 说明到最后一个结点 ,遍历结束.. while (p->LTag==Thread && p->lchild!=T) { p = p->lchild; printf("%c ", p->data); } p = p->lchild; } return 0; } int main() { BiThrTree T, H; printf("请按前序输入二叉树(如:'ABDH##I##EJ###CF##G##') "); T = CreateBiThrTree(); // 按前序产生二叉树 H = InOrderThreading(T); // 中序遍历,并中序线索化二叉树 printf("中序遍历(输出)二叉线索树: "); InOrderTraverse_Thr(H); // 中序遍历(输出)二叉线索树 printf(" 逆序访问:"); InOrderTraverse_Thr2(H); printf(" "); system("pause"); return 0; }
04 09完