二叉树的节点定义
typedef struct tree
{
int a;
struct tree* left;
struct tree* right;
int tag;//tag域用于后序遍历非递归
}Tnode, *Tree;
//使用堆栈及其操作的定义
typedef Tree* Stack;
static int top = -1;void pop(Stack a)//出栈
{
top--;
}
void push(Stack a,Tree p)//入栈
{
a[++top] = p;
}
一、二叉树的建立
Tree precreate()//使用一级指针,采用递归先序创建二叉树 { int a; scanf_s("%d", &a); if (a == -1)//表示结束输入节点 return NULL; else { Tree root = (Tree)malloc(sizeof(Tnode)); root->a = a; root->left = precreate(); root->right = precreate(); return root; } } void create(Tree *T)//使用二级指针,无返回值,递归实现先序创建二叉树 { int a; scanf_s("%d", &a); if (a == -1)//表示结束输入节点 *T = NULL; else { *T = (Tree)malloc(sizeof(Tnode));//给一级指针赋值 (*T)->a = a;//*T要加括号,因为*优先级低于-> create(&(*T)->left);//传入的是一级指针的地址,因为要改变一级指针所存的值(即树节点的地址) create(&(*T)->right); } }
二、二叉树的遍历
1.递归
void preorder(Tree T)//先序遍历递归实现
{
if (T) {
printf("%d ", T->a);
preorder(T->left);
preorder(T->right);
}
}
void midorder(Tree T)//中序遍历递归实现
{
if (T) {
midorder(T->left);
printf("%d ", T->a);
midorder(T->right);
}
}
void postorder(Tree T)//后序遍历递归实现
{
if (T) {
postorder(T->left);
postorder(T->right);
printf("%d ", T->a);
}
}
2.非递归
void PreOrderTraversal(Stack a, Tree p)//先序遍历非递归实现,根->左->右
{
if (p) {
push(a, p);
while (top != -1) {//内层while退出后,说明左子树遍历完毕,取栈顶元素,同时令其出栈
Tree q = a[top];
pop(a);
while (q) {//节点不空时,一直向其左子树走到尽头,同时碰到不空节点则输出,若有右儿子则压栈,至q==NULL退出内层while
printf("%d ", q->a);
if (q->right){
push(a, q->right);
}
q = q->left;
}
}
}
}
void InOrderTraversal(Stack a, Tree p)//中序遍历非递归实现,左->根->右
{
while (p || top != -1) {//当树不空或栈不空时进行遍历
while (p) {//节点不空则将其压栈,并一直向左子树走,直至P==NULL,退出第一个while
push(a, p);
p = p->left;
}
if (top != -1) {//此时p==NULL,说明左子树压栈完成,栈不空则取栈顶元素,访问节点
printf("%d ", a[top]->a);
p = a[top]->right;//此时该元素左子树以及自身均被访问完,所以转向访问该节点的右儿子,并弹出该元素
pop(a);
}
}
}
void PostOrderTraversal(Stack a, Tree p)//后序遍历非递归实现,设计一个tag标记是第几次经过该节点,左->右->根
{
while (p || top != -1) {//当树不空或栈不空时进行遍历
while (p) {//若节点不空,则将其压栈,设其tag=0,表示第一次访问该节点,此时将顺着该节点访问左子树
push(a, p);
p->tag = 0;
p = p->left;
}
p = a[top];//p==NULL,重新取栈顶元素并弹栈
pop(a);
if (p->tag == 0 && p->right) {//此时设tag=1,表示已经访问完左子树,如果其有右孩子就访问其右子树并且要再次将该节点压栈
p->tag++;
push(a, p);//因为右孩子未访问完毕,不能访问根节点,所以需要重新压栈,并转向右子树遍历
p = p->right;
}
else {//p->tag==1或者p->right==NULL情况,说明该节点的右子树全部访问完毕,可以输出该节点,并将其置为NULL,便于之后重新取未访问的栈顶元素
printf("%d ", p->a);
p = NULL;
}
}
}
完整代码测试(需加上之前定义的各种函数)
#include<stdio.h>
#include<stdlib.h>
#define MAXIMSIZE 100//定义堆栈大小
typedef struct tree//二叉树节点定义
{
int a;
struct tree* left;
struct tree* right;
int tag;
}Tnode, *Tree;
typedef Tree* Stack;
static int top = -1;
void create(Tree *T);
Tree precreate();
void preorder(Tree T);
void midorder(Tree T);
void postorder(Tree T);
void PreOrderTraversal(Stack a, Tree p);
void InOrderTraversal(Stack a, Tree p);
void PostOrderTraversal(Stack a, Tree p);
void pop(Stack a)//出栈
{
top--;
}
void push(Stack a,Tree p)//入栈
{
a[++top] = p;
}
/**********************************************主程序测试*****************************************/
int main(){
Tree T1;
create(&T1);//无返回值建树T1
Tree T2 = precreate();//有返回值建树T2
postorder(T1);//后序遍历T1
printf("\n");
Stack a[MAXIMSIZE];//建一个空堆栈
PostOrderTraversal(a,T2);//中序遍历T2
return 0;
}