Morris遍历详解——二叉树先序中序后序遍历( 时间复杂度O(N),空间复杂度O(1) )

Morris二叉树遍历:

来到当前的节点:Cur
  1. 如果Cur无左孩子,Cur向右移动 (Cur = Cur.right)
  2. 如果Cur有左孩子,找到Cur左子树上最右的节点,记为 mostright
  • (1) 如果mostright的右指针为null,则让其右指针指向Cur,并使Cur向左移动 (Cur = Cur.left)
  • (2) 如果mostright的右指针指向Cur,则让其右指针指向null,并使Cur向右移动 (Cur = Cur.right)
思路:(可模拟先序中序后序)
  1. 该节点有左子节点,则可以访问到该节点两次
  2. 该节点无左子节点,则只能访问到该节点一次
#include 
using namespace std;
//树的节点类型
class Node{
public:
	int val;
	Node *left, *right;
	explicit Node(int x) :val(x), left(nullptr), right(nullptr) {}
};
void printEdge(Node*&);
void reverseEdge(Node *&);

Morris先序遍历:

//Morris先序
void MorrisPre(Node* head)
{
	if (head == nullptr)return;
	Node *cur = head;
	Node *mostRight = nullptr;
	while (cur != nullptr)
	{
		mostRight = cur->left;
		//【1、2、】判断Cur的左孩子是否为空
		if (cur->left != nullptr)
		{
			//不断向右寻找Cur左子树最右的节点【mostRight右节点不为空 或者 不为当前cur节点,则非最右】
			while (mostRight->right != nullptr && mostRight->right != cur)
			{
				mostRight = mostRight->right;
			}
			// { 隐含意思:为空表示第一次来到该节点位置,为cur表示第二次来到该节点位置 } 
			//【2、(1)、】若最右节点为空
			if (mostRight->right == nullptr)//{ 第一次来到该节点, 将该节右指针设为cur,表示该节点下一步将移动到cur }
			{
				//////【---【先序遍历】: 当前指针cur要准备往左孩子走了,马上打印】
				cout << "第一次:" << cur->val << endl;
				mostRight->right = cur;
				cur = cur->left;
				continue;
			}
			else//【2、(2)、】若最右节点为当前节点cur 
			{// { 第二次来到该节点, 将该节点右指针设为原来的null,
			 //   前一步其实已经将当前cur指针指向了该节点的右节点了,即当前的cur已经是当前mostright的下一步节点了}
				mostRight->right = nullptr;
			}
		}
		else//当前cur没有左孩子的时候
		{
			//////【---【先序遍历】: 当前指针cur没有左孩子,要准备往右孩子走了,马上打印】
			cout << "第二次:" << cur->val << endl;
		}
		//【1、】Cur的左孩子为空 或者【 2、(2)、】mostright的右孩子为Cur,即第二次访问到该节点的时候
		cur = cur->right;
	}
}

Morris中序遍历:

void MorrisIn(Node* head)
{
	if (head == nullptr)return;
	Node *cur = head;
	Node *mostRight = nullptr;
	while (cur != nullptr)
	{
		mostRight = cur->left;
		//【1、2、】判断Cur的左孩子是否为空
		if(cur->left != nullptr)
		{
			//不断向右寻找Cur左子树最右的节点【mostRight右节点不为空 或者 不为当前cur节点,则非最右】
			while (mostRight->right != nullptr && mostRight->right != cur)
			{
				mostRight = mostRight->right;
			}
			// { 隐含意思:为空表示第一次来到该节点位置,为cur表示第二次来到该节点位置 } 
			//【2、(1)、】若最右节点为空
			if(mostRight->right == nullptr)//{ 第一次来到该节点, 将该节右指针设为cur,表示该节点下一步将移动到cur }
			{ 
				mostRight->right = cur;
				cur = cur->left;
				continue;
			}else//【2、(2)、】若最右节点为当前节点cur 
			{// { 第二次来到该节点, 将该节点右指针设为原来的null,
			 //   前一步其实已经将当前cur指针指向了该节点的右节点了,即当前的cur已经是当前mostright的下一步节点了}
				mostRight->right = nullptr;
			}
		}else//当前cur没有左孩子的时候
		{

		}
		//////【---【中序遍历】: 当前指针cur要准备往右孩子走了,马上打印】
		cout << "第二次:" << cur->val << endl;
		//【1、】Cur的左孩子为空 或者【 2、(2)、】mostright的右孩子为Cur,即第二次访问到该节点的时候
		cur = cur->right;
	}
}

Morris后序遍历:

void MorrisPos(Node* head)
{
	if (head == nullptr)return;
	Node *cur = head;
	Node *mostRight = nullptr;
	while (cur != nullptr)
	{
		mostRight = cur->left;
		//【1、2、】判断Cur的左孩子是否为空
		if (cur->left != nullptr)
		{
			//不断向右寻找Cur左子树最右的节点【mostRight右节点不为空 或者 不为当前cur节点,则非最右】
			while (mostRight->right != nullptr && mostRight->right != cur)
			{
				mostRight = mostRight->right;
			}
			// { 隐含意思:为空表示第一次来到该节点位置,为cur表示第二次来到该节点位置 } 
			//【2、(1)、】若最右节点为空
			if (mostRight->right == nullptr)//{ 第一次来到该节点, 将该节右指针设为cur,表示该节点下一步将移动到cur }
			{
				mostRight->right = cur;
				cur = cur->left;
				continue;
			}
			else//【2、(2)、】若最右节点为当前节点cur 
			{// { 第二次来到该节点, 将该节点右指针设为原来的null,
			 //   前一步其实已经将当前cur指针指向了该节点的右节点了,即当前的cur已经是当前mostright的下一步节点了}
				mostRight->right = nullptr;

				//////【---【后序遍历】: *逆序*打印当前节点cur的左子树的右边界】
				printEdge(cur->left);
			}
		}
		else//当前cur没有左孩子的时候
		{

		}
		//【1、】Cur的左孩子为空 或者【 2、(2)、】mostright的右孩子为Cur,即第二次访问到该节点的时候
		cur = cur->right;
	}
	//////【---【后序遍历】: Morris遍历完成后单独*逆序*打印整棵树的右边界】
	printEdge(head);

}

/*
 * 逆序打印左子树的右边界
 */
void printEdge(Node *& node)
{
	reverseEdge(node);
	Node *lastNode = nullptr;
	Node *nextNode = node->right;
	while (nextNode != nullptr)
	{
		cout << node->val << endl;
		node->right = lastNode;
		lastNode = node;
		node = nextNode;
		nextNode = nextNode->right;
	}
	cout << node->val << endl;
	node->right = lastNode;
}
/*
 * 类似单链表反转,O(1),将子树最右边界进行反转
 */
void reverseEdge(Node *&node)
{
	Node *lastNode = nullptr;
	Node *nextNode = node->right;
	while (nextNode != nullptr)
	{
		node->right = lastNode;
		lastNode = node;
		node = nextNode;
		nextNode = nextNode->right;
	}
	node->right = lastNode;
}

你可能感兴趣的:(二叉树高级算法)