二叉树
二叉树可以说是最基础的一种树,下方代码涉及到二叉树的基本操作:
根据先序和中序序列创建二叉树,显示二叉树;
先序、中序、后序遍历的递归与非递归实现,层次遍历;
建立中序线索二叉树;
删除二叉树以及丰富的应用示例。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 100
#pragma warning(disable:4996)
typedef struct mybinarytree
{
char data;
struct mybinarytree *left, *right;
struct mybinarytree *pa;
int lflag,rflag;//用于建立线索二叉树
}BT;
BT *createBT(char *pre,char *in,int k);//根据先序和中序序列创建二叉树,k表示字符数目
void showTree(BT *T);//显示二叉树
int countLeaf(BT *T);//统计叶子节点的数量
void getpa(BT *T);//为pa指针赋值
void showpa(BT *T);//显示父节点
BT *copyTree(BT *T);//复制二叉树
void preTraverse(BT *T);//递归先序遍历
void inTraverse(BT *T);//递归中序遍历
void postTraverse(BT *T);//递归后序遍历
void layerVisit(BT *T);//层次遍历
void preVisit(BT *T);//非递归先序遍历
void inVisit(BT *T);//非递归中序遍历
void postVisit(BT *T);//非递归后序遍历
BT *inorder_thread(BT *T);//建立中序线索二叉树
void getInorder_thread1(BT *head);//利用线索二叉树输出正向中序序列
void getInorder_thread2(BT *head);//利用线索二叉树输出反向中序序列
BT *deleteTree(BT *T);//删除一棵树
BT *search(BT *T,char s);//查找数据为s的节点
BT *delSubtree(BT *T,char s);//删除一棵子树
int layerTraverse(BT *T);//层次遍历二叉树,逐行输出节点数据,并判断该二叉树是否为完全二叉树,如果是,返回1,否则返回0
void getPath(BT *T);//利用后序序列输出根节点到叶子节点的路径
BT *getcomAnce(BT *T,char s1,char s2);//寻找两个指定节点s1和s2(互相不为对方的祖先)最近的共同祖先,返回该祖先指针
main()
{
BT *p;
BT *T1;
BT *head;
char pre[]="ABDEFC";
char in[]="BEDFAC";
int k=strlen(pre);
T1=createBT(pre,in,k);
printf("以括号的形式显示二叉树:\n");
showTree(T1);
printf("\n叶子节点的数量为:%d\n",countLeaf(T1));
printf("\n各个节点的父指针如下:\n");
getpa(T1);
showpa(T1);
printf("\n先序遍历:\n");
preTraverse(T1);
printf("\n中序遍历:\n");
inTraverse(T1);
printf("\n后序遍历:\n");
postTraverse(T1);
printf("\n层次遍历:\n");
layerVisit(T1);
printf("\n先序遍历:\n");
preVisit(T1);
printf("\n中序遍历:\n");
inVisit(T1);
printf("\n后序遍历:\n");
postVisit(T1);
printf("\n");
printf("\n二叉树层次遍历结果:\n");
if(layerTraverse(T1))
printf("该树是完全二叉树.\n");
else
printf("该树不是完全二叉树.\n");
printf("\n根节点到各个叶子节点的路径为:\n");
getPath(T1);
p=getcomAnce(T1,'E','F');
printf("最近的共同祖先为:%c\n",p->data);
/*
T1=delSubtree(T1,'A');
printf("删除A之后:\n");
showTree(T1);
*/
//线索化之后,指针域会发生改变,所以线索化放在最后
head=inorder_thread(T1);
printf("\n正向中序序列为:\n");
getInorder_thread1(head);
printf("\n反向中序序列为:\n");
getInorder_thread2(head);
printf("\n");
}
BT *createBT(char *pre, char *in, int k)//根据先序和中序序列创建二叉树,k表示字符数目
{
int i,pos;
char data;
BT *p;
if(k==0)
return NULL;
else
{
data=pre[0];
p=(BT *)malloc(sizeof(BT));
p->data=data;
//确定data在中序序列中的位置
for (i = 0; i < k && in[i]!=data; i++);
pos=i;
p->left=createBT(pre+1,in,pos);//创建左子树
p->right=createBT(pre+pos+1,in+pos+1,k-pos-1);//创建右子树
return p;
}
}
void showTree(BT *T)//显示二叉树
{
if (T)
{
printf("%c",T->data);
if (T->left || T->right)
{
printf("(");
showTree(T->left);
printf(",");
showTree(T->right);
printf(")");
}
}
}
int countLeaf(BT *T)//统计叶子节点的数量
{
if(!T)
return 0;
else if((!T->left)&&(!T->right))
return 1;
else
return countLeaf(T->left)+countLeaf(T->right);
}
void getpa(BT *T)//为pa指针赋值
{
if (T)//进行后序处理
{
getpa(T->left);
if(T->left)
T->left->pa=T;
getpa(T->right);
if(T->right)
T->right->pa=T;
T->pa=NULL;
}
}
void showpa(BT *T)//显示父节点
{
if (T)
{
if(T->pa)
printf("%c--%c\n",T->data,T->pa->data);
else
printf("%c--NULL\n",T->data);
showpa(T->left);
showpa(T->right);
}
}
BT *copyTree(BT *T)//复制二叉树
{
BT *T1;
if(!T)
return NULL;
else
{
T1=(BT *)malloc(sizeof(BT));
T1->data=T->data;
T1->left=copyTree(T->left);
T1->right=copyTree(T->right);
return T1;
}
}
void preTraverse(BT *T)//递归先序遍历
{
if (T)//如果是空树,什么都不输出
{
printf("%c",T->data);
//递归遍历左右子树
preTraverse(T->left);
preTraverse(T->right);
}
}
void inTraverse(BT *T)//递归中序遍历
{
if (T)
{
inTraverse(T->left);
printf("%c",T->data);
inTraverse(T->right);
}
}
void postTraverse(BT *T)//递归后序遍历
{
if (T)
{
postTraverse(T->left);
postTraverse(T->right);
printf("%c",T->data);
}
}
void layerVisit(BT *T)//层次遍历
{
BT *q[N];//建立队列
int front,rear;
BT *p;
if (!T)
{
printf("树为空.\n");
return;
}
//初始化
q[0]=T;
front=0;
rear=1;
while (front != rear)
{
p=q[front];
printf("%c",p->data);
if (p->left)
{
q[rear]=p->left;
rear++;
}
if (p->right)
{
q[rear]=p->right;
rear++;
}
front++;
}
//最后不能释放q,因为内部存放的是指向树中节点的指针
}
void preVisit(BT *T)//非递归先序遍历
{
BT *t[N];//建立栈
int top;
BT *p;
if (!T)
{
printf("树为空.\n");
return;
}
//初始化
t[0]=T;
top=0;
while (top >= 0)
{
p=t[top];
printf("%c",p->data);
top--;
//孩子按照先右后左的顺序入栈
if (p->right)
{
top++;
t[top]=p->right;
}
if (p->left)
{
top++;
t[top]=p->left;
}
}
}
void inVisit(BT *T)//非递归中序遍历
{
BT *t[N];
int top=-1;
BT *p,*q;
q=T;
while (top >= 0 || q)
{
while (q)//一直向左走
{
top++;
t[top]=q;
q=q->left;
}
//弹栈(此时栈非空)
p=t[top];
printf("%c",p->data);
top--;
q=p->right;//对弹出节点的右子树进行中序遍历,可能为空
}
}
void postVisit(BT *T)//非递归后序遍历
{
BT *t[N];
int top=-1;
BT *p,*q,*pre;
q=T;//将要进行后序遍历的树的根节点
do
{
while (q)//一直向左走
{
top++;
t[top]=q;
q=q->left;
}
pre=NULL;//表示最新弹出的节点
//此时q==NULL
while (top >= 0)//弹栈
{
p=t[top];
if (p->right == pre)
{
printf("%c",p->data);
top--;
pre=p;
}
else
{
q=p->right;
break;
}
}
}while(top>=0);//若栈弹空,肯定遍历完毕
}
BT *inorder_thread(BT *T)//建立中序线索二叉树
{
BT *head;
BT *t[N];
int top=-1;
BT *p,*q,*pre;
//创建奇怪的头结点
//头结点的左指针指向根节点
//头结点的右指针指向中序序列最后一个节点
head=(BT *)malloc(sizeof(BT));
head->lflag=0;
head->rflag=1;
head->right=head;
if (!T)
{
head->left=head;
return head;
}
head->left=T;
pre=head;
q=T;//表示将要进行中序遍历的根节点
while (top >= 0 || q)
{
while (q)
{
top++;
t[top]=q;
q=q->left;
}
p=t[top];
top--;
//弹出之后,对pre和p进行线索化
if (!p->left)
{
p->lflag=1;
p->left=pre;
}
else
p->lflag=0;
if (!pre->right)
{
pre->rflag=1;
pre->right=p;
}
else
pre->rflag=0;
pre=p;//更新pre
q=p->right;
}
//对于最后一个输出的节点,现在pre指向它
//最后一个节点的左指针已经赋值
//最后一个节点的右指针指向头结点
pre->rflag=1;
pre->right=head;
head->right=pre;
return head;
}
void getInorder_thread1(BT *head)//利用线索二叉树输出正向中序序列
{
BT *p=head->left;//p初始值为根节点
while (p != head)
{
while (p->lflag == 0)
p = p->left;
while (p->rflag == 1 && p->right != head)
{
printf("%c ", p->data);
p = p->right;
}
//将其看作是某个根节点,其左子树已全部输出
//输出根节点,转向右子树
printf("%c ", p->data);
p = p->right;//如果p是最后一个输出节点,p->right==head;
}
}
void getInorder_thread2(BT *head)//利用线索二叉树输出反向中序序列
{
BT *p=head->right;
while (p != head)
{
while (p->rflag == 0)
p=p->right;
while (p->lflag == 1 && p->left != head)
{
printf("%c ",p->data);
p=p->left;
}
//将其看作是某个根节点,其右子树已全部输出
//输出根节点,转向左子树
printf("%c ",p->data);
p=p->left;//如果是第一个节点,p->left==head;
}
}
BT *deleteTree(BT *T)//删除一棵树
{
if (T)
{
T->left=deleteTree(T->left);
T->right=deleteTree(T->right);
free(T);
}
return NULL;
}
BT *search(BT *T, char s)//查找数据为s的节点
{
BT *left,*right;
if(!T)
return NULL;
else if(T->data==s)
return T;
else
{
left=search(T->left,s);
right=search(T->right,s);
if(left)
return left;
else
return right;
}
}
BT *delSubtree(BT *T, char s)//删除一棵子树
{
BT *obj,*pa;
obj=search(T,s);
if(!obj)
return T;
else if(obj==T)
return deleteTree(T);
else
{
pa=obj->pa;
if(pa->left==obj)
pa->left=deleteTree(obj);
else
pa->right=deleteTree(obj);
return T;
}
}
int layerTraverse(BT *T)//层次遍历二叉树,逐行输出节点数据,并判断该二叉树是否为完全二叉树,如果是,返回1,否则返回0
{
BT *q[N];
int front,rear,layerfir;//记录每层的起始位置(从第二层开始)
BT *p;
int n0;//指示是否有空节点入队
int flag;//指示是否为完全二叉树
if (!T)
{
printf("树为空.\n");
return 1;
}
n0=0;
flag=1;//假设为完全二叉树
q[0]=T;
front=0;
rear=1;
layerfir=1;
while (front != rear)
{
p=q[front];
front++;
printf("%c ",p->data);
if (p->left)
{
if(n0==1)//如果之前有空节点入队,表示不是完全二叉树
flag=0;
q[rear]=p->left;
rear++;
}
else
n0=1;
if (p->right)
{
if(n0==1)
flag=0;
q[rear]=p->right;
rear++;
}
else//表示有空节点入队
n0=1;
if (front == layerfir)
{
printf("\n");
layerfir=rear;
}
}
return flag;
}
void getPath(BT *T)//利用后序序列输出根节点到叶子节点的路径
{
int i;
BT *t[N];
int top=-1;
BT *p,*q,*pre;
//初始化
q=T;
do {
while (q)
{
top++;
t[top]=q;
q=q->left;
}
pre=NULL;
while (top >= 0)
{
p=t[top];
if (p->right == pre)//表示可以弹栈
{
top--;
if ((!p->left) && (!p->right))
{
for(i=0;i<=top;i++)
printf("%c-->",t[i]->data);
printf("%c\n",p->data);
}
pre=p;
}
else
{
q=p->right;
break;
}
}
}while(top>=0);
}
BT *getcomAnce(BT *T, char s1, char s2)//寻找两个指定节点s1和s2(互相不为对方的祖先)最近的共同祖先,返回该祖先指针
{
BT *t[N],*t1[N];
int top=-1;
BT *p,*q,*pre;
int i,k;
int flag=0;
q=T;
do {
while (q)
{
top++;
t[top]=q;
q=q->left;
}
pre=NULL;
while (top >= 0)
{
p=t[top];
if (p->right == pre)
{
top--;
if (p->data == s1 || p->data == s2)
{
flag++;
if (flag == 1)
{
k=top;
for(i=0;i<=top;i++)//转移祖先
t1[i]=t[i];
}
if (flag == 2)//可以开始比较
{
for(i=0;i<=top && i<=k && t[i]==t1[i];i++);
return t[i-1];
}
}
pre=p;
}
else
{
q=p->right;
break;
}
}
}while(top>=0);
}