问题:
创建一个线索二叉树,并将其中进行线索化。任给一个结点找到结点的中序前驱和中序后继。
算法分析:
第一步创建二叉树结构:
- 根据输入一个广义表来创建二叉树(A(B(D,E(H)),C(F(,I),G))),使用二叉树的链式表示,左右孩子表示法;
- 用一个栈来存“(”后面的字母的指针,遇见“)”回退top–,再等于向top-1的指针
- 遍历广义表字符串,令pre指向树的头结点,开始遍历,遇见“(”或“,”,往前走一步i++;遇见每个字母,申请一块内存p,判断i-1是否为“(”,是则pre->lchild =p,p入栈;若为“,”,则pre->rchild = p;
第二步按照中序进行遍历,线索化:
- 左子树线索化:
- 找到最左下端结点,访问:
- 右子树线索化
第三步按照前驱后继进行访问:
代码:
#include "pch.h"
#include <iostream>
#include <stdio.h>
#include<stdlib.h>
constexpr auto MAXSIZE = 100;
typedef enum {Link,Thread} PointerTag;
typedef char DataType;
typedef struct Node // 定义线索二叉树存储类型
{
PointerTag LTag;
PointerTag RTag;
DataType data;
struct Node * lchild, *rchild;
} BiThrNode, *BiThrTree ;
BiThrNode *pre;
typedef struct
{
BiThrTree stack[MAXSIZE]; //存储树的结点指针
int top;//栈顶指针
}Stack;
void CreateBitree(BiThrTree * T, char * str)//创建线索二叉树
{
BiThrNode * pre,*p;
pre = NULL;
Stack PointerStack;
PointerStack.top = 0; //初始化栈
int i;
for (i = 0; i < strlen(str); i++)
{
if (str[i] == '(' || str[i] == ',')
{
continue;
}
else if(str[i] == ')')
{
PointerStack.top--;
if (PointerStack.top > 0)
{
pre = PointerStack.stack[PointerStack.top - 1];
}
}
else //为字母
{
//将第一个字母作为根节点
if (i == 1)
{
(*T )= (BiThrNode*)malloc(sizeof(BiThrNode));//申请一块结点的内存
(*T)->LTag = (*T)->RTag = Link;//初始化
(*T)->lchild = (*T)->rchild = NULL;
(*T)->data = str[i];
p = pre = (*T);
}
else
{
p = (BiThrNode*)malloc(sizeof(BiThrNode));//申请一块结点的内存
p->LTag = p->RTag = Link;//初始化
p->lchild = p->rchild = NULL;
p->data = str[i];
if (str[i - 1] == '(')
{
pre->lchild = p;
}
if (str[i - 1] == ',')
{
pre->rchild = p;
pre = p;// 更新pre
}
}
if (str[i + 1] == '(')//字母后面为'('。则将该字母入栈
{
PointerStack.stack[PointerStack.top++] = p;
pre = p;
}
}
}
}
void PrintBiTree(BiThrTree T) //打印二叉树
{
BiThrNode *p;
p = T;
if (p)
{
printf("%c", p->data);
PrintBiTree(p->lchild);
PrintBiTree(p->rchild);
}
}
void InThreading(BiThrTree T) //二叉树线索化
{
BiThrNode* p;
p = T;
if (p)
{
InThreading(p->lchild);//左子树线索化
if (!p->lchild)//前驱线索化
{
p->LTag = Thread;
p->lchild = pre;
}
if (!pre->rchild)//后继线索化
{
pre->RTag = Thread;
pre->rchild = p;
}
pre = p;
InThreading(p->rchild);//右子树线索化
}
}
void InOderThreading(BiThrTree *Thr,BiThrTree T)//通过中序遍历二叉树T,使T中序线索化
{
//创建一个头节点
if (!((*Thr) = (BiThrTree)malloc(sizeof(BiThrNode))))
exit(-1);
(*Thr)->data = 0;
(*Thr)->LTag = Link;
(*Thr)->RTag = Thread;
(*Thr)->rchild = (*Thr);//修改后继线索标志
if (!T)//如果二叉树为空,将头结点的左指针指向自己
{
(*Thr)->lchild = (*Thr);
}
else
{
(*Thr)->lchild = T;
pre = (*Thr);//将pre指向已经线索化的结点
InThreading(T);//中序遍历线索化
pre->rchild = (*Thr);
pre->LTag = Thread;
(*Thr)->rchild = pre;
}
}
int InorderTraverse(BiThrTree T, int(*visit) (BiThrNode *e))
//遍历线索二叉树,visit为函数指针,指向访问结点函数的实现
{
BiThrTree p;
p = T->lchild;
while (p != T) //空树遍历结束时p=T
{
while (p->LTag == Link)//找到最下端的结点
p = p->lchild;
if (!visit(p)) //打印
return 0;
while (p->RTag == Thread && p->rchild != T)
{
p = p->rchild;
visit(p);
}
p = p->rchild;
}
return 1;
}
int Print(BiThrTree T)
//打印结点信息
{
static int k = 1;
printf("%2d\t %s\t %2c\t %s\t\n", k++, T->LTag == Link ? "Link" : "Thread", T->data, T->RTag == Thread ? "Thread" : "Link");
return 1;
}
BiThrNode * InOrderFind(BiThrTree Thr , DataType e)
//查找结点
{
BiThrNode *p;
p = Thr->lchild;//指向根结点
if (!p)
return NULL;
while (p!=Thr)
{
while (p->LTag == Link) //找到最左端结点
{
p = p->lchild;
}
if (p->data == e)
{
return p;
}
while (p->RTag == Thread && p->rchild != Thr) //往后走
{
p = p->rchild;
if (p->data == e)
{
return p;
}
}
p = p->rchild;//如果右边是LINK
}
}
BiThrNode* InOrderPrev(BiThrTree T)
//找到P结点的中继前驱
{
BiThrNode * p;
p = T;
if (p->LTag == Thread)
{
return p->lchild;
}
p = p->lchild;//找到左子树的最右边下端点
while (p->RTag == Link)
{
p = p->rchild;
}
return p;
}
BiThrNode* InOrderPost(BiThrTree T)
//找到p结点的后继
{
BiThrNode * p;
p = T;
if (p->RTag == Thread)
{
return p->rchild;
}
p = p->rchild;
while (p->RTag == Link)//找到右子树的最左下端结点
{
p = p->lchild;
}
return p;
}
int main()
{
BiThrTree T,Thr;
BiThrNode *p,*post,*prev;
char str[MAXSIZE] = "(A(B(D,E(H)),C(F(,I),G)))";
CreateBitree(&T, str);
printf("二叉树:\n");
PrintBiTree(T);//打印二叉树
printf("\n");
InOderThreading(&Thr, T);//线索化
printf("中序线索化后的二叉树:\n");
InorderTraverse(Thr, Print);//遍历按中序打印
char c;
printf("输入需要查找前驱后后继结点的结点\n");
c = getchar();
p = InOrderFind(Thr, c);
if (p)
{
printf("打印找到的结点:\n");
Print(p);
}
prev = InOrderPrev(p);
post = InOrderPost(p);
if (prev)
{
printf("打印P结点的前驱结点:\n");
Print(prev);
}
if (prev)
{
printf("打印P结点的后继结点:\n");
Print(post);
}
return 0;
}
程序运行截图: