//二叉树的二叉链表表示和各种实现
//用顺序栈来实现遍历的非递归操作
//用队列来帮助实现一些函数
//二叉树的二叉链表表示和各种实现
//用顺序栈来实现遍历的非递归操作
//用队列来帮助实现一些函数
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
typedef char TElemType;
typedef int Status;
#define OK 1
#define ERROR 0
#define INIT_SIZE 100
#define INCREMENT 10
/***********************************/
//树的节点类型
typedef struct BiTNode
{
TElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
/***********************************/
typedef BiTree SElemType;
typedef BiTree QElemType;
/**********************************/
/***队列的各个函数的 定义*********/
//链表队列节点类型
typedef struct QNode
{
QElemType data;
struct QNode * next;
}QNode;
//链表队列类型
typedef struct LinkQueue
{
QNode *front;//指向链表的对头节点,用来删除
QNode *rear;//指向链表的队尾节点,用来插入
}LinkQueue;
//初始化一个队列
Status InitQueue (LinkQueue *Q)
{
//让队头指针合队尾指针均指向头结点
Q->front = Q->rear = (QNode *)malloc(sizeof(QNode ));//生成一个头结点类型
if(!Q->front)
{
printf("队列初始化失败:内存分配失败\n");
return ERROR;
}
return OK;
}
//销毁一个队列
Status DestroyQueue(LinkQueue * Q)
{
while(Q->front)//如果Q->front 不为空
{
Q->rear=Q->front->next;
free(Q->front);
Q->front=Q->rear;
}
return OK;
}
//判断是否为空队列,如果是空队列,则返回OK,如果不是空队列,则返回ERROR
Status QueueEmpty(LinkQueue *Q)
{
if(Q->rear==Q->front)//如果对头指针和队尾指针相同则是空队列,头指针始终指向头节点
return OK;
return ERROR;
}
//向队列中插入元素
Status EnQueue(LinkQueue *Q,QElemType e)
{
QNode *s=(QNode *)malloc(sizeof(QNode));
if(!s)
return ERROR;
s->data=e;
s->next=NULL;
Q->rear->next=s;
Q->rear=s;
return OK;
}
//从队列中删除元素,并将元素值存放在e中
Status DeQueue(LinkQueue *Q,QElemType *e)
{
if(Q->front==Q->rear)//队列为空
return ERROR;
QNode *s=Q->front->next;//令s指向队列的对头节点
*e=s->data;
Q->front->next=s->next;
if(Q->rear==s)//如果只有一个元素
Q->rear=Q->front;
free(s);
return OK;
}
/**********************************/
/******顺序栈的有关函数定义*******/
//顺序栈的结构类型
typedef struct
{
SElemType *base;//地址空间的基址
SElemType *top;//顺序栈的栈顶指针
int stacksize;//分配到的地址大小
}SqStack;
//初始化一个栈
Status InitStack(SqStack *S)
{
S->base=(SElemType*)malloc(sizeof(SElemType)*(INIT_SIZE));
if(!(S->base))
{
printf("栈空间内存分配失败\n");
return ERROR;
}
S->top=S->base;
S->stacksize=INIT_SIZE;
return OK;
}
//判断栈是否为空
Status StackEmpty(SqStack *S)
{
if(S->top==S->base)
return OK;
else
return ERROR;
}
//若栈不空,则用e返回S的栈顶元素,并且返回1;否则返回0
Status GetTop(SqStack *S,SElemType *e)
{
if((S->top)-(S->base)>0)
{
*e=*(S->top-1);
return OK;
}
else
return ERROR;
}
//插入元素e作为新的栈顶元素
Status Push(SqStack *S,SElemType e)
{
if((S->top)-(S->base)>=S->stacksize)//栈满
{
S->base=(SElemType *)realloc(S->base,sizeof(SElemType)*(INIT_SIZE+INCREMENT));
if(!S->base)
{
printf("栈满,且重新分配内存空间失败\n");
return ERROR;
}
S->top=S->base+S->stacksize;
S->stacksize+=INCREMENT;
}
*(S->top)=e;
S->top++;
return OK;
}
//栈顶元素出栈,并且用e记录其值
Status Pop(SqStack *S,SElemType *e)
{
if(S->top==S->base)//如果是空栈
return ERROR;
else
{
*e = *(--S->top);
return OK;
}
}
/******************************************/
/******************************************/
//用Nil表示空字符
TElemType Nil=' ';
//构造空二叉树
Status InitBiTree(BiTree *T)
{
*T=NULL;
return OK;
}
//销毁整个二叉树
Status DestroyBiTree(BiTree *T)
{
if(!*T)
return ERROR;
else
{
if((*T)->lchild)//如果存在左孩子
DestroyBiTree(&(*T)->lchild);
if((*T)->rchild)
DestroyBiTree(&(*T)->rchild);
free(*T);
*T=NULL;//将*T赋值为NULL
}
return OK;
}
#define ClearBiTree DestroyBiTree;
// 按先序次序输入二叉树中结点的值,构造二叉链表表示的二叉树T
// 变量Nil表示空(子)树。
void CreateBiTree(BiTree *T)
{
TElemType c;
scanf("%c",&c);
if(c==Nil)
*T=NULL;
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if(!*T)
exit(0);
(*T)->data=c;
CreateBiTree(&(*T)->lchild);//递归构造左子树
CreateBiTree(&(*T)->rchild);//递归构造右子树
}
}
//判断树是否为空树
Status BiTreeEmpty(BiTree T)
{
if(!T)//如果指针是空的话就是空树
return OK;
else
return ERROR;
}
//返回树的深度
int BiTreeDepth(BiTree T)
{
if(BiTreeEmpty(T))//如果树为空树 ,则返回0
return 0;
else
{
return (BiTreeDepth(T->lchild)>=BiTreeDepth(T->rchild)?BiTreeDepth(T->lchild):BiTreeDepth(T->rchild))+1;
}
}
//返回树的根值
TElemType Root(BiTree T)
{
if(BiTreeEmpty(T))//如果T为空
return Nil;
else
return T->data;
}
//返回指针p指向的 值
TElemType Value(BiTree p)
{
return p->data;
}
//给指针p所指向的节点重新赋值
void Assign(BiTree p,TElemType value)
{
p->data=value;
}
//二叉树T存在,e是T中的某一个节点,若e是T中的非根节点,则返回它的双亲的值,否则返回“空”
TElemType Parent(BiTree T,TElemType e)
{
//思想是和层次遍历队列一样的。从每一层的节点开始搜索。依次进行判断
//只不过是加了判断条件
LinkQueue *Q=(LinkQueue *)malloc(sizeof(LinkQueue));
InitQueue(Q);
if(T->data==e)
{
printf("节点是根节点,没有双亲节点\n");
return Nil;
}
EnQueue(Q,T);
BiTree p;
//BiTree *p=(BiTree *)malloc(sizeof(BiTree));
while(!QueueEmpty(Q))//如果队列不为空
{
DeQueue(Q,&p);
if(p->lchild&&(p->lchild)->data==e)
{
return p->data;//返回双亲的值
break;
}
if(p->rchild&&(p->rchild)->data==e)
{
return p->data;
break;
}
else
{
if(p->lchild)
EnQueue(Q,p->lchild);
if(p->rchild)
EnQueue(Q,p->rchild);
}
}
return Nil;//树中没有这个节点
}
//返回二叉树T中指向元素值为e的节点的指针
BiTree Point(BiTree T,TElemType e)
{
LinkQueue Q;
InitQueue(&Q);
EnQueue(&Q,T);
QElemType a;
while(!QueueEmpty(&Q))//队列为非空
{
DeQueue(&Q,&a);
if(a->data==e)
return a;
if(a->lchild)
EnQueue(&Q,a->lchild);
if(a->rchild)
EnQueue(&Q,a->rchild);
}
return NULL;
}
//二叉树T存在,e是T中的某个节点。返回T的左孩子,若无左孩子,则返回空
TElemType LeftChild(BiTree T,TElemType e)
{
BiTree a;
if(T)
{
a=Point(T,e);//获取e的指针
if(a&&a->lchild)
return (a->lchild)->data;
}
return Nil;
}
//二叉树T存在,e是T中的某个节点。返回T的右孩子,若无右孩子,则返回空
TElemType RightChild(BiTree T,TElemType e)
{
BiTree a;
if(T)
{
a=Point(T,e);//获取e的指针
if(a&&a->rchild)
return a->rchild->data;
}
return Nil;
}
//二叉树T存在,e是T中的某个节点,返回e的左兄弟,若e是T的左孩子或者无左兄弟,则返回空
TElemType LeftSibling(BiTree T,TElemType e)
{
if(!T)
return Nil;
TElemType par=Parent(T,e);
BiTree p=Point(T,par);
if(!p->lchild||p->lchild->data==e)//如果左孩子为空或者e是T的其父的左孩子
return Nil;
else
{
return p->lchild->data;
}
}
//二叉树T存在,e是T中的某个节点,返回e的右兄弟,若e是T的右孩子或者无右兄弟,则返回空
TElemType RightSibling(BiTree T,TElemType e)
{
if(!T)
return Nil;
TElemType par=Parent(T,e);
BiTree p=Point(T,par);
if(!p->rchild||p->rchild->data==e)
return Nil;
else
{
return p->rchild->data;
}
}
//二叉树T存在,p指向T中的某个节点,LR为0或者1
//非空二叉树c与T不想交且右子树为空,根据LR为0或1,插入c为T中p所指向节点的左或者右字树
//p所指向节点的原有左子树或者右子树则成为c的右子树
Status InsertChild(BiTree T,BiTree p,int LR, BiTree c)
{
if(!T)
return ERROR;
if(p)//如果p不为空
{
if(LR==0)//插入c为T中p所指节点的左子树
{
if(p->lchild&&p->rchild)
return ERROR;
p->lchild=c;
c->rchild=p->lchild;
}
else if(LR==1)//插入c为T中p所指节点的右子树
{
if(p->lchild&&p->rchild)
return ERROR;
c->rchild=p->rchild;
p->rchild=c;
}
else
return ERROR;
}
}
//二叉树T存在,p指向T中的某个节点,LR为0或1
//根据LR 为0或者1,删除T中p所指节点的左或右子树
Status DeleteChild(BiTree T,BiTree p,int LR)
{
if(p)
{
if(LR==0)
DestroyBiTree(p->lchild);
else if(LR==1)
DestroyBiTree(p->rchild);
return OK;
}
return ERROR;
}
//访问函数
int PrintElement(TElemType e)
{
printf("%c ",e);
return 1;
}
// 先序递归遍历T,对每个结点调用函数PrintElement一次且仅一次
void PreOrderTraverse(BiTree T,int(*PrintElement)(TElemType))
{
if(T) // T不空
{
PrintElement(T->data); // 先访问根结点
PreOrderTraverse(T->lchild,PrintElement); // 再先序遍历左子树
PreOrderTraverse(T->rchild,PrintElement); // 最后先序遍历右子树
}
}
// 中序递归遍历T,对每个结点调用函数PrintElement一次且仅一次
void InOrderTraverse(BiTree T,int(*PrintElement)(TElemType))
{
if(T) //T不为空
{
InOrderTraverse(T->lchild,PrintElement);
PrintElement(T->data);
InOrderTraverse(T->rchild,PrintElement);
}
}
// 后序递归遍历T,对每个结点调用函数PrintElement一次且仅一次
void PostOrderTraverse(BiTree T,int(*PrintElement)(TElemType))
{
if(T) //T不为空
{
PostOrderTraverse(T->lchild,PrintElement);
PostOrderTraverse(T->rchild,PrintElement);
PrintElement(T->data);
}
}
/*利用堆栈来实现树的一些非递归遍历*/
/*将指向树节点的指针作为栈的类型节点的内容*/
/************************************前序非递归遍历的两种写法*************************************/
//前序遍历二叉树T的非递归算法(第一种方法),对每个数据元素调用PrintElement函数
Status PreOrderNonResusiveTraverse(BiTree T,int(*PrintElement(TElemType)))
{
SqStack *S=(SqStack*)malloc(sizeof(SqStack));
InitStack(S);
while(T||(!StackEmpty(S)))
{
if(T)
{
if(!PrintElement(T->data))
return ERROR;
Push(S,T);
T=T->lchild;
}
else
{
Pop(S,&T);
T=T->rchild;
}
}
printf("\n");
return OK;
}
// 错误的方法.
//前序遍历二叉树T的非递归算法(第二种方法),对每个数据元素调用PrintElement函数
Status PreOrderNonResusiveTraverse2(BiTree T,int(*PrintElement(TElemType)))
{
// 初始化一个栈
SqStack *S=(SqStack*)malloc(sizeof(SqStack));
InitStack(S);
//首先访问根节点,并且压入栈中
Push(S,T);
//BiTree value;//value实际的值是BiTree 指针
while(!StackEmpty(S))
{
while(GetTop(S,&T)&&T)//一直将左孩子访问并放入到栈中
{
PrintElement(T->data);
T=T->lchild;
//PrintElement(T->data);
Push(S,T);//一直将左孩子节点压入栈中
}
Pop(S,&T);
//如果栈为非空,则出栈一个元素,并且判断是否有右孩子。
//直接找到第一个右孩子的节点,并且出栈将指针指向它,重新循环~
while(!StackEmpty(S))
{
Pop(S,&T);
if(T->rchild)
{
T=T->rchild;
Push(S,T);
break;
}
}
}
return OK;
}
/************************************前序非递归遍历的两种写法*************************************/
/************************************中序非递归遍历的两种写法*************************************/
//中序遍历二叉树T的非递归算法(第一种方法),对每个数据元素调用PrintElement函数
Status InOrderNonResusiveTraverse(BiTree T,int(*PrintElement(TElemType)))
{
SqStack *S=(SqStack*)malloc(sizeof(SqStack));
InitStack(S);
Push(S,T);//先将根节点入栈
BiTree *e=(BiTree* )malloc(sizeof(BiTree));
while(!StackEmpty(S))//如果栈为非空
{
/*遍历左子树,向左一直走到尽头*/
while(GetTop(S,e)&&(*e))
Push(S,(*e)->lchild);
Pop(S,e);//将最后的空指针退栈
if(!StackEmpty(S))//如果栈为非空,则访问节点,并且向右走一步,继续遍历其子树
{
Pop(S,e);
if(!(PrintElement((*e)->data)))
return ERROR;
Push(S,(*e)->rchild);
}//if
}//while
printf("\n");
return OK;
}
//中序遍历二叉树T的非递归算法(第二种方法),对每个数据元素调用PrintElement函数
Status InOrderNonResusiveTraverse2(BiTree T,int(*PrintElement(TElemType)))
{
SqStack *S=(SqStack *)malloc(sizeof(SqStack));
InitStack(S);//初始化一个栈
while(T||!StackEmpty(S))//当树不为空的情况或者栈不为空的情况下
{
if(T)//如果左孩子存在
{
Push(S,T);
T=T->lchild;
}
else
{
Pop(S,&T);
if(!PrintElement(T->data))
return ERROR;
T=T->rchild;
}
}//while
printf("\n");
return OK;
}
/************************************中序非递归遍历的两种方法*************************************/
/************************************后序非递归遍历的方法*****************************************/
//后序遍历二叉树T的非递归算法(第二种方法),对每个数据元素调用PrintElement函数
/************************************后序非递归遍历的方法*****************************************/
/*层序遍历二叉树T的算法,对每个数据元素调用PrintElement函数*/
//思想是
Status LevelOrderTraverse(BiTree T,int(*PrintElement(TElemType)))
{
LinkQueue *Q=(LinkQueue *)malloc(sizeof(LinkQueue));
InitQueue(Q);
if(!T)
{
printf("空树\n");
return ERROR;
}
EnQueue(Q,T);//先将树根节点放入到队列中
BiTree *p=(BiTree *)malloc(sizeof(BiTree));
while(!QueueEmpty(Q))//如果队列不为空
{
DeQueue(Q,p);
if((*p)->lchild)
EnQueue(Q,(*p)->lchild);
if((*p)->rchild)
EnQueue(Q,(*p)->rchild);
if(!PrintElement((*p)->data))
return ERROR;
}
return OK;
}
int main()
{
printf("输入你想要构建的二叉树.(空格表示空子树)****\n");
BiTree T=(BiTree )malloc(sizeof(BiTNode));
InitBiTree(&T);
printf("初始化树为%d (1为空,0为非空)\n",BiTreeEmpty(T));
CreateBiTree(&T);
printf("构造完后树是否为空%d (1为空,0为非空)\n",BiTreeEmpty(T));
printf("树的深度为%d\n",BiTreeDepth(T));
printf("前序递归遍历为:\n");
PreOrderTraverse(T,PrintElement);
printf("\n");
printf("前序非递归遍历的第一种方法:\n");
PreOrderNonResusiveTraverse(T,PrintElement);
printf("\n");
printf("前序非递归遍历的第二种方法:\n");
PreOrderNonResusiveTraverse2(T,PrintElement);
printf("\n");
printf("递归中序遍历为:\n");
InOrderTraverse(T,PrintElement);
printf("\n");
printf("非递归中序遍历(第一种方法)为:\n");
InOrderNonResusiveTraverse2(T,PrintElement);
printf("\n");
printf("非递归中序遍历(第一种方法)为:\n");
InOrderNonResusiveTraverse2(T,PrintElement);
printf("\n");
printf("后序遍历为:\n");
PostOrderTraverse(T,PrintElement);
printf("\n");
printf("层次遍历为:\n");
LevelOrderTraverse(T,PrintElement);
printf("\n");
printf("---下面是树的函数的一些测试实例---\n");
fflush(stdin);
TElemType e2,e3;
fflush(stdin);
printf("输入 你想查看的节点的值:\n");
scanf("%c",&e2);
e3=Parent(T,e2);
printf("输入值的双亲是%c:\n",e3);
printf("输入值的左孩子是%c:\n",LeftChild(T,e2));
printf("输入值的右孩子是%c:\n",RightChild(T,e2));
printf("输入值的左兄弟是%c:\n",LeftSibling(T,e2));
printf("输入值的右兄弟是%c:\n",RightSibling(T,e2));
return 0;
}
下图是验证的二叉树图片:
这里讲一下代码过程主要遇到的几个问题:
1:在调用函数中修改传递的指针问题,看下面的代码。
//构造空二叉树
Status InitBiTree(BiTree *T)
{
*T=NULL;
return OK;
}
首先BiTree 就是指向BiTnode 类型的一个指针,在InitBiTree函数中想修改T的值,就必须传递T 的指针进去,刚开始编码的时候在这里忘记了。小卡了一下!
2:输入的问题:
根据我们定义的输入函数:
// 按先序次序输入二叉树中结点的值,构造二叉链表表示的二叉树T
void CreateBiTree(BiTree *T)
{
TElemType c;
scanf("%c",&c);
if(c==Nil)
*T=NULL;
else
{
*T=(BiTree)malloc(sizeof(BiTNode));
if(!*T)
exit(0);
(*T)->data=c;
CreateBiTree(&(*T)->lchild);//递归构造左子树
CreateBiTree(&(*T)->rchild);//递归构造右子树
}
}
因为这个构造函数是按照先序遍历构造的,所以说如果你想构造下面图中的树的时候:
你必须以下面的形式输入(#代表空格):ab#ce#fw###d##gh###,然后按回车(#再输入的过程中表示空格)
3:在写LeftChild的函数时遇到了段错误。是因为使用了p->leftchild->data 这个语句的时候没有提前判断p->lchild 这个是否为空。导致程序不能正常执行。对于这种问题,在访问节点的时候首先应该判断节点是否为空,然后才能执行某种操作。