当前位置:网站首页>二叉树神级遍历:Morris遍历
二叉树神级遍历:Morris遍历
2022-07-01 03:14:00 【苡荏】
二叉树的Morris遍历
1. 创建二叉树
typedef struct BiTNode{
int data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
//前序创建二叉树
void createBiTree(BiTree *T){
int value;
cin>>value;
if (value == 0)
*T = NULL;
else{
*T = (BiTree)malloc(sizeof(BiTNode));
if(!*T)
exit(OVERFLOW);
(*T)->data = value;
createBiTree(&(*T)->lchild);
createBiTree(&(*T)->rchild);
}
}
1 2 4 0 0 5 0 0 3 6 0 0 7 0 0 构建二叉树

2. 常规遍历
//前序遍历
void PreOrderTraverse(BiTree T){
if(T==NULL)
return;
cout<<T->data<<" ";
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
//中序遍历
void InOrderTraverse(BiTree T){
if(T==NULL)
return;
InOrderTraverse(T->lchild);
cout<<T->data<<" ";
InOrderTraverse(T->rchild);
}
//后序遍历
void PostOrderTraverse(BiTree T){
if(T==NULL)
return;
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
cout<<T->data<<" ";
}
//测试
int main(){
BiTree T;
createBiTree(&T);
PreOrderTraverse(T); // 1 2 4 5 3 6 7
cout<<endl;
InOrderTraverse(T); // 4 2 5 1 6 3 7
cout<<endl;
PostOrderTraverse(T); // 4 5 2 6 7 3 1
return 0;
}
3. Morris遍历
- 获得Morris序的执行过程:
- 记当前节点为current(初始current = head),如果current没有左子树(current.left = null),则current向右移动(current = current.right),
- 当current有左子树(current.left != null),找到current左子树最右侧的节点(记为mostRight),
- 如果mostRight.right = null,则将mostRight的right指针指向current,即mostRight.right = current,此时current向左移动,
- 如果mostRight.right = current,则将mostRight的right指针置为null,即mostRight.right = null,此时current向右移动,
- current = null时,运行终止。
- 每次记录下current的节点最终得到Morris序。
举例演示:











//获取Morris序列
void morris(BiTree T){
if(T==NULL)
return;
BiTree cur = T; // 初始化cur=T头节点
BiTree mostRight = NULL; // 初始化mostRight=NULL
while(cur != NULL){
mostRight = cur->lchild; //mostRight=cur的左孩子
cout<<cur->data<<" "; // 打印Morris序列
if(mostRight!=NULL){
while(mostRight->rchild!=NULL && mostRight->rchild!=cur){
mostRight = mostRight->rchild; // 将mostRight移动到cur左孩子的最右节点处
}
if(mostRight->rchild == NULL){
// mostRight的右节点为NULL
mostRight->rchild = cur; // 指向cur
cur = cur->lchild; // cur左移 下接continue直接下一次循环
continue;
} else {
mostRight->rchild = NULL; // 否则mostRight置NULL
}
}
cur = cur->rchild; // 在没有左子树或执行mostRight->rchild=NULL后执行
}
}
Morris序的特点:
1. 节点无左子树,则在Morris序中只出现一次,
2. 节点有左子树,则在Morris序中出现两次。下面,根据得到的Morris序做先序、中序、后序遍历:
1. 先序遍历:在Morris序中第一次出现时进行打印,第二次不打印,
2. 中序遍历:在Morris序中出现一次的立刻打印,出现二次的在第二次时打印,
3. 后序遍历:在Morris序中出现两次的节点且出现在第二次时进行处理:逆序打印该节点的左子树的右边界,最后逆序单独打印二叉树的右边界。
//Morris先序遍历:
void morrisPre(BiTree T){
if(T==NULL)
return;
BiTree cur = T;
BiTree mostRight = NULL;
while(cur != NULL){
mostRight = cur->lchild;
if(mostRight!=NULL){
// 左子树不为NULL,必然Morris序列中存在两次节点
while(mostRight->rchild!=NULL && mostRight->rchild!=cur){
mostRight = mostRight->rchild;
}
if(mostRight->rchild == NULL){
// Morris序列中两次节点第一次出现的情况进行data打印
cout<<cur->data<<" ";
mostRight->rchild = cur;
cur = cur->lchild;
continue;
} else {
mostRight->rchild = NULL;
}
} else{
// Morris序列中只能有一次的情况进行data打印
cout<<cur->data<<" ";
}
cur = cur->rchild;
}
}
//Morris中序遍历:
void morrisIn(BiTree T){
if(T==NULL)
return;
BiTree cur = T;
BiTree mostRight = NULL;
while(cur != NULL){
mostRight = cur->lchild;
if(mostRight!=NULL){
// 左子树不为NULL,必然Morris序列中存在两次节点
while(mostRight->rchild!=NULL && mostRight->rchild!=cur){
mostRight = mostRight->rchild;
}
if(mostRight->rchild == NULL){
// Morris序列中两次节点第一次出现
mostRight->rchild = cur;
cur = cur->lchild;
continue;
} else {
// 第二次
mostRight->rchild = NULL;
}
}
cout<<cur->data<<" "; // 打印中序序列节点
cur = cur->rchild;
}
}
//Morris后序遍历:
- Morris序:1 2 4 2 5 1 3 6 3 7
- 在第二次出现2的时候逆序打印2的左子树的右边界为4,
- 在第二次出现1的时候逆序打印1的左子树的右边界为5,2,
- 在第二次出现2的时候逆序打印3的左子树的右边界为6,
- 最后逆序打印该二叉树的右边界为7,3,1。
- 得到后序遍历结果为:4,5,2,6,7,3,1。
为保证空间复杂度为O(1),在逆序打印右边界的时候,必须对边界节点右指针的指向进行调整。
// 从now开始,只考虑右指针,将其作为单链表的next,将这个单链表逆序,返回最后一个节点
BiTree reverseEdge(BiTree T){
BiTree pre = NULL;
BiTree next = NULL;
while(T!=NULL){
next = T->rchild;
T->rchild = pre;
pre = T;
T = next;
}
return pre;
}
// 以T节点为首的树,逆序打印树的右边界
void printEdge(BiTree T){
BiTree tail = reverseEdge(T);
BiTree cur = tail;
while(cur!=NULL){
cout<<cur->data<<" ";
cur = cur->rchild;
}
reverseEdge(tail);
}
//后序序列
void morrisPost(BiTree T){
if(T==NULL)
return;
BiTree cur = T;
BiTree mostRight = NULL;
while(cur != NULL){
mostRight = cur->lchild;
if(mostRight!=NULL){
// 左子树不为NULL,必然Morris序列中存在两次节点
while(mostRight->rchild!=NULL && mostRight->rchild!=cur){
mostRight = mostRight->rchild;
}
if(mostRight->rchild == NULL){
// Morris序列中两次节点第一次出现
mostRight->rchild = cur;
cur = cur->lchild;
continue;
} else {
// 出现两次且第二次出现时
mostRight->rchild = NULL;
printEdge(cur->lchild); // 进行处理
}
}
cur = cur->rchild;
}
// 结束后,逆序打印该二叉树的右边界
printEdge(T);
}
4. 时空复杂度
时间复杂度:O(n)
空间复杂度:O(1)
——————END-2022-06-26——————
边栏推荐
猜你喜欢

# 使用 KubeKey 搭建 Kubernetes/KubeSphere 环境的'心路(累)历程'

完全背包问题

【EXSI】主机间传输文件
![[QT] add knowledge supplement of third-party database](/img/ea/ca8b07ad80485208f2bb8ee8a78a28.png)
[QT] add knowledge supplement of third-party database

Edge Drawing: A combined real-time edge and segment detector 翻译

限流组件设计实战

Huawei operator level router configuration example | configuration static VPLS example

Huawei operator level router configuration example | BGP VPLS configuration example

Cloud native annual technology inventory is released! Ride the wind and waves at the right time
![Install vcenter6.7 [vcsa6.7 (vCenter server appliance 6.7)]](/img/83/e3c9d8eda9d5351d4c54928d3b090b.png)
Install vcenter6.7 [vcsa6.7 (vCenter server appliance 6.7)]
随机推荐
Finally in promise
【日常训练】1175. 质数排列
Edge Drawing: A combined real-time edge and segment detector 翻译
Huawei operator level router configuration example | configuration optionA mode cross domain LDP VPLS example
终极套娃 2.0 | 云原生交付的封装
Promise中finally的用法
第03章_用戶與權限管理
Basic concept and classification of sorting
# 使用 KubeKey 搭建 Kubernetes/KubeSphere 环境的'心路(累)历程'
A few lines of transaction codes cost me 160000 yuan
Huawei operator level router configuration example | BGP VPLS and LDP VPLS interworking example
Mybati SQL statement printing
Summary of problems encountered in debugging positioning and navigation
Overview of EtherCAT principle
Mysql知识点
XXL job User Guide
Feign remote call and getaway gateway
The value of the second servo encoder is linked to the NC virtual axis of Beifu PLC for display
Feign远程调用和Getaway网关
VMware vSphere 6.7虚拟化云管理之12、VCSA6.7更新vCenter Server许可