寻找线索二叉树的前驱后继,以及遍历线索二叉树
中序线索二叉树寻找前驱后继及遍历
定义线索二叉树:
typedef struct ThreadNode
{
int data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag;
} ThreadNode, *ThreadTree;
寻找中序序列的后继结点及正向遍历
中序遍历顺序是:根节点、左子树、右子树
如:根结点、左子树p、右子树——>
根节点、(左子树、根节点p、右子树)、右子树
所以寻找后继结点只需要判断rtag的值,rtag==0时,找左子树的最左边结点即可。
①若rtag = = 1,则后继=p->rchild
②若rtag = = 0,则后继=p右孩子中序遍历的第一个结点
也就是右子树最左边的那个结点。
//找到以p为根结点的子树中,第一个被中序遍历的结点
ThreadNode *Firstnode(ThreadNode *p)
{
while (p->ltag == 0)
{
//循环找到最左下角的结点,不一定是叶节点,只是没有左孩子
p = p->lchild;
}
return p;
}
//在中序线索二叉树中,找到p的后继结点,因为中序遍历是左子树、根结点、右子树
//所以只需要判断rtag的值,若为1,则直接返回右孩子,不为1,则寻找右子树的第一个被中序遍历的点
ThreadNode *NextNode(ThreadNode *p)
{
if (p->rtag == 1)
{
return p->rchild;
}
else
{
return Firstnode(p->rchild);
}
}
void visit(ThreadNode *p)
{
//自定义操作
}
//找到后继结点之后,就可以方便的开始对中序序列进行遍历了
void Inorder(ThreadNode *T)
{
for (ThreadNode *p = Firstnode(T); p != nullptr; p = NextNode(p))
{
visit(p); //visit()访问函数
}
}
寻找中序遍历的前驱结点及逆向遍历
①若ltag = = 1,则前驱=p->lchild
②若ltag = = 0,则前驱=p左孩子中序遍历的最后一个结点
也就是左子树最右边那个结点
ThreadNode *Fright_Node(ThreadNode *p)
{
while (p->rtag == 0)
{
p = p->rchild;
}
return p;
}
ThreadNode *PreNode(ThreadNode *p)
{
if (p->ltag==0)
{
return Fright_Node(p->lchild);
}
else return p->lchild;
}
//对中序线索二叉树进行逆向的中序遍历
void RevInorder(ThreadNode *T)
{
for(ThreadNode *p=Fright_Node(T);p!=nullptr;p=PreNode(p))
{
visit(p);
}
}
先序线索二叉树寻找后继结点及前驱结点
寻找先序序列的后继结点
先序遍历依次为:根结点、左子树p、右子树——>
根结点、(根结点p、左子树、右子树)、右子树
所以寻找先序序列的后继结点,只需要看根结点的左右孩子便可。
①若rtag = = 1,则后继=p->rchild
②若rtag = = 0,则后继=p左孩子先序遍历的第一个结点
ThreadNode *Pre_NextNode(ThreadNode *p)
{
//判断结点rtag的值,若==1,则存在后继,
//(包含左右孩子不存在的情况,p->lchild==NULL)
if (p->rtag==1)
{
return p->lchild;
}
//若结点有左孩子,则返回左孩子根结点
//p->rtag==0&&p->lchild
else if(p->lchild)
{
return p->lchild;
}
//若结点没有左孩子,有右孩子,则返回右孩子根节点
//(p->rtag==0&&p->lchild==nullptr&&p->rchild)
else
{
return p->rchild;
}
}
寻找先序序列的前驱结点
①若ltag = = 1,则前驱=p->lchild
②若ltag = = 0,则结点p遍历顺序为:根p、左、右
可以看出,是没有办法用p表示他的前驱结点的,所以必须从头开始遍历,寻找他的前驱结点,具体做法见另一篇文章:https://blog.csdn.net/qq_41185288/article/details/107183176
除非设置三叉链表,多一个指针指向它的父节点。
如果存在一个指针指向它的父节点:
一、p是左孩子
先序遍历序列:根、左、右——>根、(根p、左、右)、右
故p的前驱即为其父节点
二、p是右孩子且左孩子不存在
先序遍历序列:根、右——>根、(根p、左、右)
p的父结点即为其前驱结点
三、p是右孩子,且左孩子存在
先序遍历序列:根、左、右——>
根、(根、左、右)、(根p、左、右)
故p的前驱结点即为父节点的左孩子的最后一个访问的结点。
较复杂的访问情况:
按根、左、右依次访问下去,找到最后一个结点即可。
后序线索二叉树寻找后继结点及前驱结点
寻找后序序列的后继结点
后序遍历次序为:左、右、根
①若rtag = = 1,则后继=p->rchild
②若rtag = = 0,则结点p一定有右孩子:左、右、根p
可以看出,p的左右孩子都不是p的后继,所以只能从头开始暴力遍历寻找根p的后继。
也可以设置三叉链表,多一个指针指向父节点
如果存在一个指针指向父节点,则:
一、p是右孩子
后序遍历序列:左、右p、根——>左、(左、右、根p)、根
结点p的后继结点即为p的父节点
二、p是左孩子且父节点没有右孩子
后序遍历序列:左p、根——>(左、右、根p)、根
结点p的后继结点即为p的父节点
三、p是左孩子且父节点有右孩子
后序遍历序列:左p、右、根——>(左、右、根p)、右、根
结点p的后继即为右兄弟子树后序遍历访问的第一个结点
四、p是根结点
后序遍历序列:左、右、根p
可以看出p没有后继结点
寻找后序序列的前驱结点
后序遍历次序为:左、右p、根——>
左、(左、右、根p)、根
①若ltag = = 1,则前驱=p->lchild
②若ltag = = 0,则前驱=p的右孩子或者左孩子(当右孩子不存在时)