树的遍历的方式有很多 今天在这里进行一个汇总 不多说 直接上干货
三种基本遍历分别用递归和非递归来实现 所以需要用到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;
}
}
优点:当树的节点数为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;
}