线索二叉树(创建与遍历)

/*key mind---->对于需要线索化的节点  其左节点为前驱,右节点为后继*/

/*什么是线索树
* 定义:对于n个结点的二叉树,在二叉链存储结构中有n+1个空链域(共有2n个指针域,会用掉n-1指针域,就空了2n-(n-1)个指针域)
*	利用这些空链域存放在某种遍历次序下该结点的前驱结点和后继结点的指针,这些指针称为线索。
//* 注意是空的指针域,想下面的这颗树,A的左右child要变吗?显然不用,因为它的左右指针域不是空的,是放了东西的属于是那n+1个里面的。
* 而像C的两边这样的才是空的,其原来放的都是NULL,是对这样的节点才放入线索化的结果
*/

/*以下是一个举例(-1为NULL)
* 原树:
*	    A
*	   / \
*	  B   C
*	 / \
*	D   E
这个树此时的空节点(_)
*	       B|A|C
*	     /       \
*	  D|B|E    _|C|_
*	 /     \
* _|D|_   _|E|_
*
前序线索化(ABDEC)
*	       B|A|C
*	     /       \
*	  D|B|E    E|C|-1
*	 /     \
* B|D|E   D|E|C
*
中序线索化(DBEAC)
*	       B|A|C
*	     /       \
*	  D|B|E    A|C|-1
*	 /     \
* -1|D|B   B|E|A
*
后序线索化(DEBCA)
*	       B|A|C
*	     /       \
*	  D|B|E    B|C|A
*	 /     \
* -1|D|E   D|E|B
*/

/*以下是关于线索二叉树的注意点
* 
* 1.应该从前/中/后序遍历的结果作为切入点,思考前驱和后继
*	l_child与parent有关
*	r_child与parent有关
*	可以近似的理解成左节点为前驱,右节点为后继
* 2.parent确实是要传NULL,判断是不是第一次的办法就是看parent是不是NULL(parent为二级)
* 3.root为一级:因为只有改变当前节点值的时候才传二级(比如creat_tree的时候就传的二级)
*	parent为二级:因为要改变parent的值
* 4.这段代码
	parent->rtag = 1;
	parent->r_child = NULL;
	只有前序和中序线性化才需要在main中写
* 5.if (root->ltag == 0)//前序线索化独有
*/

/*这段是错误的理解,没有理解线索树的定义
*	对于根节点不能这么解释,其左右不是线索化的,还是原来的节点
*	    A
*	   / \
*	  B   C
*	 / \
*	D   E
*	就像这颗树,前序遍历时,要是将A也线索化的话,其lchild应该是NULL,rchild应该是D(ABDEC),但真正的线索化并不要求这样,所以
*	A的l,rchild还是B和C
*/

/*关于线索二叉树的遍历:
* 前序的线索二叉树:只需要findNext,因为自己root就是头,不需要找头
* 中序:只需要找头,找到头后,下面的每一个都是rchild,因为线索化过了
* 后序:要节点中加一个parent域,再左右遍历即可
*/

#pragma once
#include <stdio.h>
#include <stdlib.h>
#include <stack>

struct node {
	char data;
	int ltag;
	int rtag;
	struct node* l_child;
	struct node* r_child;
	struct node* parent;
};

void creat_tree(struct node** root, char* ch, struct node** parent);
void pre_thread(struct node* root, struct node** parent);
void in_thread(struct node* root, struct node** parent);
void post_thread(struct node* root, struct node** parent);
//前序线索化的遍历
void traverse_pre_threadtree(struct node* root);
struct node* pre_getNext(struct node* root);
//中序线索化的遍历
void traverse_in_threadtree(struct node* root);
struct node* in_findFirst(struct node* root);
//后序线索化的遍历
void traverse_post_threadtree(struct node* root);
struct node* post_findFirst(struct node* root);

#include "head.h"

void creat_tree(struct node** root, char* ch, struct node** parent) {
	static int cur = 0;
	char tmp = ch[cur++];
	if (tmp == '\0') {
		(*root) = NULL;
		return;
	}
	if (tmp != '#') {
		struct node* newnode = (struct node*)malloc(sizeof(struct node));
		newnode->data = tmp;
		newnode->ltag = newnode->rtag = 0;
		newnode->parent = *parent;
		(*root) = newnode;
		creat_tree(&(*root)->l_child, ch, &(*root));
		creat_tree(&(*root)->r_child, ch, &(*root));
	}
	else {
		(*root) = NULL;
	}
}

void pre_thread(struct node* root, struct node** parent) {
	if (root != NULL) {
		if (root->l_child == NULL) {
			root->ltag = 1;
			root->l_child = *parent;
		}
		if ((*parent) != NULL && (*parent)->r_child == NULL) {
			(*parent)->rtag = 1;
			(*parent)->r_child = root;
		}
		(*parent) = root;
		if (root->ltag == 0)//前序线索化独有,
			pre_thread(root->l_child, parent);
		pre_thread(root->r_child, parent);
	}
}
void in_thread(struct node* root, struct node** parent) {
	if (root != NULL) {
		in_thread(root->l_child, parent);
		//deeling
		if (root->l_child == NULL) {
			root->ltag = 1;
			root->l_child = (*parent);
		}
		if ((*parent) != NULL && (*parent)->r_child == NULL) {
			(*parent)->rtag = 1;
			(*parent)->r_child = root;
		}
		(*parent) = root;
		in_thread(root->r_child, parent);
	}
}
void post_thread(struct node* root, struct node** parent) {
	if (root != NULL) {
		post_thread(root->l_child, parent);
		post_thread(root->r_child, parent);
		//deeling
		if (root->l_child == NULL) {
			root->ltag = 1;
			root->l_child = (*parent);
		}
		if ((*parent) != NULL && (*parent)->r_child == NULL) {
			(*parent)->rtag = 1;
			(*parent)->r_child = root;
		}
		(*parent) = root;
	}
}
//前序线索化的遍历
void traverse_pre_threadtree(struct node* root) {
	while (root!=NULL) {
		printf("%c ", root->data);
		root = pre_getNext(root);
	}
}
struct node* pre_getNext(struct node* root) {
	if (root->ltag == 0)
		return root->l_child;
	else
		return root->r_child;
}
//中序线索化的遍历
void traverse_in_threadtree(struct node* root) {
	root = in_findFirst(root);
	while (root != NULL) {
		printf("%c ", root->data);
		root = root->r_child;
	}
}
struct node* in_findFirst(struct node* root) {
	return root->ltag == 0 ? in_findFirst(root->l_child) : root;
	//要是该节点左边是原生的(ltag==0)就继续找头,要是不是就什么这个是最左边的了,就是头了,所以返回.
}

//后序线索化的遍历//有大问题

void traverse_post_threadtree(struct node* root) {
	root = post_findFirst(root->l_child);
	while (root->parent!=NULL) {
		printf("%c ", root->data);
		if (root->rtag == 1) 
			printf("%c ", root->r_child->data);
		root = root->parent;
	}
	root = post_findFirst(root->r_child);
	while (root->parent != NULL) {
		printf("%c ", root->data);
		if (root->rtag == 1&&root->r_child!=root->parent)//因为左边为前驱,和parent相同就是最后一个了
			printf("%c ", root->r_child->data);
		root = root->parent;
	}
	printf("%c ", root->data);
}
struct node* post_findFirst(struct node* root) {
	return root->ltag == 1 ? root : post_findFirst(root->l_child);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值