二叉树是一种重要的数据结构.
二叉树是n(n>=0)个结点的有限集合,该集合或为空集,或由一个根结点和两棵互不相交的,分别称为根结点的左子树和右子树的二叉树组成(递归定义)
满二叉树:对于这样的一棵二叉树,如果所有分支结点都存在左右子树,且所有叶子节点都在同一层上,称这样的二叉树为满二叉树。
完全二叉树:如果一棵具有n个结点的二叉树的结构与满二叉树的前n个结点完全相同,称之为完全二叉树。
二叉树的性质:
性质1 二叉树的第i层结点数目最多为2^(i-1) (i>=1)
性质2 深度为k的二叉树至多有2^(k-1)
性质3 对于任意一棵二叉树,叶子结点(度为0)数为n0,度为2的结点个数为n2,则有n0=n2+1.
证明:n0+n1+n2=n1+2*n2+1 即结点数=分支数+1
二叉树存储结构
1.顺序存储结构 (可用数组表示)适用于满二叉树,完全二叉树,否则会有大量空间浪费
2链式存储结构 数据域+左右孩子指针表示 数据域+左右孩子指针表示+双亲指针表示
二叉树的数据域+左右孩子指针表示 还可以推广到每个结点的孩子数至多为常数k的任意类型的树,但实际中若不是所有结点都有k个孩子,则会造成空间浪费。一种巧妙的方法用来表示孩子数任意的树-----左孩子右兄弟表示法,该方法对于任意n个结点的树,只需要O(n)的存储空间。下面以二叉树的链式存储结构: 数据域+左右孩子指针表示法为例 进行二叉树的相关操作。
#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#define maximum 20
typedef struct BiTNode
{
char data;
struct BiTNode *lchild,*rchild;
}BTNode ;
typedef BTNode *BTree;
struct
{
int ln;//节点的层次编号
BTree p;//节点指针
}Qu[maximum];
//输入先序序列,创建二叉树的二叉链表
BTree CreateBTree()
{
char ch;
BTree T;
if((ch=getchar())=='#')
return(NULL);
else
{
T=(BTNode *)malloc(sizeof(BTNode));
T->data=ch;
T->lchild=CreateBTree(T->lchild);//构造左子树
T->rchild=CreateBTree(T->rchild);//构造右子树
return (T);
}
}
//根据前序遍历和中序遍历构建二叉树
BTree CreateTreeByPreIn(char *preorder,char *inorder,int length)
{
BTree root;
int rootIndex=0;
if(0==length)
return NULL;
root = (BTNode *)malloc(sizeof(BTNode));
root->data = *preorder;
for(;rootIndex<length;rootIndex++)
{
if(inorder[rootIndex]==*preorder)
break;
}
root->lchild = CreateTreeByPreIn(preorder+1,inorder,rootIndex);
root->rchild = CreateTreeByPreIn(preorder+rootIndex+1,inorder+rootIndex+1,length-rootIndex-1);
return root;
}
//先序遍历
void preorder(BTree root)
{
if(root!=NULL)
{
printf("%c",root->data);
preorder(root->lchild);
preorder(root->rchild);
}
}
//先序遍历的非递归算法
void preorder1(BTree root)
{
//BTNode *St[MaxSize],*p;
BTree St[maximum],p;
int top=-1;
if(root!=NULL)
{
top++;//根结点入栈
St[top]=root;
while(top>-1)//桟不为空时循环
{
p=St[top];//退桟并访问该结点
top--;
printf("%c",p->data);
if(p->rchild!=NULL)//右孩子入桟----顺序:先右再左入栈,出栈相反
{
top++;
St[top]=p->rchild;
}
if(p->lchild!=NULL)//左孩子入桟
{
top++;
St[top]=p->lchild;
}
}
printf("\n");
}
}
//中序遍历
void inorder(BTree root)
{
if(root)
{
inorder(root->lchild);
printf("%c",root->data);
inorder(root->rchild);
}
}
//中序遍历的非递归算法
void inorder1(BTree root)
{
//BTNode *St[MaxSize],*p;
BTree St[maximum],p;
int top=-1;
if(root!=NULL)
{
p=root;
while(top>-1||p!=NULL)//桟不为空时循环
{
while(p!=NULL)//入桟
{
top++;
St[top]=p;
p=p->lchild;
}
if(top>-1)
{
p=St[top];
top--;
printf("%c",p->data);
p=p->rchild;
}
}
printf("\n");
}
}
//后序遍历
void postorder(BTree root)
{
if(root)
{
postorder(root->lchild);
postorder(root->rchild);
printf("%c",root->data);
}
}
//后序遍历非递归算法
void postorder1(BTree root)
{
BTree St[maximum],p;
int flag,top=-1;
if(root!=NULL)
{
do
{
while(root!=NULL)
{
top++;
St[top]=root;
root=root->lchild;
}
p=NULL;//p指向当前节点的前一个访问的节点
flag=1;//设置b的访问标记为已访问过
while(top!=-1&&flag)
{
root=St[top];//取出当前的栈顶元素
if(root->rchild==p)//右子树不存在或已被访问,访问之
{
printf("%c",root->data);
top--;
p=root;//p指向刚被访问的节点
}
else
{
root=root->rchild;
flag=0;//设置未被访问的标记
}
}
}while(top!=-1);
printf("\n");
}
}
//层次遍历
void travelevel(BTree root)
{
BTree Qu[maximum];
int front,rear;
front=rear=0;
if(root!=NULL)
printf("%c",root->data);
rear++;
Qu[rear]=root;
while(rear!=front)
{
front=(front+1)%maximum;
root=Qu[front];
if(root->lchild!=NULL)
{
printf("%c",root->lchild->data);
rear=(rear+1)%maximum;
Qu[rear]=root->lchild;
}
if(root->rchild!=NULL)
{
printf("%c",root->rchild->data);
rear=(rear+1)%maximum;
Qu[rear]=root->rchild;
}
}
}
//统计二叉树叶子节点个数
int leaf_num(BTree root)
{
int L,R;
if(root==NULL)
return 0;
if(root->lchild==NULL&&root->rchild==NULL)
return 1;
L=leaf_num(root->lchild);
R=leaf_num(root->rchild);
return L+R;
}
//统计二叉树深度
int BTheight(BTree root)
{
int l_height,r_height;
if(root==NULL)
return 0;
else
{
l_height=BTheight(root->lchild);//左子树深度+1(根节点)
r_height=BTheight(root->rchild);
return l_height>r_height?(l_height+1):(r_height+1);
}
}
//统计二叉树宽度
int BTwidth(BTree root)
{
int front,rear;
int num,max,i,n;
front=rear=0;
if(root!=NULL)
{
rear++;
Qu[rear].p=root;//根节点入队
Qu[rear].ln=1;//根节点层次编号1
while(front!=rear)
{
front++;
root=Qu[front].p;//队头出队
num=Qu[front].ln;
if(root->lchild!=NULL)
{
rear++;
Qu[rear].p=root->lchild;
Qu[rear].ln=num+1;
}
if(root->rchild!=NULL)
{
rear++;
Qu[rear].p=root->rchild;
Qu[rear].ln=num+1;
}
}
max=0;num=1;i=1;
while(i<=rear)//通过比较相同层次的节点数求数的宽度
{
n=0;
while(i<=rear&&Qu[i].ln==num)
{n++;i++;}
num=Qu[i].ln;
if(n>max)
max=n;
}
return max;
}
else
return 0;
}
//输出每个从根节点到叶子节点的路径
void printArray(char a[],int len)
{
int i;
for(i=0;i<len;i++)
printf("%c",a[i]);
printf("\n");
}
void printAllPath(BTree root,char path[],int pathLen)
{
if(root == NULL)
return;
path[pathLen] = root->data;
pathLen++;
if(root->lchild == NULL && root->rchild == NULL)
printArray(path,pathLen);
else
{
printAllPath(root->lchild,path,pathLen);
printAllPath(root->rchild,path,pathLen);
}
}
void printPaths(BTree root)
{
char path[100];
printAllPath(root,path,0);
}
//二叉树镜像--每个节点的左右子树都交换了的。
BTree exchange2(BTree T)
{
BTree temp;
if(T)
{
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
exchange2(T->lchild);
exchange2(T->rchild);
}
return T;
}
//比较两棵二叉树是否相等
int CompareBTree(BTree root1,BTree root2)
{
if(root1==NULL && root2==NULL)
return 1;
else if((root1==NULL&&root2!=NULL)||(root2==NULL&&root1!=NULL))
return 0;
else if(root1->data == root2->data)
{
if(CompareBTree(root1->lchild,root2->lchild) == 1)
return CompareBTree(root1->rchild,root2->rchild);
}
}
void main()
{
BTree root1,root2;
//int height,width;
char pre_order[6]={'A','B','D','C','E','F'};
char in_order[6]={'B','D','A','E','F','C'};
printf("******************************************");
printf("\n按先序遍历和空节点#建立二叉树:");
root1 = CreateBTree();
printf("\n先序遍历-递归root1:");
preorder(root1);
printf("\n先序遍历-非递归root1:");
preorder1(root1);
printf("\n中序遍历-递归root1:");
inorder(root1);
printf("\n中序遍历-非递归root1:");
inorder1(root1);
printf("\n后序遍历-递归root1:");
postorder(root1);
printf("\n后序遍历-非递归root1:");
postorder1(root1);
printf("\n层次遍历");
travelevel(root1);
printf("\n二叉树高度和宽度和叶子节点个数:");
printf("%d,%d,%d",BTheight(root1),BTwidth(root1),leaf_num(root1));
printf("\n输出二叉树所有路径:\n");
printPaths(root1);
printf("\n******************************************");
printf("\n按先序遍历结果和中序遍历结果建立二叉树");
root2 = CreateTreeByPreIn(pre_order,in_order,6);
printf("\nroot1和root2是否相等:");
if(CompareBTree(root1,root2)==1)
printf("root1 == root2\n");
else
printf("root1 != root2\n");
}
参考:http://blog.youkuaiyun.com/sunmenggmail/article/details/7466635