线索化 - 遍历思想,流程,代码
1、前言
普通二叉树仅仅能找到结点的左右孩子信息。而该结点的直接前驱和直接后继仅仅能在遍历过程中获得。
若可将遍历后相应的有关前驱和后继预存起来,则从第一个结点開始就能非常快“顺藤摸瓜”而遍历整个树了。
二叉线索树思想是干什么的?
中序遍历这棵树===》转换成链表訪问
2线索化思想
结论:线索化过程就是在遍历过程(如果是中序遍历)中改动空指针的过程:
将空的lchild改为结点的直接前驱。
将空的rchild改为结点的直接后继。
3线索化思想
请将此树线索化。
1)右空指针线索化:
2)左空指针线索化
3)总结
线索化的本质:让前后结点,建立关系。
1)两个辅助指针变量形成差值后:后继结点的左孩子指向前驱结点,前驱结点的右孩子指向后继结点。
2)赋值指针变量和业务操作的逻辑关系
代码:
// threadTree.cpp // 树的线索化 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <stack> using namespace std; // 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) { // 没有左子树 p->LTag = Thread; // 前驱线索 p->lchild = pre;// 左孩子指向前驱 } if (!pre->rchild) { // 前驱没有又孩子 pre->RTag = Thread; // 后继线索 pre->rchild = p; // 前驱又孩子指向后继 } pre = p; // 保持pre指向p的前驱 inThreading(p->rchild); // 递归右子树线索化 } } // 中序遍历二叉树T。并将当中序线索化,thrt指向头结点 BiThrNode* inOrderThreading(BiThrTree T) { BiThrNode *Thrt = NULL; Thrt = (BiThrNode *)malloc(sizeof(BiThrNode)); if (!Thrt) { return NULL; } memset(Thrt, 0, sizeof(BiThrNode)); Thrt->LTag = Link; // 左孩子为孩子指针 Thrt->RTag = Thread; // 右孩子为线索化的指针 Thrt->rchild = Thrt; // 右指针回指 if (!T) { // 若二叉树为空,则左指针回指 Thrt->lchild = Thrt; } 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; } void operatorTree() { BiThrTree T, H; printf("请按前序输入二叉树(如:'ABDH##I##EJ###CF##G##')\n"); T = createBiThrTree(); // 按前序产生二叉树 H = inOrderThreading(T); // 中序遍历,并中序线索化二叉树 printf("中序遍历(输出)二叉线索树:\n"); InOrderTraverse_Thr(H); // 中序遍历(输出)二叉线索树 // H D I B J E A F C G printf("\n逆序訪问:"); InOrderTraverse_Thr2(H); // G C F A E J B I D H printf("\n"); } int main() { operatorTree(); return 0; }