(先序,中序)线索化及遍历
由于篇幅的原因,这里仅仅展示(先序,中序)线索化及遍历,主要原因这两个有很高的相识度,思想几乎一样。仅仅是访问顺序不同!!!
接下来都是按先序操作实现功能(整体流程),中序操作实现功能(整体流程),后序操作实现功能(整体流程)。即一个一个讲完整在进行下一个。
后序线索化及遍历(我的下篇文章):
首先,不管在哪种线索化,都需要一个pre指针指向上次访问的结点,因为我们的目的是找到前驱和后继,那么就肯定需要两个指针(一前一后)。
一:先序线索化及遍历
递归与先序访问顺序
对应代码
//先序线索化
void PreThreading(BiThrTree p)
{
if (p)
{
if (!p->lchild) //前驱线索
{
p->lchild = pre;
p->LTag = Thread;
}
if (pre != NULL && !pre->rchild) //后继线索
{
pre->rchild = p;
pre->RTag = Thread;
}
pre = p;
if(p->LTag == Link)
PreThreading(p->lchild); //左子树线索化
if (p->RTag == Link)
PreThreading(p->rchild); //右子树线索化
}
}
2:先序线索化添加虚设头结点(建立双向循环链表)
作用:规范,方便,忠实数据结构书上的的做法(转一圈就结束),如果你觉得麻烦,不加也可以,但必须了解其遍历的前因后果,以便知道遍历结束的循环出口。
对应代码
//先序线索化二叉树(添加头结点)建立双向循环链表
Status PreOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
return OVERFLOW;
Thrt->LTag = Link; Thrt->RTag = Thread; //左指针指向头结点
Thrt->rchild = Thrt; //右指针回指
if (!T)
Thrt->lchild = Thrt; //二叉树为空,左指针回指
else
{
Thrt->lchild = T; pre = Thrt; //虚设头节点指向头节点
PreThreading(T);
pre->rchild = Thrt; pre->RTag = Thread; //处理最后一个节点指向虚设头结点
Thrt->rchild = pre;
}
return OK;
}
3:先序线索化遍历
先序线索化遍历前驱与后继图
核心思想:递归与访问顺序
1:如果你不添加虚设的头结点,也可以利用先序线索化的唯一NULL(G->rchild)作为循环出口
2:这里需要注意如果使用先序线索化就要用先序线索化遍历
对应代码
//先序遍历--必须要先序线索化
Status PreOrderTraverse(BiThrTree HeadNode, Status(*visit)(TElemType e))
{
BiThrTree p = HeadNode->lchild; //虚设头结点指向根节点
while (p != HeadNode) //转一圈回来结束
{
while (p->lchild != NULL && p->LTag == Link) //先序一直向左走
{
visit(p->data); //1:访问根节点
p = p->lchild; //向左走
}
visit(p->data); //2:访问最左边节点
if(p->LTag == Thread) //3:遍历右子树(如果有子树,则返回215行,往左走)
p = p->rchild;
}
return OK;
}
先序线索化及遍历输出结果
二:中序线索化及遍历
1:中序线索化
递归与先序访问顺序
对应代码
//中序线索化
void InThreading(BiThrTree p)
{
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); //右子树线索化
}
}
2:先序线索化添加虚设头结点(建立双向循环链表)
作用:规范,方便,忠实数据结构书上的的做法(转一圈就结束),如果你觉得麻烦,不加也可以,但必须了解其遍历的前因后果,以便知道遍历结束的循环出口。
对应代码
//中序线索化二叉树(添加头结点)--双向链表
Status InOrderThreading(BiThrTree &Thrt, BiThrTree T)
{
if(!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode)))) //虚设根节点
return OVERFLOW;
Thrt->LTag = Link; Thrt->RTag = Thread; //左指针指向头结点
Thrt->rchild = Thrt; //右指针回指
if(!T)
Thrt->lchild = Thrt; //二叉树为空,左指针回指
else
{
Thrt->lchild = T; pre = Thrt; //虚设根节点指向头节点
InThreading(T);
pre->rchild = Thrt; pre->RTag = Thread; //处理最后一个节点指向虚设头结点
Thrt->rchild = pre;
}
return OK;
}
3:中序线索化遍历
中序线索化遍历前驱与后继图
核心思想:递归与访问顺序
1:如果你不添加虚设的头结点,也可以利用先序线索化的NULL(G->rchild)作为循环出口
2:这里需要注意如果使用中序线索化就要用中序线索化遍历
对应代码
//中序遍历--必须要中序线索化
Status InOrderTraverse(BiThrTree HeadNode, Status(*visit)(TElemType e))
{
BiThrTree p = HeadNode->lchild; // 虚设头结点指向根节点
while (p != HeadNode) { //转一圈回来结束
while (p->LTag == Link) { //一直往左走
p = p->lchild;
}
visit(p->data); //1:访问最左边节点
while (p->RTag == Thread && p->rchild != HeadNode) { //右子树为线索,且不为头结点
p = p->rchild; //2:访问分支节点
visit(p->data);
}
p = p->rchild; //回到分支节点,又开始232行,一个新子树
}
return OK;
}
中序线索化及遍历输出结果
后序线索化及遍历(我的下篇文章):
https://blog.csdn.net/weixin_39956356/article/details/80144113
二叉树的(先,中,后)序的建树
https://blog.csdn.net/weixin_39956356/article/details/80141837
线索二叉树的基本知识:
https://blog.csdn.net/weixin_39956356/article/details/80141980