先决条件:-莫里斯有序遍历,树遍历(有序,前序和后序)
给定二叉树,任务是使用O(N)时间复杂度和恒定空间按后顺序打印元素。
Input: 1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
Output: 8 9 4 5 2 6 7 3 1
Input: 5
/ \
7 3
/ \ / \
4 11 13 9
/ \
8 4
Output: 8 4 4 11 7 13 9 3 5
方法1:使用Morris有序遍历
- 创建一个虚拟节点,并将其根作为左子节点。
- 用虚拟节点初始化电流。
- 当当前不为NULL时
- 如果当前没有左孩子遍历右孩子,则current = current-> right
- 除此以外,
- 在左侧子树中找到最右侧的子级。
- 如果最右边孩子的右边孩子为NULL
- 将current作为最右边节点的右边子节点。
- 遍历左孩子,当前=当前->左
- 除此以外,
- 将最右边的孩子的右边的指针设置为NULL。
- 从当前对象的左子元素开始,与右子元素一起遍历直到最右子元素,然后反转指针。
- 通过反转指针并打印元素,从最右边的子节点向后移动到当前节点的左子节点。
- 遍历右边的孩子,当前=当前->右边
下图显示了左子树中最右边的子节点,指向其有序后继节点。
下图突出显示了路径1-> 2-> 5-> 9以及根据上述算法处理和打印节点的方式。
下面是上述方法的实现:
C++
// C++ program to implement
// Post Order traversal
// of Binary Tree in O(N)
// time and O(1) space
#include
using namespace std;
class node
{
public:
int data;
node *left, *right;
};
// Helper function that allocates a
// new node with the given data and
// NULL left and right pointers.
node* newNode(int data)
{
node* temp = new node();
temp->data = data;
temp->left = temp->right = NULL;
return temp;
}
// Postorder traversal without recursion
// and without stack
void postOrderConstSpace(node* root)
{
if (root == NULL)
return;
node* current = newNode(-1);
node* pre = NULL;
node* prev = NULL;
node* succ = NULL;
node* temp = NULL;
current->left = root;
while (current)
{
// If left child is null.
// Move to right child.
if (current->left == NULL)
{
current = current->right;
}
else
{
pre = current->left;
// Inorder predecessor
while (pre->right &&
pre->right != current)
pre = pre->right;
// The connection between current and
// predecessor is made
if (pre->right == NULL)
{
// Make current as the right
// child of the right most node
pre->right = current;
// Traverse the left child
current = current->left;
}
else
{
pre->right = NULL;
succ = current;
current = current->left;
prev = NULL;
// Traverse along the right
// subtree to the
// right-most child
while (current != NULL)
{
temp = current->right;
current->right = prev;
prev = current;
current = temp;
}
// Traverse back
// to current's left child
// node
while (prev != NULL)
{
cout << prev->data << " ";
temp = prev->right;
prev->right = current;
current = prev;
prev = temp;
}
current = succ;
current = current->right;
}
}
}
}
// Driver code
int main()
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
node* root = NULL;
root = newNode(1);
root->left = newNode(2);
root->right = newNode(3);
root->left->left = newNode(4);
root->left->right = newNode(5);
root->right->left = newNode(6);
root->right->right = newNode(7);
root->left->right->left = newNode(8);
root->left->right->right = newNode(9);
postOrderConstSpace(root);
return 0;
}
// This code is contributed by Saurav Chaudhary
Java
// Java program to implement
// Post Order traversal
// of Binary Tree in O(N)
// time and O(1) space
// Definition of the
// binary tree
class TreeNode {
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data)
{
this.data = data;
}
public String toString()
{
return data + " ";
}
}
public class PostOrder {
TreeNode root;
// Function to find Post Order
// Traversal Using Constant space
void postOrderConstantspace(TreeNode
root)
{
if (root == null)
return;
TreeNode current
= new TreeNode(-1),
pre = null;
TreeNode prev = null,
succ = null,
temp = null;
current.left = root;
while (current != null) {
// Go to the right child
// if current does not
// have a left child
if (current.left == null) {
current = current.right;
}
else {
// Traverse left child
pre = current.left;
// Find the right most child
// in the left subtree
while (pre.right != null
&& pre.right != current)
pre = pre.right;
if (pre.right == null) {
// Make current as the right
// child of the right most node
pre.right = current;
// Traverse the left child
current = current.left;
}
else {
pre.right = null;
succ = current;
current = current.left;
prev = null;
// Traverse along the right
// subtree to the
// right-most child
while (current != null) {
temp = current.right;
current.right = prev;
prev = current;
current = temp;
}
// Traverse back from
// right most child to
// current's left child node
while (prev != null) {
System.out.print(prev);
temp = prev.right;
prev.right = current;
current = prev;
prev = temp;
}
current = succ;
current = current.right;
}
}
}
}
// Driver Code
public static void main(String[] args)
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
PostOrder tree = new PostOrder();
tree.root = new TreeNode(1);
tree.root.left = new TreeNode(2);
tree.root.right = new TreeNode(3);
tree.root.left.left = new TreeNode(4);
tree.root.left.right
= new TreeNode(5);
tree.root.right.left
= new TreeNode(6);
tree.root.right.right
= new TreeNode(7);
tree.root.left.right.left
= new TreeNode(8);
tree.root.left.right.right
= new TreeNode(9);
tree.postOrderConstantspace(
tree.root);
}
}
Python3
# Python3 program to implement
# Post Order traversal
# of Binary Tree in O(N)
# time and O(1) space
class node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# Helper function that allocates a
# new node with the given data and
# None left and right pointers.
def newNode(data):
temp = node(data)
return temp
# Postorder traversal without recursion
# and without stack
def postOrderConstSpace(root):
if (root == None):
return
current = newNode(-1)
pre = None
prev = None
succ = None
temp = None
current.left = root
while (current):
# If left child is None.
# Move to right child.
if (current.left == None):
current = current.right
else:
pre = current.left
# Inorder predecessor
while (pre.right and
pre.right != current):
pre = pre.right
# The connection between current
# and predecessor is made
if (pre.right == None):
# Make current as the right
# child of the right most node
pre.right = current
# Traverse the left child
current = current.left
else:
pre.right = None
succ = current
current = current.left
prev = None
# Traverse along the right
# subtree to the
# right-most child
while (current != None):
temp = current.right
current.right = prev
prev = current
current = temp
# Traverse back
# to current's left child
# node
while (prev != None):
print(prev.data, end = ' ')
temp = prev.right
prev.right = current
current = prev
prev = temp
current = succ
current = current.right
# Driver code
if __name__=='__main__':
''' Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
'''
root = None
root = newNode(1)
root.left = newNode(2)
root.right = newNode(3)
root.left.left = newNode(4)
root.left.right = newNode(5)
root.right.left = newNode(6)
root.right.right = newNode(7)
root.left.right.left = newNode(8)
root.left.right.right = newNode(9)
postOrderConstSpace(root)
# This code is contributed by pratham76
C#
// C# program to implement
// Post Order traversal
// of Binary Tree in O(N)
// time and O(1) space
using System;
// Definition of the
// binary tree
public class TreeNode
{
public int data;
public TreeNode left, right;
public TreeNode(int item)
{
data = item;
left = right = null;
}
}
class PostOrder{
public TreeNode root;
// Function to find Post Order
// Traversal Using Constant space
void postOrderConstantspace(TreeNode root)
{
if (root == null)
return;
TreeNode current = new TreeNode(-1), pre = null;
TreeNode prev = null,
succ = null,
temp = null;
current.left = root;
while (current != null)
{
// Go to the right child
// if current does not
// have a left child
if (current.left == null)
{
current = current.right;
}
else
{
// Traverse left child
pre = current.left;
// Find the right most child
// in the left subtree
while (pre.right != null &&
pre.right != current)
pre = pre.right;
if (pre.right == null)
{
// Make current as the right
// child of the right most node
pre.right = current;
// Traverse the left child
current = current.left;
}
else
{
pre.right = null;
succ = current;
current = current.left;
prev = null;
// Traverse along the right
// subtree to the
// right-most child
while (current != null)
{
temp = current.right;
current.right = prev;
prev = current;
current = temp;
}
// Traverse back from
// right most child to
// current's left child node
while (prev != null)
{
Console.Write(prev.data + " ");
temp = prev.right;
prev.right = current;
current = prev;
prev = temp;
}
current = succ;
current = current.right;
}
}
}
}
// Driver code
static public void Main ()
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
PostOrder tree = new PostOrder();
tree.root = new TreeNode(1);
tree.root.left = new TreeNode(2);
tree.root.right = new TreeNode(3);
tree.root.left.left = new TreeNode(4);
tree.root.left.right = new TreeNode(5);
tree.root.right.left = new TreeNode(6);
tree.root.right.right = new TreeNode(7);
tree.root.left.right.left = new TreeNode(8);
tree.root.left.right.right = new TreeNode(9);
tree.postOrderConstantspace(tree.root);
}
}
// This code is contributed by offbeat
Java
// Java Program to implement
// the above approach
class TreeNode {
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data)
{
this.data = data;
}
public String toString()
{
return data + " ";
}
}
public class PostOrder {
TreeNode root;
// Function to Calculate Post
// Order Traversal
// Using Constant Space
void postOrderConstantspace(TreeNode root)
{
if (root == null)
return;
TreeNode current = null;
TreeNode prevNode = null;
TreeNode pre = null;
TreeNode ptr = null;
TreeNode netChild = null;
TreeNode prevPtr = null;
current = root;
while (current != null) {
if (current.left == null) {
current.left = prevNode;
// Set prevNode to current
prevNode = current;
current = current.right;
}
else {
pre = current.left;
// Find the right most child
// in the left subtree
while (pre.right != null
&& pre.right != current)
pre = pre.right;
if (pre.right == null) {
pre.right = current;
current = current.left;
}
else {
// Set the right most
// child's right pointer
// to NULL
pre.right = null;
System.out.print(pre);
ptr = pre;
netChild = pre;
prevPtr = pre;
while (ptr != null) {
if (ptr.right == netChild) {
System.out.print(ptr);
netChild = ptr;
prevPtr.left = null;
}
if (ptr == current.left)
break;
// Break the loop
// all the left subtree
// nodes of current
// processed
prevPtr = ptr;
ptr = ptr.left;
}
prevNode = current;
current = current.right;
}
}
}
System.out.print(prevNode);
// Last path traversal
// that includes the root.
ptr = prevNode;
netChild = prevNode;
prevPtr = prevNode;
while (ptr != null) {
if (ptr.right == netChild) {
System.out.print(ptr);
netChild = ptr;
prevPtr.left = null;
}
if (ptr == root)
break;
prevPtr = ptr;
ptr = ptr.left;
}
}
// Main Function
public static void main(String[] args)
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
PostOrder tree = new PostOrder();
tree.root = new TreeNode(1);
tree.root.left = new TreeNode(2);
tree.root.right = new TreeNode(3);
tree.root.left.left
= new TreeNode(4);
tree.root.left.right
= new TreeNode(5);
tree.root.right.left
= new TreeNode(6);
tree.root.right.right
= new TreeNode(7);
tree.root.left.right.left
= new TreeNode(8);
tree.root.left.right.right
= new TreeNode(9);
tree.postOrderConstantspace(
tree.root);
}
}
C#
// C# Program to implement
// the above approach
using System;
class TreeNode{
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data)
{
this.data = data;
}
public string toString()
{
return data + " ";
}
}
class PostOrder{
TreeNode root;
// Function to Calculate Post
// Order Traversal Using
// Constant Space
void postOrderConstantspace(TreeNode root)
{
if (root == null)
return;
TreeNode current = null;
TreeNode prevNode = null;
TreeNode pre = null;
TreeNode ptr = null;
TreeNode netChild = null;
TreeNode prevPtr = null;
current = root;
while (current != null)
{
if (current.left == null)
{
current.left = prevNode;
// Set prevNode to current
prevNode = current;
current = current.right;
}
else
{
pre = current.left;
// Find the right most child
// in the left subtree
while (pre.right != null &&
pre.right != current)
pre = pre.right;
if (pre.right == null)
{
pre.right = current;
current = current.left;
}
else
{
// Set the right most
// child's right pointer
// to NULL
pre.right = null;
Console.Write(pre.data + " ");
ptr = pre;
netChild = pre;
prevPtr = pre;
while (ptr != null)
{
if (ptr.right == netChild)
{
Console.Write(ptr.data + " ");
netChild = ptr;
prevPtr.left = null;
}
if (ptr == current.left)
break;
// Break the loop
// all the left subtree
// nodes of current
// processed
prevPtr = ptr;
ptr = ptr.left;
}
prevNode = current;
current = current.right;
}
}
}
Console.Write(prevNode.data + " ");
// Last path traversal
// that includes the root.
ptr = prevNode;
netChild = prevNode;
prevPtr = prevNode;
while (ptr != null)
{
if (ptr.right == netChild)
{
Console.Write(ptr.data + " ");
netChild = ptr;
prevPtr.left = null;
}
if (ptr == root)
break;
prevPtr = ptr;
ptr = ptr.left;
}
}
// Driver code
public static void Main(string[] args)
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
PostOrder tree = new PostOrder();
tree.root = new TreeNode(1);
tree.root.left = new TreeNode(2);
tree.root.right = new TreeNode(3);
tree.root.left.left = new TreeNode(4);
tree.root.left.right = new TreeNode(5);
tree.root.right.left = new TreeNode(6);
tree.root.right.right = new TreeNode(7);
tree.root.left.right.left = new TreeNode(8);
tree.root.left.right.right = new TreeNode(9);
tree.postOrderConstantspace(tree.root);
}
}
// This code is contributed by Rutvik_56
输出
4 8 9 5 2 6 7 3 1
时间复杂度: O(N)
辅助空间: O(1)
方法2:在方法1中,我们遍历路径,反向引用,打印节点,因为我们通过再次反转它们来恢复引用。在方法2中,我们使用当前节点的左子树从当前节点遍历到父节点,而不是反转路径并还原结构。根据树的结构,例如在右偏的树中,这可能会更快。
以下算法和图表提供了该方法的详细信息。
下面是概念图,显示了如何使用左右子引用来回遍历。
下图突出显示了路径1-> 2-> 5-> 9以及根据上述算法处理和打印节点的方式。
下面是上述方法的实现:
Java
// Java Program to implement
// the above approach
class TreeNode {
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data)
{
this.data = data;
}
public String toString()
{
return data + " ";
}
}
public class PostOrder {
TreeNode root;
// Function to Calculate Post
// Order Traversal
// Using Constant Space
void postOrderConstantspace(TreeNode root)
{
if (root == null)
return;
TreeNode current = null;
TreeNode prevNode = null;
TreeNode pre = null;
TreeNode ptr = null;
TreeNode netChild = null;
TreeNode prevPtr = null;
current = root;
while (current != null) {
if (current.left == null) {
current.left = prevNode;
// Set prevNode to current
prevNode = current;
current = current.right;
}
else {
pre = current.left;
// Find the right most child
// in the left subtree
while (pre.right != null
&& pre.right != current)
pre = pre.right;
if (pre.right == null) {
pre.right = current;
current = current.left;
}
else {
// Set the right most
// child's right pointer
// to NULL
pre.right = null;
System.out.print(pre);
ptr = pre;
netChild = pre;
prevPtr = pre;
while (ptr != null) {
if (ptr.right == netChild) {
System.out.print(ptr);
netChild = ptr;
prevPtr.left = null;
}
if (ptr == current.left)
break;
// Break the loop
// all the left subtree
// nodes of current
// processed
prevPtr = ptr;
ptr = ptr.left;
}
prevNode = current;
current = current.right;
}
}
}
System.out.print(prevNode);
// Last path traversal
// that includes the root.
ptr = prevNode;
netChild = prevNode;
prevPtr = prevNode;
while (ptr != null) {
if (ptr.right == netChild) {
System.out.print(ptr);
netChild = ptr;
prevPtr.left = null;
}
if (ptr == root)
break;
prevPtr = ptr;
ptr = ptr.left;
}
}
// Main Function
public static void main(String[] args)
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
PostOrder tree = new PostOrder();
tree.root = new TreeNode(1);
tree.root.left = new TreeNode(2);
tree.root.right = new TreeNode(3);
tree.root.left.left
= new TreeNode(4);
tree.root.left.right
= new TreeNode(5);
tree.root.right.left
= new TreeNode(6);
tree.root.right.right
= new TreeNode(7);
tree.root.left.right.left
= new TreeNode(8);
tree.root.left.right.right
= new TreeNode(9);
tree.postOrderConstantspace(
tree.root);
}
}
C#
// C# Program to implement
// the above approach
using System;
class TreeNode{
public int data;
public TreeNode left;
public TreeNode right;
public TreeNode(int data)
{
this.data = data;
}
public string toString()
{
return data + " ";
}
}
class PostOrder{
TreeNode root;
// Function to Calculate Post
// Order Traversal Using
// Constant Space
void postOrderConstantspace(TreeNode root)
{
if (root == null)
return;
TreeNode current = null;
TreeNode prevNode = null;
TreeNode pre = null;
TreeNode ptr = null;
TreeNode netChild = null;
TreeNode prevPtr = null;
current = root;
while (current != null)
{
if (current.left == null)
{
current.left = prevNode;
// Set prevNode to current
prevNode = current;
current = current.right;
}
else
{
pre = current.left;
// Find the right most child
// in the left subtree
while (pre.right != null &&
pre.right != current)
pre = pre.right;
if (pre.right == null)
{
pre.right = current;
current = current.left;
}
else
{
// Set the right most
// child's right pointer
// to NULL
pre.right = null;
Console.Write(pre.data + " ");
ptr = pre;
netChild = pre;
prevPtr = pre;
while (ptr != null)
{
if (ptr.right == netChild)
{
Console.Write(ptr.data + " ");
netChild = ptr;
prevPtr.left = null;
}
if (ptr == current.left)
break;
// Break the loop
// all the left subtree
// nodes of current
// processed
prevPtr = ptr;
ptr = ptr.left;
}
prevNode = current;
current = current.right;
}
}
}
Console.Write(prevNode.data + " ");
// Last path traversal
// that includes the root.
ptr = prevNode;
netChild = prevNode;
prevPtr = prevNode;
while (ptr != null)
{
if (ptr.right == netChild)
{
Console.Write(ptr.data + " ");
netChild = ptr;
prevPtr.left = null;
}
if (ptr == root)
break;
prevPtr = ptr;
ptr = ptr.left;
}
}
// Driver code
public static void Main(string[] args)
{
/* Constructed tree is as follows:-
1
/ \
2 3
/ \ / \
4 5 6 7
/ \
8 9
*/
PostOrder tree = new PostOrder();
tree.root = new TreeNode(1);
tree.root.left = new TreeNode(2);
tree.root.right = new TreeNode(3);
tree.root.left.left = new TreeNode(4);
tree.root.left.right = new TreeNode(5);
tree.root.right.left = new TreeNode(6);
tree.root.right.right = new TreeNode(7);
tree.root.left.right.left = new TreeNode(8);
tree.root.left.right.right = new TreeNode(9);
tree.postOrderConstantspace(tree.root);
}
}
// This code is contributed by Rutvik_56
输出
4 8 9 5 2 6 7 3 1
时间复杂度: O(N)
辅助空间: O(1)