以下代码包括二叉树的创建、前中后序遍历(递归)、非递归中序遍历(栈实现)、层序遍历(队列实现)和中序线索化遍历。
- main
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include"Tree.h"
#include"Queue.h"
#include"Stack.h"
#include"Tree.h"
#include"Marco.h"
using namespace std;
BiThrTree pre;//全局变量,表示刚刚访问过的结点
int main()
{
BiThrTree T = NULL;
printf("二叉树测试程序开始:\n");
printf("1.创建非空二叉树:\n");
CreateBiThrTree(T);
printf("\n2.前序遍历二叉树:\n");
PreOrderTraverse(T);
printf("\n3.中序遍历二叉树:\n");
InOrderTraverse(T);
printf("\n4.后序遍历二叉树:\n");
PostOrderTraverse(T);
printf("\n5.非递归中序遍历二叉树(用栈实现):\n");
NoRecursionInTraverse(T);
printf("\n6.层序遍历二叉树(用队列实现):\n");
LevelOrderTraverse(T);
printf("\n7.中序线索化遍历二叉树:\n");
BiThrTree Thrt;
InOrderThreading( Thrt,T );
InOrderAfterThreading(Thrt);
cout << "\n二叉树测试程序结束!" << endl;
return OK;
}
2.Tree.c
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include"Tree.h"
#include"Stack.h"
#include"Queue.h"
#include"Marco.h"
using namespace std;
extern BiThrTree pre;
/********************对二叉树的操作********************/
//1.创建二叉树
int CreateBiThrTree(BiThrTree &T)
{
char data;
scanf("%c", &data);
if (' ' == data)
{
T = NULL; //如果字符为空,则根节点为空
}
else
{
if (!(T = (BiThrTree)malloc(sizeof(BiThrNode))))//否则建立根节点
{
printf("出错:创建结点时分配空间错误!");
exit(OVERFLOW);
}
T->data = data; //根节点数据域
T->LTag = Link;
T->RTag = Link;
CreateBiThrTree(T->lchild); //构造左子树
CreateBiThrTree(T->rchild); //构造右子树
}
return OK;
}
//2.前序遍历
void PreOrderTraverse(BiThrTree T)
{
if (T)
{
printf("%c", T->data);
PreOrderTraverse(T->lchild);
PreOrderTraverse(T->rchild);
}
}
//3.中序遍历
void InOrderTraverse(BiThrTree T)
{
if (T)
{
InOrderTraverse(T->lchild);
printf("%c", T->data);
InOrderTraverse(T->rchild);
}
}
//4.后序遍历
void PostOrderTraverse(BiThrTree T)
{
if (T)
{
PostOrderTraverse(T->lchild);
PostOrderTraverse(T->rchild);
printf("%c", T->data);
}
}
//5.非递归中序遍历
void NoRecursionInTraverse(BiThrTree T)
{
BiThrTree p;
Stack s;
if (!(s.base = (BiThrTree*)malloc(sizeof(BiThrNode)))) //初始化栈
{
printf("出错:栈初始化失败时分配存储空间失败!\n");
exit(1);
}
s.top = s.base;
s.stackSize = STACK_INIT_SIZE;
p = T;
while(p || (s.top - s.base))
{
while (p) //遍历左子树,直到最左下角的节点
{
Push(s, p);
p = p->lchild;
}
if((s.top-s.base)) //左子树为空,根结点退栈,再遍历右子树
{
Pop(s, p);
printf("%c", p->data);
p = p->rchild;
}
}
}
//6.层序遍历
void LevelOrderTraverse(BiThrTree T)
{
Queue Q;
BiThrTree p=T; //p在过程中不断被赋予新的结点地址
Q.front = Q.rear = (QPtr)malloc(sizeof(QNode)); //初始化链队列
if (!Q.front)
{
cout << "\n初始化分配存储空间失败!\n" << endl;
exit(1);
}
Q.front->next = NULL;
if (p)
EnQueue(Q, p);
while (Q.front != Q.rear)
{
DelQueue(Q, p); //将被删除的结点赋予p,从而实现结点的更新
cout << p->data;
if (p->lchild != NULL)
{
EnQueue(Q, p->lchild);
}
if (p->rchild != NULL)
{
EnQueue(Q, p->rchild);
}
}//while
}
//7.中序线索化遍历
int InOrderThreading(BiThrTree &Thrt,BiThrTree T)
{
if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode))))
{
printf("出错:分配空间错误!");
exit(-2);
}
Thrt->LTag = Link; //建立头节点
Thrt->RTag = Thread;
Thrt->rchild = Thrt; //右指针回指指向头节点
if (!T) //二叉树空,头节点的lchild指向根节点
{
Thrt->lchild = Thrt;
}
else
{
Thrt->lchild = T; //T不为空,头节点的lchild连接根结点
pre = Thrt; //全局变量pre初始化,始终指向刚刚访问过的结点
InThreading(T); //中序遍历进行中序线索化,传入的是根结点
pre->rchild = Thrt;
pre->RTag = Thread;
Thrt->rchild = pre; //最后一个结点进行线索化
}
return OK;
}
void InThreading(BiThrTree p)
{
if (p)
{
InThreading(p->lchild); //递归,左子树线索化,直至最左下角的结点,其左子树为空,不在继续递归
//中间部分为对 当前结点 的线索化
if (!p->lchild) //当前结点 没有左子树,前驱线索
{
p->LTag = Thread;
p->lchild = pre; //p->lchild指向直接前驱
}
if (!pre->rchild) //刚访问过的结点 没有右子树,后继线索
{
pre->RTag = Thread;
pre->rchild = p; //
}
pre = p; //保持pre指向刚刚访问过的结点
InThreading(p->rchild); //递归,右子树线索化
}
}
//利用已经线索化的二叉树进行中序遍历输出, 非递归
void InOrderAfterThreading(BiThrTree Thrt) //传入的是pre,传入前进行的最后操作为:
{ //pre->rchild = Thrt;pre->RTag = Thread;Thrt->rchild = pre;
BiThrTree p;
p = Thrt->lchild;
while (p != Thrt)
{
while (p->LTag == Link)
{
p = p->lchild;
}
cout << p->data;
while (p->RTag == Thread && p->rchild != Thrt)
{
p = p->rchild;
cout << p->data;
}
p = p->rchild;
}
}
3.Stack.c
#include<stdio.h>
#include<stdlib.h>
#include"Stack.h"
#include"Tree.h"
/***********************对栈的操作***********************/
//1.Push
void Push(Stack &s, BiThrTree e)
{
// 栈满,追加空间
if (s.top - s.base >= s.stackSize)
{
s.base = (BiThrTree *)realloc(s.base, (s.stackSize + STACKINCREMENT) * sizeof(BiThrNode));
if (!s.base)
exit(0);
s.top = s.base + s.stackSize;
s.stackSize = s.stackSize + STACKINCREMENT;
}
*(s.top) = e; // 存放数据
s.top++;
}
//2.Pop
void Pop(Stack &s, BiThrTree &e)
{
if (s.top == s.base)
{
printf("\n出错:出栈时栈为空!\n");
exit(-2);
}
e = *(--s.top); // 将栈顶元素弹出并修改栈指针
}
4.Queue.c
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include"Queue.h"
#include"Marco.h"
#include"Tree.h"
using namespace std;
/*******************对队列的操作***************************/
//1.EnQueue
void EnQueue(Queue &Q, BiThrTree e)
{
QPtr q;
if (!(q = (QPtr)malloc(sizeof(QNode))))
{
printf("出错:队列分配存储空间失败!\n");
exit(OVERFLOW);
}
q->data = e;
q->next = NULL;
Q.rear->next = q;
Q.rear = q;
}
//2.DelQueue
void DelQueue(Queue &Q, BiThrTree &e)
{
if (Q.front == Q.rear)
{
cout << "出错:执行删除操作的队列为空!" << endl;
exit(1);
}
QPtr p = Q.front->next;
e = p->data;
Q.front->next = p->next;
if (Q.rear == p)
{
Q.rear = Q.front;
}
free(p);
}
5.Tree.h
#ifndef TREE_H_
#define TREE_H_
#include<stdio.h>
#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10
typedef enum PointerTag { Link, Thread }; //Link==0,表示指针,Thread==1,表示线索
typedef struct BiThrNode
{
char data;
struct BiThrNode *lchild;
struct BiThrNode *rchild;
PointerTag LTag;
PointerTag RTag;
}BiThrNode, *BiThrTree;
/********************对二叉树的操作********************/
//1.创建
int CreateBiThrTree(BiThrTree &T);
//2.前序遍历
void PreOrderTraverse(BiThrTree T);
//3.中序遍历
void InOrderTraverse(BiThrTree T);
//4.后序遍历
void PostOrderTraverse(BiThrTree T);
//5.非递归中序遍历
void NoRecursionInTraverse(BiThrTree T);
//6.层序遍历
void LevelOrderTraverse(BiThrTree T);
//7.中序遍历并线索
int InOrderThreading(BiThrTree &Thrt,BiThrTree T);
void InThreading(BiThrTree p);
//利用已经线索化的二叉树进行中序遍历输出
void InOrderAfterThreading(BiThrTree Thrt);
#endif
6.Stack.h
#ifndef STACK_H_
#define STACK_H_
#include"Tree.h"
typedef struct
{
BiThrTree *top;
BiThrTree *base;
int stackSize;
}Stack; //用于非递归遍历二叉树
/*******************需要的对栈的操作***********************/
//1.Push
void Push(Stack &s, BiThrTree e);
//2.Pop
void Pop(Stack &s, BiThrTree &e);
#endif
7.Queue.h
#ifndef QUEUE_H_
#define QUEUE_H_
#include"Tree.h"
typedef struct QNode //用于层序遍历二叉树
{
BiThrTree data; //存储地址
struct QNode *next;
}QNode, *QPtr;
typedef struct
{
QPtr front;
QPtr rear;
}Queue;
/******************对队列的操作****************************/
//1.EnQueue
void EnQueue(Queue &Q, BiThrTree e);
//2.DelQueue
void DelQueue(Queue &Q, BiThrTree &e);
#endif
8.Marco.h(此部分的代码作用暂时不大)
#ifndef MARCO_H_
#define MARCO_H_
#define OK 0
#define ERROR 1
//#define OVERFLOW -2
#endif
在编写二叉树的线索化的代码时,一直不清楚线索化的具体过程,尽管看上去很容易理解。希望在调试的过程中理解过程,但很难进行下去,因为并没有能够运行的代码,每当想到这里就果断放弃调试,感觉是对时间的浪费。终于,今天静下心来,搜到了一个二叉树动态线索化的网页,观看后勉强理解了,代码写出后,进行调试,进一步理解过程。当然,写代码时不断抄袭书中内容的习惯一直是硬伤,鉴于二叉树的重要性,打算完全靠自己重新写一次。望天道酬勤!
ps:在写这个程序期间,学习了部分C++的知识,但在上述代码中所夹杂的C++代码都是基本的输出,没有输入。(如有错误,望各位指出)。