当前位置:网站首页>二叉树神级遍历: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——————
边栏推荐
- Cookie&Session
- [applet project development -- Jingdong Mall] classified navigation area of uni app
- 8 pits of redis distributed lock
- leetcode 1818 绝对值,排序,二分法,最大值
- Chapitre 03 Bar _ Gestion des utilisateurs et des droits
- POI导出excel,按照父子节点进行分级显示
- How the network is connected: Chapter 2 (Part 2) packet receiving and sending operations between IP and Ethernet
- [applet project development -- Jingdong Mall] user defined search component of uni app (Part 1)
- 多元线性回归
- Feign远程调用和Getaway网关
猜你喜欢

雪崩问题以及sentinel的使用

Nacos

Let's just say I can use thousands of expression packs

Redis高效点赞与取消功能

最新接口自动化面试题
![Install vcenter6.7 [vcsa6.7 (vCenter server appliance 6.7)]](/img/83/e3c9d8eda9d5351d4c54928d3b090b.png)
Install vcenter6.7 [vcsa6.7 (vCenter server appliance 6.7)]

完全背包问题
![[applet project development -- Jingdong Mall] user defined search component of uni app (Part 1)](/img/73/a22ab1dbb46e743ffd5f78b40e66a2.png)
[applet project development -- Jingdong Mall] user defined search component of uni app (Part 1)

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

Data exchange JSON
随机推荐
VMware vSphere 6.7 virtualization cloud management 12. Vcsa6.7 update vCenter server license
Redis 教程
Pytest -- plug-in writing
10、Scanner.next() 无法读取空格/indexOf -1
Golang多图生成gif
Leetcode 1482 guess, how about this question?
multiple linear regression
手把手带你了解一块电路板,从设计到制作(干货)
ES6解构语法详解
Redis分布式锁的8大坑
Basic concepts of database
数组的includes( )
Cookie&Session
VMware vSphere 6.7虚拟化云管理之12、VCSA6.7更新vCenter Server许可
完全背包问题
Redis efficient like and cancel function
[small program project development -- Jingdong Mall] the home page commodity floor of uni app
伺服第二编码器数值链接到倍福PLC的NC虚拟轴做显示
第03章_用戶與權限管理
Introduction to ieda right click source file menu