一、二叉树的实现
二叉树是计算机一个重要的结构,许多复杂算法都是由二叉树演变而来,其具有的性质和树相类似,但注意:二叉树和树不是同一个概念,他的孩子有左右之分。在二叉树的代码实现中,可以利用栈来实现,递归可以快速地生成二叉树,并且代码较简洁,但许多公司的面试题会考到二叉树的非递归实现方法,下面我用栈这个数据结构实现二叉树的构建,先序、中序、后序遍历以及销毁。这里需要C语言的指针掌握。
二、二叉树利用到的数据结构:
1.二叉树数据结构:
typedef struct TNode
{
ElemType data; //数据域
struct TNode *lchild; //左孩子指针
struct TNode *rchild; //右孩子指针
}BinaryTree,*BiTreePoint;
2.链栈数据结构:
typedef struct SNode
{
BiTreePoint *data;
struct SNode *next;
}StackNode,*StackPoint; //栈结点数据结构,注意这里的数据域我们用到一个二维指针,用来保存二叉树的结点指针
typedef struct
{
int StackSize;
StackPoint base;
StackPoint top;
}StackHead,*StackHeadPoint; //栈头信息数据结构
3.队列数据结构:
typedef struct QNode
{
BiTreePoint *data;
struct QNode *next;
}QueueNode,*QueuePoint;
typedef struct
{
int QueueSize;
QueuePoint front;
QueuePoint rear;
}QueueHead,*QueueHeadPoint;
三、二叉树的方法
1.二叉树的构建:
这里我们利用栈的数据结构先序构造二叉树,使用时注意指针的传递
BiTreePoint CreatBiTree() //非递归先序构造二叉树
{
BiTreePoint *temp,T;
ElemType ch;
StackHeadPoint Head=InitStack();
temp=&T;
do
{
ch=getchar();
getchar();
if(ch=='^')
(*temp)=NULL;
else
{
(*temp)=(BiTreePoint)malloc(sizeof(BinaryTree));
if(*temp==NULL)
{
printf("对不起,系统内存不足,子树构造失败,请扩容!\n");
system("pause");
}
(*temp)->data=ch;
StackPush(&Head,&(*temp)->rchild);
StackPush(&Head,&(*temp)->lchild);
}
temp=getTop(&Head);
}while(!StackEmpty(Head) && StackPop(&Head));
StackDelete(&Head);
return T;
}
2.二叉树的遍历:
其中,先序遍历和中序遍历结构较为类似,而后序遍历则比较难操作,以下采用两种方法。当然,方法不一,网上还有另解。后序遍历方法1则是利用一个标记flag,代码逻辑如下:
if Point!=NULL ^ Point not visit
visit Point.left;
else
if Point is Point.parent.left
Point=Point.parent.right;
else
do:
Point=stack.pop;
visit Point;
loop until Point is Point.parent.left;
而后序遍历的方法2则是每次把孩子指针进栈,用一个before指针记录之前操作完的结点,即可以将它理解为前一步操作完的子树的根(root),每次什么时候可以输出呢?即你发现叶子结点,或者你发现栈顶结点的所有孩子结点操作完之后。接着按层遍历使用到队列,先进先出的特性就可以一层一层地扫描二叉树。
Status PreOrderTraverse(BiTreePoint T) //非递归先序遍历方法
{
BiTreePoint *temp;
StackHeadPoint Head=InitStack();
temp=&T;
while(*temp || !StackEmpty(Head))
{
if(*temp)
{
printf("%c",(*temp)->data);
if(!StackPush(&Head,temp))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
temp=&(*temp)->lchild;
}
else
{
temp=getTop(&Head);
StackPop(&Head);
temp=&(*temp)->rchild;
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status InOrderTraverse(BiTreePoint T) //非递归中序遍历方法
{
BiTreePoint *temp;
StackHeadPoint Head=InitStack();
temp=&T;
while(*temp || !StackEmpty(Head))
{
if(*temp)
{
if(!StackPush(&Head,temp))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
temp=&(*temp)->lchild;
}
else
{
temp=getTop(&Head);
printf("%c",(*temp)->data);
StackPop(&Head);
temp=&(*temp)->rchild;
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status PostOrderTraverse(BiTreePoint T) //非递归后序遍历方法
{
BiTreePoint *temp;
Status flag=1;
StackHeadPoint Head=InitStack();
if(T==NULL || !StackPush(&Head,&T))
{
printf("\n");
return OK;
}
temp=&T->lchild;
while(!StackEmpty(Head))
{
if(*temp && flag)
{
if(!StackPush(&Head,temp))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
temp=&(*temp)->lchild;
}
else if(temp==&(*(getTop(&Head)))->lchild)
{
temp=&(*(getTop(&Head)))->rchild;
flag=1;
}
else
{
temp=getTop(&Head);
StackPop(&Head);
printf("%c",(*temp)->data);
while(temp!=&T && temp==&(*(getTop(&Head)))->rchild)
{
temp=getTop(&Head);
StackPop(&Head);
printf("%c",(*temp)->data);
}
flag=0;
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status PostOrderTraverse2(BiTreePoint T) //非递归后序遍历方法2
{
BiTreePoint *temp,*before;
StackHeadPoint Head=InitStack();
if(T==NULL || !StackPush(&Head,&T))
{
printf("\n");
return OK;
}
before=NULL;
while(!StackEmpty(Head))
{
temp=getTop(&Head);
if( (*temp)->lchild==NULL && (*temp)->rchild==NULL || before && (before==&(*temp)->lchild || before==&(*temp)->rchild) )
{
printf("%c",(*temp)->data);
StackPop(&Head);
before=temp;
}
else
{
if((*temp)->rchild)
{
if(!StackPush(&Head,&(*temp)->rchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
if((*temp)->lchild)
{
if(!StackPush(&Head,&(*temp)->lchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status LevelOrderTraverse(BiTreePoint T) //按层遍历方法
{
BiTreePoint *temp;
QueueHeadPoint Head=InitQueue();
if(T==NULL || !QueuePush(&Head,&T))
{
printf("\n");
return OK;
}
while(!QueueEmpty(Head))
{
temp=getFront(&Head);
QueuePop(&Head);
printf("%c",(*temp)->data);
if((*temp)->lchild)
{
if(!QueuePush(&Head,&(*temp)->lchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
if((*temp)->rchild)
{
if(!QueuePush(&Head,&(*temp)->rchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
}
QueueDelete(&Head);
printf("\n");
return OK;
}
具体实现代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<windows.h>
//******宏定义参数******
#define NO 0
#define OK 1
#define EORRO 0
//******定义数据类型别名******
typedef char ElemType;
typedef int Status;
//******声明数据结构******
typedef struct TNode
{
ElemType data;
struct TNode *lchild;
struct TNode *rchild;
}BinaryTree,*BiTreePoint;
typedef struct SNode
{
BiTreePoint *data;
struct SNode *next;
}StackNode,*StackPoint;
typedef struct
{
int StackSize;
StackPoint base;
StackPoint top;
}StackHead,*StackHeadPoint;
typedef struct QNode
{
BiTreePoint *data;
struct QNode *next;
}QueueNode,*QueuePoint;
typedef struct
{
int QueueSize;
QueuePoint front;
QueuePoint rear;
}QueueHead,*QueueHeadPoint;
//******以下为链栈的数据结构操作******
StackHeadPoint InitStack()
{
StackHeadPoint Head=(StackHeadPoint)malloc(sizeof(StackHead));
Head->StackSize=0;
Head->base=Head->top=(StackPoint)malloc(sizeof(StackNode));
return Head;
}
Status StackEmpty(StackHeadPoint Head)
{
if(Head->base == Head->top)
return OK;
return NO;
}
BiTreePoint* getTop(StackHeadPoint *Head)
{
if(StackEmpty(*Head))
return NULL;
return (*Head)->top->next->data;
}
Status StackPush(StackHeadPoint *Head,BiTreePoint *data)
{
StackPoint p=(StackPoint)malloc(sizeof(StackNode));
if(p==NULL)
{
printf("对不起,系统内存不足!入栈失败!\n");
return NO;
}
(*Head)->top->data=data;
p->next=(*Head)->top;
(*Head)->top=p;
(*Head)->StackSize++;
return OK;
}
Status StackPop(StackHeadPoint *Head)
{
StackPoint p=(*Head)->top;
if(StackEmpty(*Head))
return NO;
(*Head)->top=p->next;
(*Head)->StackSize--;
free(p);
return OK;
}
Status StackDelete(StackHeadPoint *Head)
{
while(!StackEmpty(*Head))
StackPop(Head);
free((*Head)->base);
return OK;
}
//******以上为链栈数据结构操作******
//******以下为链队列数据结构操作******
QueueHeadPoint InitQueue()
{
QueueHeadPoint Head=(QueueHeadPoint)malloc(sizeof(QueueHead));
Head->QueueSize=0;
Head->front=Head->rear=(QueuePoint)malloc(sizeof(QueueNode));
Head->rear->next=NULL;
return Head;
}
Status QueueEmpty(QueueHeadPoint Head)
{
if(Head->front == Head->rear)
return OK;
return NO;
}
BiTreePoint* getFront(QueueHeadPoint *Head)
{
if(QueueEmpty(*Head))
return NULL;
return (*Head)->front->next->data;
}
Status QueuePush(QueueHeadPoint *Head,BiTreePoint *data)
{
QueuePoint p=(QueuePoint)malloc(sizeof(QueueNode));
if(p==NULL)
{
printf("对不起,系统内存不足!入栈失败!\n");
return NO;
}
p->data=data;
p->next=(*Head)->rear->next;
(*Head)->rear->next=p;
(*Head)->rear=p;
(*Head)->QueueSize++;
return OK;
}
Status QueuePop(QueueHeadPoint *Head)
{
QueuePoint p=(*Head)->front;
if(QueueEmpty(*Head))
return NO;
(*Head)->front=p->next;
(*Head)->QueueSize--;
free(p);
return OK;
}
Status QueueDelete(QueueHeadPoint *Head)
{
while(!QueueEmpty(*Head))
QueuePop(Head);
free((*Head)->front);
return OK;
}
//******以上为链队列数据结构操作******
//******以下为二叉树数据结构操作******
BiTreePoint InitBiTree()
{
return NULL;
}
Status BiTreeEmpty(BiTreePoint T)
{
if(T==NULL)
return OK;
return NO;
}
void DestroyBiTree(BiTreePoint* T) //非递归销毁二叉树
{
StackHeadPoint Head=InitStack();
BiTreePoint *temp;
if(BiTreeEmpty(*T))
{
printf("该二叉树已空!\n");
return ;
}
StackPush(&Head,T);
while(!StackEmpty(Head))
{
temp=getTop(&Head);
StackPop(&Head);
if(!BiTreeEmpty((*temp)->lchild)) StackPush(&Head,&(*temp)->lchild);
if(!BiTreeEmpty((*temp)->rchild)) StackPush(&Head,&(*temp)->rchild);
free(*temp);
}
StackDelete(&Head);
return ;
}
BiTreePoint CreatBiTree() //非递归先序构造二叉树
{
BiTreePoint *temp,T;
ElemType ch;
StackHeadPoint Head=InitStack();
temp=&T;
do
{
ch=getchar();
getchar();
if(ch=='^')
(*temp)=NULL;
else
{
(*temp)=(BiTreePoint)malloc(sizeof(BinaryTree));
if(*temp==NULL)
{
printf("对不起,系统内存不足,子树构造失败,请扩容!\n");
system("pause");
}
(*temp)->data=ch;
StackPush(&Head,&(*temp)->rchild);
StackPush(&Head,&(*temp)->lchild);
}
temp=getTop(&Head);
}while(!StackEmpty(Head) && StackPop(&Head));
StackDelete(&Head);
return T;
}
Status PreOrderTraverse(BiTreePoint T) //非递归先序遍历方法
{
BiTreePoint *temp;
StackHeadPoint Head=InitStack();
temp=&T;
while(*temp || !StackEmpty(Head))
{
if(*temp)
{
printf("%c",(*temp)->data);
if(!StackPush(&Head,temp))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
temp=&(*temp)->lchild;
}
else
{
temp=getTop(&Head);
StackPop(&Head);
temp=&(*temp)->rchild;
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status InOrderTraverse(BiTreePoint T) //非递归中序遍历方法
{
BiTreePoint *temp;
StackHeadPoint Head=InitStack();
temp=&T;
while(*temp || !StackEmpty(Head))
{
if(*temp)
{
if(!StackPush(&Head,temp))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
temp=&(*temp)->lchild;
}
else
{
temp=getTop(&Head);
printf("%c",(*temp)->data);
StackPop(&Head);
temp=&(*temp)->rchild;
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status PostOrderTraverse(BiTreePoint T) //非递归后序遍历方法
{
BiTreePoint *temp;
Status flag=1;
StackHeadPoint Head=InitStack();
if(T==NULL || !StackPush(&Head,&T))
{
printf("\n");
return OK;
}
temp=&T->lchild;
while(!StackEmpty(Head))
{
if(*temp && flag)
{
if(!StackPush(&Head,temp))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
temp=&(*temp)->lchild;
}
else if(temp==&(*(getTop(&Head)))->lchild)
{
temp=&(*(getTop(&Head)))->rchild;
flag=1;
}
else
{
temp=getTop(&Head);
StackPop(&Head);
printf("%c",(*temp)->data);
while(temp!=&T && temp==&(*(getTop(&Head)))->rchild)
{
temp=getTop(&Head);
StackPop(&Head);
printf("%c",(*temp)->data);
}
flag=0;
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status PostOrderTraverse2(BiTreePoint T) //非递归后序遍历方法2
{
BiTreePoint *temp,*before;
StackHeadPoint Head=InitStack();
if(T==NULL || !StackPush(&Head,&T))
{
printf("\n");
return OK;
}
before=NULL;
while(!StackEmpty(Head))
{
temp=getTop(&Head);
if( (*temp)->lchild==NULL && (*temp)->rchild==NULL || before && (before==&(*temp)->lchild || before==&(*temp)->rchild) )
{
printf("%c",(*temp)->data);
StackPop(&Head);
before=temp;
}
else
{
if((*temp)->rchild)
{
if(!StackPush(&Head,&(*temp)->rchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
if((*temp)->lchild)
{
if(!StackPush(&Head,&(*temp)->lchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
}
}
StackDelete(&Head);
printf("\n");
return OK;
}
Status LevelOrderTraverse(BiTreePoint T) //按层遍历方法
{
BiTreePoint *temp;
QueueHeadPoint Head=InitQueue();
if(T==NULL || !QueuePush(&Head,&T))
{
printf("\n");
return OK;
}
while(!QueueEmpty(Head))
{
temp=getFront(&Head);
QueuePop(&Head);
printf("%c",(*temp)->data);
if((*temp)->lchild)
{
if(!QueuePush(&Head,&(*temp)->lchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
if((*temp)->rchild)
{
if(!QueuePush(&Head,&(*temp)->rchild))
{
printf("对不起,当前系统内存不足,二叉树遍历失败!\n");
return NO;
}
}
}
QueueDelete(&Head);
printf("\n");
return OK;
}
//******以上为二叉树数据结构操作******
int main()
{
BiTreePoint T;
printf("请先序构建二叉树(^:表示空,换行表示结点一个输入完毕!):\n");
T=CreatBiTree();
printf("该树的先序遍历为:\n");
PreOrderTraverse(T);
printf("该树的中序遍历为:\n");
InOrderTraverse(T);
printf("该树的后序遍历为:\n");
PostOrderTraverse(T);
printf("该树的后序序遍历2为:\n");
PostOrderTraverse2(T);
printf("该树的按层遍历为:\n");
LevelOrderTraverse(T);
DestroyBiTree(&T);
printf("二叉树销毁成功!\n");
return 0;
}
总结:
二叉树的C语言实现考察了之前的链表、栈、队列,以及基础的指针方法,在C++的STL中有封装好的类使用。其理论思想是今后深度优先搜索,广度优先搜索,以及图的一些东西的基础。可以利用其实现哈弗曼树、线索二叉树等等。