图解 二叉线索树

二叉线索树

概念

普通二叉树只能找到结点的左右孩子信息,而该结点的直接前驱和直接后继只能在遍历过程中获得。

若可将遍历后对应的有关前驱和后继预存起来,则从第一个结点开始就能很快“顺藤摸瓜”而遍历整个树了。

 

 

 

 

 理解:

线索化核心算法的理解类似使用2个辅助指针变量交替的挖字符串

 

代码讲解

 

 

按照严老师 增加一个头结点

 

 

 

#define _CRT_SECURE_NO_WARNINGS

#include "string.h"
#include "stdio.h"    
#include "stdlib.h"   
#include "io.h"  
#include "math.h"  
#include "time.h"

#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

#define MAXSIZE 100 /* 存储空间初始分配量 */
typedef int Status;
typedef char TElemType;
typedef enum{
	Link,  //Link = 0   表示指向左右孩子指针
	Thread //Thread = 1 表示指向前驱或后继的线索
}PointerTag;

//二叉线索存储节点
typedef struct BiThrNode{
	TElemType data;						//节点数据
	struct BiThrNode *lchild, *rchild;	//左右孩子指针
	PointerTag LTag;					//左标志
	PointerTag RTag;					//右标志
}BiThrNode, *BiThrTree;

TElemType Nil = '#';//字符型以空格符为空
Status visit(TElemType e)
{
	printf("%c", e);
	return OK;
}

//按前序输入二叉线索树中结点的值,构造二叉线索树
/* 0(整型)/空格(字符型)表示空结点 */
//以# 法 按照给定的先序序列 建立二叉链表
Status CreateBiThrTree(BiThrTree *T)//二级指针
{
	TElemType h;
	scanf("%c", &h);

	if (h == Nil){
		*T = NULL;
	}
	else{
		*T =(BiThrTree)malloc(sizeof(BiThrNode));
		if (NULL == *T){
			exit(OVERFLOW);
		}

		(*T)->data = h;//生产根节点
		CreateBiThrTree(&(*T)->lchild);//递归构造左子树
		if ((*T)->lchild){//有左孩子
			(*T)->LTag = Link;
		}
		CreateBiThrTree(&(*T)->rchild);//递归构造右子树
		if ((*T)->rchild){//有右孩子
			(*T)->RTag = Link;
		}
	}
	return OK;
}

BiThrTree pre;//全局变量,始终指向刚刚访问过得节点
//中序遍历进行中序线索化 算法
void InThreading(BiThrTree 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;		//前驱右孩子指向后继
		}
		pre = p;		//保持pre指向p的前驱,辅助指针交替移动
		InThreading(p->rchild);		//递归右子树线索化
	}
}

//中序遍历二叉树T,并将其中序线索化,Thrt指向头结点

Status InOrderThreading(BiThrTree *Thrt, BiThrTree T)
{
	//按照严老师的设计将二叉线索链表变为一个环
	*Thrt = (BiThrTree)malloc(sizeof(BiThrNode));
	if (NULL == *Thrt){
		exit(OVERFLOW);
	}
	(*Thrt)->LTag = Link;			//建立头结点
	(*Thrt)->RTag = Thread;
	(*Thrt)->rchild = (*Thrt);		//右指针回指

	if (!T){
		(*Thrt)->lchild = *Thrt;	//若二叉树为空,则左指针回指
	}
	else{
		(*Thrt)->lchild = T;		//让头结点的左孩子指向树根,避免悬空指针
		
		pre = (*Thrt);				//初始化 pre(全局变量)
		//------------------------------------------------
		InThreading(T);				//中序遍历进行中序线索化
		//--------------------------------------------------
		//线索化完后pre指向了中序遍历的末尾结点
		pre->rchild = *Thrt;		//让末尾结点的右孩子指向头结点
		pre->RTag = Thread;			//最后一个节点进行线索化
		
		(*Thrt)->rchild = pre;		//头结点的右孩子指向  中序遍历末尾结点,避免悬空指针
	}
	return OK;
}

//中序遍历 二叉线索树T (头结点)的非递归算法
//线索化的第二种遍历方法: 中序遍历过程中,将每个节点存放在链表中,则可通过链表访问整个树
Status InOrderTraverse_Thr(BiThrTree T)
{
	BiThrTree p;
	p = T->lchild;//p指向根节点
	while (p != T){//访问链表  空树或遍历结束时, p ==T

//------------------------将虚线部分之间内容屏蔽,则就是遍历一个链表
		//一直往左走,找到中序遍历的起点
		while (p->LTag == Link){
			p = p->lchild;
		}

		//访问左子树为空的节点,打印该节点
		if (!visit(p->data)){ //若起点值为空则出错告警
			return ERROR;
		}

		//如果这个结点有右子树且是线索化 ,找到p,然后返回到下一循环125行,一直往左走,类似递归
		//若有后继标志,则直接提取p->rchild中线索并访问后继结点;
		while (p->RTag == Thread && p->rchild != T){
			p = p->rchild;
			visit(p->data);//访问后继节点
		}
//------------------------
		p = p->rchild; //当前结点右域不空或已经找好了后继,则一律从结点的右子树开始重复{  }的全部过程
	}
	return OK;
}

int main()
{
	BiThrTree H, T;
	printf("请按前序输入二叉树(如:'ABDH##I##EJ###CF##G##')\n");

	CreateBiThrTree(&T);//按照前序 #法创建二叉树
	InOrderThreading(&H, T);//中序遍历,并中序线索化二叉树
	printf("中序遍历(输出)二叉线索树:\n");
	InOrderTraverse_Thr(H);//采用非递归算法中序遍历(输出)二叉线索树
	printf("\n");
	system("pause");;
	return 0;
}


 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
决策树流程图解是一种基本的分类与回归方法,它可以用来解决决策问题。决策树的流程图由判断模块和终止模块组成。判断模块用长方形表示,终止模块用椭圆形表示。流程图的箭头表示分支,可以链接到另一个判断模块或终止模块。决策树的生成过程中,我们需要选择最优的特征来进行切分,以得到一颗最优的决策树。为了衡量选择特征的优劣,我们引入了信息熵的概念。信息熵是衡量集合信息的度量方式,也称为香农熵。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [【机器学习】决策树——ID3和C4.5(理论+图解+公式推导)](https://blog.csdn.net/m0_47256162/article/details/119929570)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [决策树(基础理论篇)](https://blog.csdn.net/zz0377/article/details/114536492)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值