/*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);
}
线索二叉树(创建与遍历)
于 2023-06-28 21:25:23 首次发布