目录
在中序线索二叉树里找指定节点在后序的前驱节点
/**
* 用二叉树链式存储实现 王道 P150 T18
* ①算法思想
* ①在中序线索二叉树里找指定节点在后序的前驱节点
* ②在中序线索二叉树里找指定节点在先序的后继
* 关于①:
* 如果p有右孩子,那么p的右孩子就是p的前驱。
* 如果p没有右孩子,但是有左孩子,那么p的左孩子就是p的前驱。
* 但如果p是叶子节点:
* 如果p是一个偏左行为的节点(想象成左下角的一个),那么它一定是第一个遍历的,他就不会有前驱。
* 如果p是一个偏右行为的节点(想象成右下角的一个),那么它有可能有前驱,也有可能没有,得在这个节点的左边找一找。
* 关于②:
* 如果p有左孩子,那么p的左孩子就是p的后继。
* 如果p没有左孩子,但是有右孩子,那么p的右孩子就是p的后继。
* 但如果p是叶子节点:
* 如果p是一个偏右行为的节点(想象成右下角的一个),那么它一定是最后一个遍历的,他就不会有后继。
* 如果p是一个偏左行为的节点(想象成左下角的一个),那么它有可能有后继,也有可能没有,得在这个节点的右边找一找。
*
*
* ②算法设计
*/
#include <stdio.h>
#include <iostream>
#define MaxSize 100
typedef struct ThreadBiTreeNode{
int data;
struct ThreadBiTreeNode *lchild,*rchild,*parent;//parent域指向双亲结点
int ltag,rtag;
int weight;//如果给叶子节点赋权值的话会用到
}ThreadBiTreeNode,*ThreadBiTree;
//P150 T18
//①在中序线索二叉树里找指定节点在后序的前驱节点
ThreadBiTree InFindNodePostPre(ThreadBiTree p){
if(p -> rtag == 0){//说明p一定有右孩子,那么p的前驱就是右孩子
return p -> rchild;
}else if(p -> ltag == 0){//如果p没有右孩子,但是有左孩子,那么p的前驱就是p的左孩子
return p -> lchild;
}else{//如果p是叶子节点:((注意为什么后序找前驱不用考虑这个情况?
//因为不需要考虑到,要是在后序中p是叶子结点的话就可以直接return p -> ltag了。
//这也正是在先序中找某个节点在后序中的前驱的麻烦之处。))
//①如果p是一个偏左行为的节点(想象成左下角的一个),那么它一定是第一个遍历的,他就不会有前驱。
if(p -> lchild == NULL)//p现在是叶子节点,所以p -> lchild == NULL 相当于p在中序序列中没有前驱,那么p在后序序列中也没有前驱
return NULL;
//②如果p是一个偏右行为的节点(想象成右下角的一个或者是右子树中的一个),那么它有可能有前驱,也有可能没有,得在这个节点的左边找一找。
while(p -> lchild != NULL && p -> ltag == 1){//一直向上找直到找到一个点有左孩子
//因为p是叶子节点,所以p -> lchild就是它在~中序~中的前驱,
//这是一个一直向上找的过程,如果向上找的时候遇到某个节点他有左孩子,那么这个左孩子就是p在后序中的前驱
p = p -> lchild;//一直在向上找
}
if(p -> ltag == 0)//说明是因为p->ltag!=1结束循环的,说明向上找到了一个节点,这个节点有左孩子,那么这个左孩子就是p的前驱。
return p -> lchild;
else//说明是因为p -> lchild == NULL 结束while的,那么这就是一个单支树,p就不会有前驱。
return NULL;
}
}
在中序线索二叉树里找指定节点在先序的后继节点
/**
* 用二叉树链式存储实现 王道 P150 T18
* ①算法思想
* ①在中序线索二叉树里找指定节点在后序的前驱节点
* ②在中序线索二叉树里找指定节点在先序的后继
* 关于①:
* 如果p有右孩子,那么p的右孩子就是p的前驱。
* 如果p没有右孩子,但是有左孩子,那么p的左孩子就是p的前驱。
* 但如果p是叶子节点:
* 如果p是一个偏左行为的节点(想象成左下角的一个),那么它一定是第一个遍历的,他就不会有前驱。
* 如果p是一个偏右行为的节点(想象成右下角的一个),那么它有可能有前驱,也有可能没有,得在这个节点的左边找一找。
* 关于②:
* 如果p有左孩子,那么p的左孩子就是p的后继。
* 如果p没有左孩子,但是有右孩子,那么p的右孩子就是p的后继。
* 但如果p是叶子节点:
* 如果p是一个偏右行为的节点(想象成右下角的一个),那么它一定是最后一个遍历的,他就不会有后继。
* 如果p是一个偏左行为的节点(想象成左下角的一个),那么它有可能有后继,也有可能没有,得在这个节点的右边找一找。
*
*
* ②算法设计
*/
#include <stdio.h>
#include <iostream>
#define MaxSize 100
typedef struct ThreadBiTreeNode{
int data;
struct ThreadBiTreeNode *lchild,*rchild,*parent;//parent域指向双亲结点
int ltag,rtag;
int weight;//如果给叶子节点赋权值的话会用到
}ThreadBiTreeNode,*ThreadBiTree;
//②在中序线索二叉树里找指定节点在先序的后继
ThreadBiTree InFindNodePrePost(ThreadBiTree p){
if(p -> ltag == 0){//说明p一定有左孩子,那么p的后继就是右孩子
return p -> lchild;
}else if(p -> rtag == 0){//如果p没有左孩子,但是有右孩子,那么p的后继就是p的右孩子
return p -> rchild;
}else{//如果p是叶子节点:
//①如果p是一个偏右行为的节点(想象成右下角的一个),那么它一定是最后一个遍历的,他就不会有后继。
if(p -> rchild == NULL)//p现在是叶子节点,所以p -> rchild == NULL 相当于p在中序序列中没有后继,那么p在先序序列中也没有后继
return NULL;
//②如果p是一个偏左行为的节点(想象成左下角的一个或者是左子树中的一个),那么它有可能有后继,也有可能没有,得在这个节点的右边找一找。
while(p -> rchild != NULL && p -> rtag == 1){//一直向上找直到找到一个点有右孩子
//因为p是叶子节点,所以p -> rchild就是它在~中序~中的后继,
//这是一个一直向上找的过程,如果向上找的时候遇到某个节点他有右孩子,那么这个右孩子就是p在先序中的后继
p = p -> rchild;//一直在向上找
}
if(p -> ltag == 0)//说明是因为p->ltag!=1结束循环的,说明向上找到了一个节点,这个节点有右孩子,那么这个右孩子就是p的后继。
return p -> rchild;
else//说明是因为p -> rchild == NULL 结束while的,那么这就是一个单支树,p就不会有后继。
return NULL;
}
}