a b c 使用 1 2 3 表示
/*
描述:二叉树的深度(前序 中序 后序 递归非递归搜素)、广度、搜索
作者:jz
日期:20140819
*/
#include<stdio.h>
#include<malloc.h>
#include<process.h> /* exit() */
#include<iostream>
using namespace std;
#include<stack>
#include<queue>
#define OK 1
#define TElemType int
#define Status int
#define Nil (-1)
//结束符
#define TRUE 1
#define FALSE 0
#define ERROR 0
typedef struct BiTNode /* 二叉树的二叉链表存储表示 */
{
TElemType data;
struct BiTNode *lchild,*rchild; /* 左右孩子指针 */
}BiTNode,*BiTree;
enum enum_tag {L=1,R=2};//后序遍历使用作为标记
typedef struct StackNode
{//后序遍历使用
enum_tag tag;
BiTNode* ptr;
}StackNode;
Status InitBiTree(BiTree *T)
{ /* 操作结果: 构造空二叉树T */
*T=NULL;
return OK;
}
void DestroyBiTree(BiTree *T)
{ /* 初始条件: 二叉树T存在。操作结果: 销毁二叉树T */
if(*T) /* 非空树 */
{
if((*T)->lchild) /* 有左孩子 */
DestroyBiTree(&(*T)->lchild); /* 销毁左孩子子树 */
if((*T)->rchild) /* 有右孩子 */
DestroyBiTree(&(*T)->rchild); /* 销毁右孩子子树 */
free(*T); /* 释放根结点 */
*T=NULL; /* 空指针赋0 */
}
}
void CreateBiTree(BiTree *T)
{ /*按先序次序输入二叉树中结点的值(可为字符型或整型,在主程中 */
/* 定义),构造二叉链表表示的二叉树T。变量Nil表示空(子)树。有改动 */
TElemType ch;
scanf("%d",&ch);
if(ch==Nil) /* 空 */
*T=NULL;
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if(!*T)
exit(-1);
(*T)->data=ch; /* 生成根结点 */
CreateBiTree(&(*T)->lchild); /* 构造左子树 */
CreateBiTree(&(*T)->rchild); /* 构造右子树 */
}
}
void PreOrderTraverse(BiTree T,Status(*Visit)(TElemType))
{ /* 初始条件: 二叉树T存在,Visit是对结点操作的应用函数。算法6.1,有改动 */
/* 操作结果: 先序递归遍历T,对每个结点调用函数Visit一次且仅一次 */
if(T) /* T不空 */
{
Visit(T->data); /* 先访问根结点 */
PreOrderTraverse(T->lchild,Visit); /* 再先序遍历左子树 */
PreOrderTraverse(T->rchild,Visit); /* 最后先序遍历右子树 */
}
}
void InOrderTraverse(BiTree T,Status(*Visit)(TElemType))
{ /* 初始条件: 二叉树T存在,Visit是对结点操作的应用函数 */
/* 操作结果: 中序递归遍历T,对每个结点调用函数Visit一次且仅一次 */
if(T)
{
InOrderTraverse(T->lchild,Visit); /* 先中序遍历左子树 */
Visit(T->data); /* 再访问根结点 */
InOrderTraverse(T->rchild,Visit); /* 最后中序遍历右子树 */
}
}
void PostOrderTraverse(BiTree T,Status(*Visit)(TElemType))
{ /* 初始条件: 二叉树T存在,Visit是对结点操作的应用函数 */
/* 操作结果: 后序递归遍历T,对每个结点调用函数Visit一次且仅一次 */
if(T) /* T不空 */
{
PostOrderTraverse(T->lchild,Visit); /* 先后序遍历左子树 */
PostOrderTraverse(T->rchild,Visit); /* 再后序遍历右子树 */
Visit(T->data); /* 最后访问根结点 */
}
}
Status Visit(TElemType e)//显示
{
printf("%d ",e);
return OK;
}
Status InOrderTraverse_use_stack(BiTree T,Status(*Visit)(TElemType))
{ /*非递归算法使用栈 进行前序 中序遍历 后序遍历的思想比较复杂需要使用到二次进栈*/
stack<BiTNode*> S;
BiTree p=T;
do
{
while(p)
{ /* 根指针进栈,遍历左子树 */
Visit(p->data);//先序遍历,先输出节点数据再压入栈
S.push(p);
p=p->lchild;
}
if(!S.empty())
{ /* 根指针退栈,访问根结点,遍历右子树 */
p=S.top();
//Visit(p->data);//中序遍历,在栈弹出时显示,(需要时将上面的Visit注释掉)
S.pop();
p=p->rchild;
}
}while(p||!S.empty());
printf("\n");
return OK;
}
/*
后序遍历非递归
后序非递归算法比较复杂,每个结点要到它们左、右子树都遍历完时才得以访问,所以在去遍历它的左、
右子树之前都需要进栈。当它出栈时,需要判断是从左子树回来(即刚遍历完左子树,此时需要去遍历右子树)
,还是从右子树回来(即刚遍历完右子树,此时需要去访问这个结点)。因此,进栈的结点需要伴随着一个标记
tag
*/
void PostOrderTraverse_use_stack(BiTree T)
{
stack<StackNode> S;
BiTree p;
StackNode w;
p=T;
do {
while(p)
{
w.ptr=p;
w.tag=L;
S.push(w);
p=p->lchild;
}
int cont_flag=1;
while( cont_flag&&!S.empty() )
{
w=S.top();
S.pop();
p = w.ptr;
switch(w.tag)
{
case L :
w.tag=R;
S.push(w);
cont_flag = 0;
p=p->rchild;
break;
case R:
Visit(p->data);
break;
}
}
}while(!S.empty() );
}
void LevelOrderTraverse(BiTree T,Status(*Visit)(TElemType))
{ /* 初始条件:二叉树T存在,Visit是对结点操作的应用函数 */
/* 操作结果:层序递归遍历T(利用队列),对每个结点调用函数Visit一次且仅一次 */
queue<BiTNode*> qu;
BiTree p;
p=T;
if(T)
{
qu.push(p);
while(!qu.empty())
{
p=qu.front();
qu.pop();
Visit(p->data);
if(p->lchild!=NULL)
qu.push(p->lchild);
if(p->rchild!=NULL)
qu.push(p->rchild);
}
printf("\n");
}
}
int main()
{
//输入: 1 2 3 -1 -1 4 5 -1 7 -1 -1 6 -1 -1 -1
printf("请输入构造二叉树的值,整数值,空值请输入‘-1’\n");
BiTree BT;
InitBiTree(&BT);
CreateBiTree(&BT);
printf("\n先序递归遍历递归\n");
PreOrderTraverse(BT,Visit);
printf("\n中序归遍历递归\n");
InOrderTraverse(BT,Visit);
printf("\n后序归遍历递归\n");
PostOrderTraverse(BT,Visit);
printf("\n-----------------------\n");
printf("\n先序递归遍历_非递归\n");
InOrderTraverse_use_stack(BT,Visit);
printf("\n后序遍历非递归\n");
PostOrderTraverse_use_stack(BT);
printf("\n层次遍历非递归\n");
LevelOrderTraverse(BT,Visit);
printf("\n");
DestroyBiTree(&BT);
return 0;
}