#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stack>
#include <iostream>
typedef struct tag_Tree //二叉树
{
char data;
struct tag_Tree* lchild;
struct tag_Tree* rchild;
}Tree;
/*
函数功能: 访问树的节点
*/
void Visit(Tree* t)
{
printf("元素为:%c\n", t->data);
}
/*
函数功能:先序遍历一棵树;
注意:任何树的遍历方式,遍历一棵树的路径相同,只是访问的时间不同
*/
void PreOrder(Tree* root)
{
if (root == NULL)
{
return;
}
Visit(root);//先序
PreOrder(root->lchild);
PreOrder(root->rchild);
}
void InOrder(Tree* root)
{
if (root == NULL)
{
return;
}
InOrder(root->lchild);
Visit(root);//中序
InOrder(root->rchild);
}
void PostOrder(Tree* root)
{
if (root == NULL)
{
return;
}
PostOrder(root->lchild);
PostOrder(root->rchild);
Visit(root);//后序
}
/*
函数功能:计算树的叶子节点数
*/
void CountOfLeaf(Tree* root ,int * count)
{
if (root == NULL)
{
return;
}
if ((root->lchild == NULL) && (root->rchild == NULL))
{
++*count;//先序
Visit(root);
}
CountOfLeaf(root->lchild,count);
CountOfLeaf(root->rchild,count);
}
/*
函数功能:计算树的深度,根节点深度为0
*/
int DepthOfTree(Tree* root)
{
int leftDepth = 0;
int rightDepth = 0;
if (root == NULL)
{
return 0;
}
leftDepth = DepthOfTree(root->lchild);
rightDepth = DepthOfTree(root->rchild);
return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
}
/*
函数功能:计算树的叶子节点数
*/
int CountOfTree(Tree* root)
{
int lchild = 0;
int rchild = 0;
if (root == NULL)
{
return 0;
}
if ((root->lchild == NULL) && (root->rchild == NULL))
{
return 1;
}
lchild = CountOfTree(root->lchild);
rchild = CountOfTree(root->rchild);
return lchild + rchild;
}
/*
函数功能:树的拷贝
*/
Tree* CopyTree(Tree* root)
{
Tree* newT = NULL;
if (root == NULL) {
return NULL;
}
//先序拷贝
newT = (Tree*)malloc(sizeof(Tree));
if (newT == NULL) {
return NULL;
}
newT->data = root->data;
newT->lchild = CopyTree(root->lchild);
newT->rchild = CopyTree(root->rchild);
return newT;
}
using namespace std;
//到达树的最左边的节点
Tree* GoLeft(Tree* lchild, stack<Tree*>& s)
{
while (lchild->lchild != NULL)
{
s.push(lchild);
lchild = lchild->lchild;
}
return lchild;
}
/*前序遍历:非递归*/
void PreOrder2(Tree* root)
{
stack<Tree*> s;
Tree* p = root;
while (!s.empty() || p)//栈不为空或者p不为空
{
if (p)
{
Visit(p);//访问该节点
s.push(p);//节点入栈
p = p->lchild;//左子树
}
else//没有左子树
{
p = s.top();//弹出父节点
s.pop();
p = p->rchild;//右子树
}
}
}
/*函数功能:中序遍历树的非递归*/
void InOrder2(Tree* root)
{
/*
步骤1:
如果该节点有左子树,该节点入栈;
如果该节点没有左子树,访问该节点;
步骤2:
如果该节点有右子树,该节点入栈,接步骤一;
如果该节点没有右子树,访问该节点,退到栈顶,;
*/
Tree* t = NULL;
stack<Tree*> s;
if (root == NULL)
{
return;
}
t = GoLeft(root, s);//最左的节点
while (t != NULL)
{
Visit(t);
if (t->rchild != NULL)//节点有右子树
{
t = GoLeft(t->rchild, s);
}
else if (!s.empty())//没有右子树,且栈不为空
{
t = s.top();//根节点
s.pop();
}
else
{
t = NULL;//访问完毕
}
}
}
void InOrder3(Tree* root)
{
stack<Tree*> s;
Tree* p = root;
while (p != NULL || !s.empty())
{
while (p != NULL)
{
s.push(p);
p = p->lchild;
}
if (!s.empty())
{
p = s.top();
Visit(p);
s.pop();
p = p->rchild;
}
}
}
/*后序遍历非递归
要保证根结点在左孩子和右孩子访问之后才能访问,
因此对于任一结点P,先将其入栈。如果P不存在左孩子和右孩子
,则可以直接访问它;或者P存在左孩子或者右孩子,
但是其左孩子和右孩子都已被访问过了,
则同样可以直接访问该结点。若非上述两种情况,
则将P的右孩子和左孩子依次入栈,这样就保证了每次取栈顶元素的时候,
左孩子在右孩子前面被访问,左孩子和右孩子都在根结点前面被访问。
*/
void PostOrder2(Tree* root)
{
if (root == NULL)
{
return;
}
stack<Tree*> s;
Tree* cur;
Tree* pre = NULL;
s.push(root);
while (!s.empty())
{
cur = s.top();
if ((cur->lchild == NULL && cur->rchild == NULL)
|| (pre != NULL && (pre == cur->lchild || pre == cur->rchild)))
{
Visit(cur);//如果当前结点没有孩子结点或者孩子节点都已被访问过
s.pop();
pre = cur;
}
else
{
if (cur->rchild != NULL)
{
s.push(cur->rchild);
}
if (cur->lchild != NULL)
{
s.push(cur->lchild);
}
}
}
}
struct BTNode
{
Tree* btnode;
bool isFirst;
};
/*
对于任一结点P,将其入栈,然后沿其左子树一直往下搜索,
直到搜索到没有左孩子的结点,此时该结点出现在栈顶,
但是此时不能将其出栈并访问,因其右孩子还为被访问。
所以接下来按照相同的规则对其右子树进行相同的处理,
当访问完其右孩子时,该结点又出现在栈顶,此时可以将其出栈并访问。
这样就保证了正确的访问顺序。可以看出,在这个过程中,
每个结点都两次出现在栈顶,只有在第二次出现在栈顶时,才能访问它。
因此需要多设置一个变量标识该结点是否是第一次出现在栈顶。
*/
void PostOrder3(Tree* root)
{
stack<BTNode*> s;
Tree* p = root;
BTNode* temp;
while (p != NULL || !s.empty())
{
while (p != NULL)
{
BTNode* btn = new BTNode;
btn->btnode = p;
btn->isFirst = true;
s.push(btn);
p = p->lchild;
}
if (!s.empty())
{
temp = s.top();
s.pop();
if (temp->isFirst == true)
{
temp->isFirst = false;
s.push(temp);
p = temp->btnode->rchild;
}
else
{
Visit(temp->btnode);
delete temp;
temp = NULL;
p = NULL;
}
}
}
}
/*函数功能:先序创建一棵树*/
Tree* CreateTree()
{
Tree* t = NULL;
char ch;
scanf("%c", &ch);
if (ch == '#'){
return NULL;
}
else{
t = (Tree*)malloc(sizeof(Tree));
memset(t, 0, sizeof(Tree));
if (t == NULL){
return NULL;
}
t->data = ch;
t->lchild = CreateTree();
t->rchild = CreateTree();
}
return t;
}
int main()
{
Tree* myTree = NULL;
myTree = CreateTree();
if (myTree != NULL)
{
PostOrder(myTree);
}
return 0;
}
树的遍历及相关递归函数
最新推荐文章于 2022-05-25 11:51:12 发布