树的三种基本遍历+层序遍历+神级遍历(Morris)

树的遍历的方式有很多 今天在这里进行一个汇总 不多说 直接上干货

三种基本遍历分别用递归和非递归来实现 所以需要用到stack 层序遍历需要用到queue 所以先引入头文件

#include
#include
#include
using namespace std;

先建立一个树的结点

class BinaryTreeNode
{
public:
	int value;
	BinaryTreeNode* left;
	BinaryTreeNode* right;
};

方便大家的验证 这里我为大家提供了一个插入函数

bool Insert(BinaryTreeNode **r, int value)
{
	if (!(*r))
	{
		(*r) = (BinaryTreeNode*)calloc(1, sizeof(BinaryTreeNode));
		(*r)->value = value;
		(*r)->left = NULL;
		(*r)->right = NULL;
	}
	else
	{
		BinaryTreeNode *p = *r;
		BinaryTreeNode *parent = NULL;
		while (p)
		{
			if (value < p->value)
			{
				parent = p;
				p = p->left;
			}
			else if (value > p->value)
			{
				parent = p;
				p = p->right;
			}
			else
			{
				return false;
			}
		}
		if (value < parent->value)
		{
			parent->left = (BinaryTreeNode*)calloc(1, sizeof(BinaryTreeNode));
			parent->left->value = value;
			parent->left->left = NULL;
			parent->left->right = NULL;
		}
		else
		{
			parent->right = (BinaryTreeNode*)calloc(1, sizeof(BinaryTreeNode));
			parent->right->value = value;
			parent->right->left = NULL;
			parent->right->right = NULL;
		}
	}
	return true;
}

三种基本遍历的递归方式很简单 很多书籍都有说明 这里不做重点强调 只给出代码

前序遍历 递归

void PreorderRecur(BinaryTreeNode* root)
{
	if (root == NULL)
	{
		return;
	}
	cout << root->value << " ";
	PreorderRecur(root->left);
	PreorderRecur(root->right);
}

中序遍历 递归

void InorderRecur(BinaryTreeNode* root)
{
	if (root == NULL)
	{
		return;
	}
	InorderRecur(root->left);
	cout << root->value << " ";	
	InorderRecur(root->right);
}

后序遍历 递归

void PostorderRecur(BinaryTreeNode* root)
{
	if (root == NULL)
	{
		return;
	}
	PostorderRecur(root->left);
	PostorderRecur(root->right);
	cout << root->value << " ";
}

三种基本遍历的非递归实现

前序遍历 非递归

思想:根入栈 循环条件(栈不空){ 根节点指栈顶 出栈输出 (右子树)先(左子树)入栈}

void PreorderNonRecur(BinaryTreeNode* root)
{
	if (root != NULL)
	{
		stack s;
		s.push(root);
		while (!s.empty())
		{
			root = s.top();
			s.pop();
			cout << root->value << " ";
			if (root->right != NULL)
			{
				s.push(root->right);
			}
			if (root->left != NULL)
			{
				s.push(root->left);
			}
		}
		cout << endl;
	}
}

中序遍历 非递归

思想:循环条件(栈不空||根节点不空){ 如果(根不空) 根入栈 根节点指向左子树 否则 根节点指向栈顶 出栈输出 根节点指向右子树}

void InorderNonRecur(BinaryTreeNode* root)
{
	if (root != NULL)
	{
		stack s;
		while (!s.empty() || root != NULL)
		{
			if (root != NULL)
			{
				s.push(root);
				root = root->left;
			}
			else
			{
				root = s.top();
				s.pop();
				cout << root->value << " ";
				root = root->right;
			}
		}
		cout << endl;
	}
}

后序遍历 非递归

后序遍历比较麻烦 这里提供两种方式实现 分别使用两个栈和一个栈来实现

方式1:两个栈实现

思想:根入栈1 循环条件(栈1不空){ 根节点指向栈1顶 出栈 根入栈2 (左子树)先(右子树)入栈1} 循环条件(栈2不空){ 栈2出栈输出}

void PostorderNonRecur1(BinaryTreeNode* root)
{
	if (root != NULL)
	{
		stack s1;
		stack s2;
		s1.push(root);
		while (!s1.empty())
		{
			root = s1.top();
			s1.pop();
			s2.push(root);
			if (root->left != NULL)
			{
				s1.push(root->left);
			}
			if (root->right != NULL)
			{
				s1.push(root->right);
			}
		}
		while (!s2.empty())
		{
			cout << s2.top()->value << " ";
			s2.pop();
		}
		cout << endl;
	}
}

方式2:一个栈实现

思想:根入栈 新建节点指针cur等于NULL 循环条件(栈不空){ cur=栈顶 如果(cur左子树非空&&根不为cur左子树&&根不为cur右子树) cur左子树入栈 如果(cur右子树非空&&根不为cur右子树) cur右子树入栈 否则 出栈输出 根节点等于cur}

个人理解:这里的root更像一个标记值 记住三点就可以:

1、root所指的位置意味着其本身包括其子节点都已被访问

2、当root为某个节点的左节点时 表示这个节点的左节点已被访问

3、当root为某个节点的右节点时 表示这个节点的左节点和右节点都已被访问

void PostorderNonRecur2(BinaryTreeNode* root)
{
	if (root != NULL)
	{
		stack s;
		s.push(root);
		BinaryTreeNode *cur = NULL;
		while (!s.empty())
		{
			cur = s.top();
			if ((cur->left != NULL) && (root != cur->left) && (root != cur->right))
			{
				s.push(cur->left);
			}
			else if ((cur->right != NULL) && (root != cur->right))
			{
				s.push(cur->right);
			}
			else
			{
				cout << s.top()->value << " ";
				s.pop();
				root = cur;
			}
		}
		cout << endl;
	}
}

层序遍历

像前序遍历 不同的是用队列来实现 并且左子树先右子树入队列

void Sequence(BinaryTreeNode* root)
{
	if (root != NULL)
	{
		queue q;
		q.push(root);
		while (!q.empty())
		{
			root = q.front();
			q.pop();
			cout << root->value << " ";
			if (root->left != NULL)
			{
				q.push(root->left);
			}
			if (root->right != NULL)
			{
				q.push(root->right);
			}
		}
		cout << endl;
	}
}

神级遍历 Morris算法

优点:当树的节点数为N时 遍历的时间复杂度O(N) 额外空间复杂度O(1)

这种方法没有使用函数栈(递归)和栈(非递归) 降低了空间复杂度 主要是利用了叶子节点的right为NULL 利用两个指针 让某个节点的左子树的最右边的结点的right指向自己本身 进行遍历后 又会将right赋NULL 不会改变树的结构 三种实现大体一样 具体可见代码

前序遍历

void MorrisPre(BinaryTreeNode *root)
{
	if (root != NULL)
	{
		BinaryTreeNode *cur1 = root;
		BinaryTreeNode *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;
					cout << cur1->value << " ";
					cur1 = cur1->left;
					continue;
				}
				else
				{
					cur2->right = NULL;
				}
			}
			else
			{
				cout << cur1->value << " ";
			}
			cur1 = cur1->right;
		}
		cout << endl;
	}
}

中序遍历

void MorrisIn(BinaryTreeNode *root)
{
	if (root != NULL)
	{
		BinaryTreeNode *cur1 = root;
		BinaryTreeNode *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;
	}
}

后序遍历

void printEdge(BinaryTreeNode *root);
BinaryTreeNode* reverseEdge(BinaryTreeNode* from);
void MorrisPost(BinaryTreeNode *root)
{
	if (root != NULL)
	{
		BinaryTreeNode *cur1 = root;
		BinaryTreeNode *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(cur1->left);
				}
			}
			cur1 = cur1->right;
		}
		printEdge(root);
		cout << endl;
	}
}
void printEdge(BinaryTreeNode *root)
{
	BinaryTreeNode *tail = reverseEdge(root);
	BinaryTreeNode *cur = tail;
	while (cur != NULL)
	{
		cout << cur->value << " ";
		cur = cur->right;
	}
	reverseEdge(tail);
}
BinaryTreeNode* reverseEdge(BinaryTreeNode *from)
{
	BinaryTreeNode *pre = NULL;
	BinaryTreeNode *next = NULL;
	while (from != NULL)
	{
		next = from->right;
		from->right = pre;
		pre = from;
		from = next;
	}
	return pre;
}

 

你可能感兴趣的:(数据结构)