Morris神级遍历二叉树,时间复杂度为O(1)
来源:互联网 发布:mac迅雷下载 编辑:程序博客网 时间:2024/05/21 01:31
Morris算法介绍
Morris算法在遍历的时候避免使用了栈结构,而是让下层到上层有指针,具体是通过底层节点指向NULL的空闲指针返回上层的某个节点,从而完成下层到上层的移动。我们知道二叉树有很多空闲的指针,比如某个人节点没有右孩子,我们称这种情况为空闲状态,Morris算法的遍历就是利用了这些 空闲的指针!
Morris算法算法的规则:
当我拿到一个节点(node)的时候看它有没有左子树,没有的话向右指针方向移动
有的话找到左子树的最右节点,如果这个最右节点的右指针为空则让它指向node,然后node向左指针移动
,如果这个最右节点已经指向node,则让它指向空则让node向右指针移动
我们就拿一个普通的二叉树来说吧:
描述:我们从根节点开始,node节点就为1,1有左子树,找到1左子树的最右节点为5,5的右指针为空,让5的右指针指向node即1,然后node向左指针移动,变为2,2也有左子树,左子树的最右节点为4,4的右指针为空则指向2,node向左移动变为4,node为4没有左子树,所以node向右指针方向移动回到2(这是第二次来到2),2有左子树,并且它左子树的最右节点已经指向了node(即2),则让这个最右节点指向NULL,node向右指针移动来到5,5没有左子树,向右指针移动来到1,1有左子树,切左子树的最右节点指向了node(即自己),让最右节点指向NULL,node向右指针移动来到3,3有子树,左子树的最右节点右指针为空所以让他指向node(即3),node向左指针移动来到7,7没有左子树,向右指针移动回到3(第二次来到3),3有左子树切左子树的最右节点指向自己,则让左子树的最右节点指向NULL,node往右指针走,来到8,此树遍历完毕。
我们可以看到节点2,1,3在node走的过程中会两次来到它,而其他节点node只会来到一次!
归纳为:如果一个节点有左子树node就会访问它两次,如果没有左子树,node只会访问它一次。
这样我们就可以开始做前、中序遍历了:
前序遍历:
一个节点没有左子树直接打印当前节点
如果有的话(第一次来到此节点的时候就去打印),即再往左子树节点走之前打印
code
struct Node{ int value; Node* left; Node* right; Node(int data) { value = data; }};//Morris前序遍历void MorrisPre(Node* root){ if(root == NULL) return; Node* cur1 = root; Node* cur2 = NULL; while(cur1 != NULL) { cur2 = cur1->left; if(cur2!=NULL) { while(cur2->right!=NULL && cur2->right!=cur1) { cur = cur->right; } if(cur2->right == NULL) { cur2->right = cur1; cout<<cur1->value<<" ";//在node走向左子树之前打印 cur1 = cur1->left; continue; }else{ cur2->right = NULL;//如果cur2->right指向node,则置空 } }else{//cur2为空,直接打印当前节点 cur1往右指针走 cout<<cur1->value<<" "; } cur1 = cur->right; } cout<<endl;}
中序遍历
在没有左子树的时候直接往右子树走之前打印
有左子树先去遍历左子树然后回来当前节点打印,之后再去右子树(都是往右指针走之前打印他)
code
//morris中序遍历void MorrisIn(Node* root){ if(root == NULL) return; Node* cur1 = root; Node* cur2 = NULL; while(cur1 !=NULL) { cur2 = cur1->left; if(cur2!=NULL) { while(cur2->right!=NULL && cur2->right!=cur1) { cur2 = cur2->right; } if(cur2->right == NULL) { cur2->right = cur1; cur1 = cur1->left; continue; }else{ cur2->right = NULL; } } cout<<cur1->value<<" "; cur1 = cur1->right; } cout<<endl;}
后序遍历
后序遍历就有点麻烦了,我们仔细观察前面的前中序,node最多可以访问一个节点两次,前序是第一次访问就打印当前节点,中序是第二次访问打印当前节点,那么后序需要第三次访问的时候打印当前节点,但是一个节点最多被访问两次,那怎么办呢?
下来我们引入一个方法:
图中红线画出来的称为这棵二叉树的所有右边界,所有的右边界节点加起来就是二叉树的节点个数N,每个节点最多可能被遍历2次,遍历整体二叉树的代价就是2N
后序的方法就是:
第二次来到到此节点,逆序打印它的右边界就是后序,整个走完之后(遍历到二叉树最右节点)后单独逆序打印整棵树的右边界。
那怎么逆序打印呢?类似于单链表的逆置,更改右节点的指针指向即可,在打印完在更改回去,(如1->right = 3,3->right = 8,可以设置为 8->prev = 3,3->pre = 1)
code
/morris后序遍历void PrintEdge(Node* from);void MorrisPos(Node* root){ if(root == NULL) { return; } Node* cur1 = root; NOde* cur2 = NULL; while(cur1 != NULL) { cur2 = cur1->left; if(cur2 != NULL) { while(cur2->right != NULL && cur2->right != cur1) { cur2 = cur2->right; } if(cur2->right == NULL) { cur2->right = cur1; cur1 = cur1->left; continue; }else{ cur2->right = NULL; PrintEdge(cur->left); } } cur1 = cur1->right; } PrintEdge(root); cout<<endl;}void ReverseEdge(Node* from);void PrintEdge(Node* root){ Node* tail = ReverseEdge(root); Node* cur = tail; while(cur != NULL) { cout<<cur->value<<" "; cur = cur->right; } ReverseEdge(tail);}Node ReverseEdge(Node* from){ Node* pre = NULL; Node* next = NULL; while(from != NULL) { next = from->right; from->right = pre; pre = from; from = next; } return pre;}
- Morris神级遍历二叉树,时间复杂度为O(1)
- 二叉树遍历 Morris O(1)空间复杂度
- 二叉树面试算法:空间复杂度为 O(1)的Morris遍历法
- 【算法】二叉树的非递归遍历的简洁写法/迭代器实现/O(1)空间复杂度的Morris遍历
- morris 树的中序遍历(O(1)空间 O(n)时间)
- 遍历二叉树的神级方法(Morris)
- Morris Traversal 方法遍历二叉树(非递归、不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- Morris Traversal方法遍历二叉树(非递归,不用栈,O(1)空间)
- JAVA线程浅见
- Android 实现拍照,选择图片并剪切保存
- kylin count distinct需要注意的东西
- 字符流转字节流的方法。
- a标签中执行js函数的几种方法
- Morris神级遍历二叉树,时间复杂度为O(1)
- 使用神经网络和遗传算法玩转 Flappy Bird
- QTcpSocket 发送数据心得
- VMware Tools (ubuntu系统)安装详细过程与使用
- Java解析(读取)Json数据
- unity读取Json文件
- AAPT err(Facade for 1742568639) : No Delegate set : lost message:\\?\C:\Users\陈健\.android\build-cach
- MongoDB管理:慎用local、admin数据库
- Linux下搭建MySQL集群 / Mysql“集群”和”主从“两者的区别