留个笔记
Description
建立中序线索二叉树,并按中序遍历该二叉树。
Input
输入数据有多组,对于每组测试数据
按先序遍历顺序输入二叉树的各个结点值,#表示空节点。
Output
该二叉树的中序遍历序列。
Sample Input
ABD##E##C##
Sample Output
DBEAC
感觉有点鸡肋
前置定义
char a[10000];//读取字符串
int index;//用作建树的时候控制数组下表,这里有多组样例,也不知道有什么更好的办法
typedef struct TreeNode* ptr;
#define Size sizeof(TreeNode)
struct TreeNode {
char data;
int ltag,rtag;//标记是线索还是指针
ptr lchild, rchild;//
};
建立线索二叉树首先要建立一棵普通的二叉树,这里给出了先序遍历的序列就直接建了,就先把所有指针域的tag赋值为1了,后面还要修改的
//建立二叉树
void createTree(ptr &p) {
if (index == strlen(a))return;//建完了
index++;
char ch = a[index];
if (a[index] == '#') {
p = NULL;
return;
}
p = (ptr)malloc(Size);
p->data = ch; //不要忘记填充数据
p->ltag = 1;
p->rtag = 1;//都赋值为指针
createTree(p->lchild);
createTree(p->rchild);
}
接下来是线索二叉树的建立
就以中序序列为例,这里把0作为线索,1作为指针,左线索指向前驱,有线索指向后继也就是ltag和rtag
为了后面的遍历的方便一般会额外建立一个根节点的根节点,也就是所谓头结点,作为遍历序列的前驱和最后一个节点的后继,也就是最先和最后
第一步是进行头结点的初始化,头结点的两个指针域一定是线索,一开始让头结点的右线索指向自己,因为这时候还不知道后继是谁,左线索要视根节点的情况而定,要是根节点为空也就是一棵空树的话,没有人的前驱是头结点,那么头结点的左线索也指向自己。
然后递归建立线索二叉树,这里的pre是全局变量,在初始化的时候pre指向了头结点,传参是根节点,可以看到这里的pre和p(传参)就是前驱和后继的关系,在后面的动态变化中也要一直维护这种关系(这也是为什么一定要以中序去建立线索二叉树),从而能够不断去更新pre节点的右线索(后继)和p的左线索(前驱),当然更新的前提是这个指针域必须为空。
ptr pre;//全局变量用来记录前驱用的,这里实际上一直在变
//线索化
void thread(ptr p) {//地址不引用也可以修改内容
if (p == NULL)return;//空节点无意义
thread(p->lchild);
//下面开始线索化,右线索指向后继,左线索指向前驱
if (pre->rchild == NULL) {
pre->rtag = 0;
pre->rchild = p;
}
if (p->lchild == NULL) {
p->ltag = 0;
p->lchild = pre;
}
pre = p;
thread(p->rchild);
}
//建立线索二叉树
//线索0指针1
void createThread(ptr &pf,ptr pb) {//pfront和pbehind
//分别前驱和当前节点,其实就是头结点和根节点,这里实际上到最后都是一样的
pf = (ptr)malloc(Size);
pf->ltag = 0;
pf->rtag = 0;//线索
pf->rchild = pf;//右指针指向自己
if (!pb) {
pf->lchild = pf;
return;
}//空树
pre = pf;
pf->lchild = pb;
thread(pb);
pre->rtag = 0;
pre->rchild = pf;//pf没有变但是pre变了,变成了最后一个节点,这个顺序要注意
}
遍历操作
线索二叉树本身的右线索就已经指向了遍历序列的后继,只要找到了右线索,那么指向的那个节点直接输出就可以,所以首先要根据一定的顺序找到第一个节点,中序的第一个节点就是顺着头结点一直向左下找,找到左孩子为空(有右孩子不影响,根在右之前),那么这个就是第一个节点,这个其实是一组输出,然后根据左根右遍历原则,这时候去看右指针域是不是线索,是的话直接跳转输出,不是的话(可能是有右孩子,这时候tag为指针,或者已经指向头结点了),那么就退出,跳转到那个指针,然后再以相同的规则,一直往左下找找到没有右孩子,再去找一直找到最终指向头结点退出
//其实就是按照规则先去找到最左下的然后通过右线索(直接指向遍历序列的后继),再以同样规则查找
void print(ptr T) {
ptr p;
p = T->lchild;
//开始遍历
while (p != T) {
while (p->ltag == 1)p = p->lchild;//找到最左的节点
printf("%c", p->data);//输出最左的字母
while (p->rtag == 0 && p->rchild != T) {//找后继,一直找找到找不到了为止
p = p->rchild;
printf("%c", p->data);
}
p = p->rchild;
}
}
全部代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char a[10000];
int index;//用作建树的时候控制数组下表,这里有多组样例,也不知道有什么更好的办法
typedef struct TreeNode* ptr;
#define Size sizeof(TreeNode)
struct TreeNode {
char data;
int ltag,rtag;//标记是线索还是指针
ptr lchild, rchild;//
};
//建立二叉树
void createTree(ptr &p) {
if (index == strlen(a))return;//建完了
index++;
char ch = a[index];
if (a[index] == '#') {
p = NULL;
return;
}
p = (ptr)malloc(Size);
p->data = ch; //不要忘记填充数据
p->ltag = 1;
p->rtag = 1;//都赋值为指针
createTree(p->lchild);
createTree(p->rchild);
}
ptr pre;//全局变量用来记录前驱用的,这里实际上一直在变
//线索化
void thread(ptr p) {//地址不引用也可以修改内容
if (p == NULL)return;//空节点无意义
thread(p->lchild);
//下面开始线索化,右线索指向后继,左线索指向前驱
if (pre->rchild == NULL) {
pre->rtag = 0;
pre->rchild = p;
}
if (p->lchild == NULL) {
p->ltag = 0;
p->lchild = pre;
}
pre = p;
thread(p->rchild);
}
//建立线索二叉树
//线索0指针1
void createThread(ptr &pf,ptr pb) {//分别前驱和当前
pf = (ptr)malloc(Size);
pf->ltag = 0;
pf->rtag = 0;//线索
pf->rchild = pf;//右指针指向自己
if (!pb) {
pf->lchild = pf;
return;
}//空树
pre = pf;
pf->lchild = pb;
pf->ltag = 0;//线索
thread(pb);
pre->rtag = 0;
pre->rchild = pf;//pf没有变但是pre变了,变成了最后一个节点,这个顺序要注意
}
//其实就是按照规则先去找到最左下的然后通过右线索(直接指向遍历序列的后继),再以同样规则查找
void print(ptr T) {
ptr p;
p = T->lchild;
//开始遍历
while (p != T) {
while (p->ltag == 1)p = p->lchild;//找到最左的节点
printf("%c", p->data);//输出最左的字母
while (p->rtag == 0 && p->rchild != T) {//找后继,一直找找到找不到了为止
p = p->rchild;
printf("%c", p->data);
}
p = p->rchild;
}
}
void mediumtPrint(ptr p) {
if (p == NULL)return;
mediumtPrint(p->lchild);
printf("%c", p->data);
mediumtPrint(p->rchild);
}
int main()
{
ptr root, rootParent;
while (~scanf("%s", a)){
index = -1;
root = (ptr)malloc(Size);
createTree(root);//先建树
//mediumtPrint(root);//验证树建立的正确性
createThread(rootParent, root);//建立线索二叉树
print(rootParent);//中序遍历线索二叉树输出
printf("\n");
}
return 0;
}