[基本算法] morris(空间复杂度为O(1)的二叉树遍历算法)
morris算法空间复杂度为O(1),时间复杂度为O(N)
核心思想是使用节点的左子树最右叶节点的右指针指向节点。其特点在于:
每个节点的左子树最右节点都不同,不用担心冲突;
可以不保存原节点的指针,进行右移动时会自动回到子树的根节点;
通过判断最右节点是否指向当前节点可以知道是否已遍历过左子树;
其基本算法步骤如下:
当前节点为cur
1.若节点有左子树
寻找左子树最右根节点mostRight;
a.若mostRight->right指向null,则令其指向cur,cur左移;
b.若mostRight->right指向cur,说明左子树已遍历完毕,令其指向null,cur右移;
2.若节点无左子树
cur右移;
前序遍历
若节点左子树为空,立刻访问;
若mostRight右指针指向空(即首次到当前此节点cur),立刻访问;
1 void morrisPre(TreeNode *root){ 2 if(root==nullptr) 3 return ; 4 TreeNode *cur=root, *mostRight=nullptr; 5 6 while(cur!=nullptr){ 7 if(cur->left!=nullptr){ 8 //有左子树,寻找mostright节点 9 mostRight=cur->left; 10 //寻找左子树最右节点,注意避免回到当前节点 11 while(mostRight->right!=nullptr && mostRight->right!=cur) 12 mostRight=mostRight->right; 13 14 if(mostRight->right==nullptr){ 15 //若mostRight指向空,则令其指向cur,cur左移 16 cout<<cur->val<<endl; 17 mostRight->right=cur; 18 cur=cur->left; 19 } 20 else if(mostRight->right==cur){ 21 //若mostRight指向cur(说明左子树已经访问完毕),则令其指向空,cur右移动 22 mostRight->right=nullptr; 23 cur=cur->right; 24 } 25 } 26 else{ 27 //无左子树,让cur向右移动 28 cout<<cur->val<<endl; 29 cur=cur->right; 30 } 31 } 32 }
中序遍历
若节点左子树为空,立即访问;
若mostRight右指针指向节点本身(当前节点cur左子树已被访问),立即访问;
void morrisMid(TreeNode *root){ if(root==nullptr) return ; TreeNode *cur=root, *mostRight=nullptr; while(cur!=nullptr){ if(cur->left!=nullptr){ //有左子树,寻找mostright节点 mostRight=cur->left; //寻找左子树最右节点,注意避免回到当前节点 while(mostRight->right!=nullptr && mostRight->right!=cur) mostRight=mostRight->right; if(mostRight->right==nullptr){ //若mostRight指向空,则令其指向cur,cur左移 mostRight->right=cur; cur=cur->left; } else if(mostRight->right==cur){ //若mostRight指向cur(说明左子树已经访问完毕),则令其指向空,cur右移动 cout<<cur->val<<endl; mostRight->right=nullptr; cur=cur->right; } } else{ //无左子树,让cur向右移动 cout<<cur->val<<endl; cur=cur->right; } } }
后续遍历
仅在碰到mostRight右指针指向当前节点cur时,以倒序的方式遍历cur左子树的全部右节点;
最后调用一次printEdge(root)来完成最右侧所有节点的倒序遍历;
1 TreeNode* reverseEdge(TreeNode *node){ 2 TreeNode *pre=nullptr; 3 TreeNode *next=nullptr; 4 5 while(node!=nullptr){ 6 next = node->right; 7 node->right = pre; 8 pre = node; 9 node = next; 10 } 11 12 return pre; 13 } 14 15 void printEdge(TreeNode *root){ 16 TreeNode *tail = reverseEdge(root); 17 TreeNode *cur = tail; 18 while(cur!=nullptr){ 19 cout<<cur->val<<endl; 20 cur = cur->right; 21 } 22 reverseEdge(tail); 23 } 24 25 void morrisPost(TreeNode *root){ 26 if(root==nullptr) 27 return ; 28 TreeNode *cur=root, *mostRight=nullptr; 29 30 while(cur!=nullptr){ 31 if(cur->left!=nullptr){ 32 //有左子树,寻找mostright节点 33 mostRight=cur->left; 34 //寻找左子树最右节点,注意避免回到当前节点 35 while(mostRight->right!=nullptr && mostRight->right!=cur) 36 mostRight=mostRight->right; 37 38 if(mostRight->right==nullptr){ 39 //若mostRight指向空,则令其指向cur,cur左移 40 mostRight->right=cur; 41 cur=cur->left; 42 } 43 else if(mostRight->right==cur){ 44 //若mostRight指向cur(说明左子树已经访问完毕),则令其指向空,cur右移动 45 mostRight->right=nullptr; 46 printEdge(cur->left); 47 cur=cur->right; 48 } 49 50 } 51 else{ 52 //无左子树,让cur向右移动 53 cur=cur->right; 54 } 55 } 56 printEdge(root); 57 }
浙公网安备 33010602011771号