二叉树的线索化和实现

二叉树的线索化

为什么要线索化:

在中序遍历二叉树时能够快速的找到某个节点的前驱或后继节点。

条件支持:

在一棵有 n 个节点(每个节点都有前驱和后继两个指针域)的二叉树中,有 n-1 条边,所以会有 2n -(n-1)= n+1 个空指针域

线索化后的结果

线索化后的访问流程

中序线索二叉树的遍历过程如下:

1️⃣ 从根节点开始,沿着左指针一直向下,找到最左节点 p
2️⃣ 访问该节点;
3️⃣ 然后根据 rTag 决定下一步:

  • p->rTag == 1,说明 p->right 是中序后继线索,直接执行 p = p->right

  • p->rTag == 0,说明 p->right 是右子树,转到右子树,继续寻找该右子树的最左节点;

不断重复步骤 2️⃣ 和 3️⃣,直到 p == NULL

如上图所示,当找到D节点时,D是当前状态下的最左节点左点(先访问它),开始 p=p->right,p发现D节点的 rtag==1 说明 D->right 是D的后驱节点,直接访问B;发现 B->rtag == 0 说明 B->right 是B节点的右子树,则进入以 B->left 为根节点的右子树寻找最左节点;发现E就是该最左节点,直接访问E然后继续执行 p=p->right; 接下来的流程以此类推。

如何进行线索化

cur通过递归中的递不断从根节点往左走,然后通过归返回上一个节点。

但cur碰到第一个NULL时,通过归返回上一个节点并通过  cur->left = prev 使prev加入。

并不断通过  prev->right = cur 来记录cur的上一个节点

 cur->left=prev;
 prev->right=cur;

节点结构

 typedef struct treeNode{
     Element data;
     struct treeNode *left;
     struct treeNode *right;
     int lTag;       // 0表示left指向左孩子,1表示left指向了中序前驱
     int rTag;       // 0表示right指向右孩子,1表示right指向了中序后驱
 }BTNode;
 // 树头结构
 typedef struct{
     BTNode *root;
     int count;
 }ThreadBTree;

线索化

 static int *prev;
 static void inOrderThreading(BTNode *cur){
     if(cur){
         inOrderThreading(cur->left);
         // 此处代码与中序遍历输出结果的功能位置一致,只是把功能改成了线索化
         // 相当于从左边第一次回中
         if(cur->left==NULL){
             cur->lTag=1;
             cur->left=prev;
         }
         if(prev && prev->right==NULL){
             cur->rTag=1;
             prev->right=cur;
         }
         prev=cur;   // 更新prev节点,让他指向cur的前一个节点
         inOrderThreading(node->right);
     }
 }
 ​
 void inOrderThreadingBTree(ThreadedBTree *tree){
     if(tree){
         inOrderThreading(tree->root);
     }
 }
 ​
 // 线索化后遍历这棵树
 void InOrderBTree(ThreadedBTree *tree){
     BTNode *node=tree->root;
     while(node){
         // 一直往左走
         while(node->lTag==0){
             node=node->left;
         }
         // 找到了线索化的首节点
         visitBTNode(node);
         // 向右进行中序线索化后的结果
         while(node->rTag && node->right){
             node=node->right;
             visitBTNode(node);
         }
         // 将这个不是右线索化的节点当作新节点再进行循环
         node=node->right;
     }
 }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值