利用先序建树,二叉树的遍历才是重点,针对这章,编写了非递归遍历的几种方法
习惯性操作 将一些头文件包含在头文件t11.h中
#include"stdio.h"
#include"string.h"
#include"ctype.h"
#include"malloc.h"
#include"stdlib.h" //atoi(),exit();
#include"io.h" //eof()
#include"math.h"
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status;
typedef int Boolean;
在之后就是数据结构定义了,英语没学好啊,ercs.h中
#define INIT_STACK 40
#define ADD 2
typedef struct Binode // 定义二叉树节点类型
{
char data; // 存入元素
Binode *lchild,*rchild; // 定义左孩子和右孩子的结构体指针
}Binode,*Bitree;
struct lpBitree // 定义的存储二叉树结构体的结构体
{
Bitree lp;
int i; // 方便对栈操作,而设定的,在后序非递归遍历中一个判断变量
};
typedef struct // 定义栈结构体
{
lpBitree *bottom;
lpBitree *top;
int stacksize;
}Sqstack,*linkstack;
之后就是具体的实现函数代码了,定义在ercs.cpp中,利用栈的操作,根据遍历顺序,采取相应的操作
void inittree(Bitree &T) // 初始化二叉树
{
T=NULL;
}
void initstack(Sqstack &L) // 初始化栈
{
L.bottom=(lpBitree*)malloc(INIT_STACK*sizeof(lpBitree));
L.top=L.bottom;
L.stacksize=INIT_STACK;
}
Status push(Sqstack &L,Bitree e) // 入栈操作
{
if(L.top-L.bottom >= L.stacksize) // 栈空间不足
{
L.bottom=(lpBitree*)realloc(L.bottom,(L.stacksize+ADD)*sizeof(lpBitree));
L.top=L.bottom+L.stacksize;
L.stacksize+=ADD;
}
L.top->i=0; // 将首次入栈的元素同时表示执行次数,在gettop()函数中改变其值
(L.top++)->lp=e;
return OK;
}
Status pop(Sqstack &L,Bitree &e) // 出栈操作
{
if(L.top == L.bottom)
return ERROR;
else
{
e=(--L.top)->lp;
return OK;
}
}
Status emptystack(Sqstack L) // 判断栈是否为空
{
if(L.bottom == L.top)
return OK;
else
return ERROR;
}
Status gettop(Sqstack &L,Bitree &T) // 获取元素操作
{
if(L.bottom == L.top)
return ERROR;
else
{
T=(L.top-1)->lp;
++(L.top-1)->i; // 每执行此函数,栈中相应的i值发生变化
return OK;
}
}
void Createtree(Bitree &T) // 先序创建二叉树
{
char ch;
ch=getchar();
if(ch == 10) // 如果是回车键置为空
T=NULL;
else
{
T=(Bitree)malloc(sizeof(Binode));
if(!T)
{
printf("分配失败!");
exit(0);
}
if(ch != ' ') // 不为空格键执行递归调用
{
T->data=ch;
Createtree(T->lchild);
Createtree(T->rchild);
}
else
{
while(' ' == ch) // 屏蔽空格键
ch=getchar();
T->data=ch;
Createtree(T->lchild);
Createtree(T->rchild);
}
}
} // 创建二叉树结束
void xianxu(Bitree T,Sqstack &S) // 先序非递归遍历,采用的是保存右孩子的地址通过栈实现
{
printf("先序非递归遍历输出:\n");
if(T)
{
if(T->rchild)
push(S,T->rchild); // 专门压入右孩子指针地址
printf("%-3c",T->data);
T=T->lchild; // 更新指针
}else
exit(0);
while(T || !emptystack(S)) // 循环终止条件
{
if(T!= NULL) // 始终作为一个点存在加以判断,一种情况是一直指向左孩子,另一种就是出栈弹出的右孩子
{
printf("%-3c",T->data); // 输出节点的数据域
if(T->rchild != NULL) // 该节点存在右孩子,将右孩子入栈
push(S,T->rchild);
T=T->lchild; // 更新指针,始终往左走
}
else
pop(S,T);
}
}
void protraver(Bitree T,Sqstack &S) // 中序非递归遍历输出
{
printf("\n中序非递归遍历输出:\n");
while(T||!emptystack(S)) // 中序遍历规律与相关栈的操作
{
if(T)
{
push(S,T);
T=T->lchild;
}
else
{
pop(S,T);
printf("%-3c",T->data);
T=T->rchild;
}
}
printf("\n");
}
void lasttraver(Bitree T,Sqstack &S) // 后序非递归遍历程序 ,主要是采用i标记当一个元素左右孩子都存在,何时才应该出栈此元素
{
printf("后序非递归遍历输出:\n");
int num=0; // 记录单节点的个数
int leaf=0; // 记录叶子树
if(T)
push(S,T); // 头不为空,将其压入栈中
else
exit(0); // 头空退出
while(!emptystack(S)) // 判断是否栈空
{
if(T->lchild != NULL && (S.top-1)->i == 0) // 往左循环,相应的i值要为0,保证往左只有一次
{
if(T->rchild == NULL) // 单节点数的个数,条件是只有一个孩子,判断条件起始为0 防止后面修改,先获取单节点数
num++;
T=T->lchild;
push(S,T);
}
else
{
if(T->rchild != NULL && (S.top-1)->i == 0)
num++;
if((S.top-1)->i == 2) // 通过gettop()函数调用而改变的i的值,当获取次数为2次时,表明此元素出栈元素
{
pop(S,T);
printf("%-3c",T->data);
gettop(S,T); // 获取栈顶元素,并且是i值加1
}
else
{
if(T->lchild == NULL) // 左子树为空,相应的标记加1,直接寻找右子树
++(S.top-1)->i;
if(T->rchild != NULL) // 右子树不为空,入栈
{
T=T->rchild;
push(S,T);
}
else // 左右子树都为空
{
if(T->lchild == NULL) // 左子树为空,相应的标记加1,直接寻找右子树
leaf++;
pop(S,T); // 弹出元素
printf("%-3c",T->data);
gettop(S,T); // 得到栈顶元素,并使相应的i加1
}
}
} // 循环结束
}
printf("\n单节点数为:%d\n叶子树为:%d\n",num,leaf);
}
再就是定义主函数里面调用了 定义为main_ercs.cpp中
#include"t11.h"
#include"ercs.h"
#include"ercs.cpp"
void main()
{
Bitree S; // 构建树节点的指针
Sqstack R; // 构建栈结构体
initstack(R); // 初始化栈
inittree(S); // 初始化树
printf("输入数,回车构建空!\n");
Createtree(S); // 先序递归建树
printf("\n创建成功!\n");
xianxu(S,R); // 先序非递归遍历
protraver(S,R); // 中序非递归遍历
lasttraver(S,R); // 后序非递归遍历
}
总结,不知不觉学习数据结构课程有一段时间了,自己觉得最大的进步就是,编写程序比以前有了很大进步,思想也比较成熟,学习一些算法,所以自己一直没有停下脚步,因为我相信,高手是一个坚持的过程,过程造就了高手。我会继续,不抛弃,不放弃。因为喜欢,所以热爱。我心无悔。。。。。。。留住最真的于2012.04.17-07:40写~~~~~~~~~~~