一、树的定义:
1、定义:树(Tree)是n(n>=0)个节点的有限集,n=0时称为“空树”。在任意一棵非空树中:
⒈有且仅有一个特定的称为根(root)的节点。
⒉当n>1时,其余节点可分为m(m>0)个互不相交的有限集T1、T2……Tm,其中每一个集合本身又是一棵树,并且称之为根的子树(SubTree)。
2、树的节点的分类:
树的节点包含一个数据元素以及若干个指向其子树的分支。节点拥有的子树个数称为节点的度(Degree)。度为0的节点称为叶节点(Leaf);度不为0且不为根节点的节点称为“内部节点”。
3、节点间关系:
节点的子树的根称为该节点的孩子(Child),相应地,该节点称为孩子的父(Parent,或翻译成“双亲”)。同一个父节点的孩子之间互称兄弟(Sibling)。
4、层次:
节点的层次(Level)从根开始定义起,根为第一层,根的孩子为第二层,依次类推。树中节点的最大层次称为树的深度(Depth)或高度。
如果该树中节点的子树看成是从左到右有次序的,不能互换的,则称该树为有序树,否则称为无序树。
二、二叉树概念
1、定义:二叉树(BinaryTree)是n(n>=0)个节点的有限集合,该集合或者为空集(称为“空二叉树”),或者由一个根节点和两棵互不相交的、分别称为根节点的左子树和右子树的二叉树组成。
定理:任意一棵树都可以完全等价于一棵二叉树。
2、二叉树的特点:
1)每个节点最多有两棵子树,所以二叉树中不存在度大于2的节点。
2)左子树和右子树有序,不能随意颠倒。
3)即使树中某节点只有一棵子树,也要区分它是左子树还是右子树,不能混淆。
3、满二叉树:
在一棵二叉树中,如果所有分支节点都存在左子树和右子树,并且所有叶子节点都在同一层上,这样的二叉树称为满二叉树。
满二叉树的特点有:
1)叶子节点只能出现在最下面一层。出现在其他层就不可能达到平衡。
2)非叶子节点的度一定是2。
3)在同样深度的二叉树中,满二叉树的节点个数最多,叶子节点个数最多。
4、完全二叉树:
对一棵具有n个节点的二叉树按层序编号,如果编号为i(1<=i<=n)的节点与同样深度的满二叉树中编号为i的节点在二叉树中的位置完全相同,则这棵二叉树称为完全二叉树。
二、二叉树的性质
1、性质1:在二叉树的第i层上至多有2^(i-1)个节点(i>=1)。
2、性质2:深度为k的二叉树至多有2^k-1个节点(k>=1)。注意不是2^(k-1)。
3、性质3:对于任何一棵二叉树T,如果其叶子节点数为n0,度为2的节点数为n2,则n0=n2+1。
性质3的推导:
二叉树的节点的度只有3种:0、1、2。我们设其对应的节点数分别为n0、n1、n2,则二叉树的节点总数为:
Tn=n0+n1+n2
二叉树的连线数应等于节点个数减1,即
Sn=Tn-1
另一方面,二叉树的连线数应等于2*n2+n1,即
Sn=2*n2+n1
我们可得到:
n0+n1+n2-1=2*n2+n1
整理可得
n0=n2+1
三、二叉树链式存储
二叉树每个节点最多有两个孩子,所以为它涉及一个数据域和两个指针域。
lchild︱data︱rchild
其中data是数据域,lchild和rchild都是指针域,分别存放指向左孩子和右孩子的指针。
typedef struct BiTNode
{
data_tdata;
structBiTNode *lchild,*rchild;
}BiTNode,*BiTree;
四、二叉树的遍历
二叉树的遍历(traversing)是指从根节点出发,按照某种次序依次访问二叉树中所有节点,使得每个节点被且仅被访问一次。
二叉树的遍历方式有很多,常用的有前序遍历、中序遍历、后序遍历3种。
1、前序遍历(PreOrderTraverse)
规则:
⒈若二叉树为空,则不进行操作,返回
⒉访问根节点
⒊前序遍历左子树
⒋前序遍历右子树
2、中序遍历(InOrderTraverse)
规则:
⒈若二叉树为空,则不进行操作,返回
⒉中序遍历左子树
⒊访问根节点
⒋中序遍历右子树
3、后序遍历(PostOrderTraverse)
规则:
⒈若二叉树为空,则不进行操作,返回
⒉后序遍历左子树
⒊后序遍历右子树
⒋访问根节点
/*************************************************************************
@Author: wanghao
@Created Time : Fri 11 May 2018 12:54:47 AMPDT
@File Name: tree.c
@Description:
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
typedef char data_t;
typedef struct tree
{
data_tdata;
structtree *lchild;
structtree *rchild;
}Tree;
Tree *init_tree(void)
{
Tree*treenode = NULL;
treenode= (Tree *)malloc(sizeof(Tree));
if(treenode== NULL)
{
printf("Malloctree fail!\n");
returnNULL;
}
treenode->lchild= NULL;
treenode->rchild= NULL;
treenode->data= 0;
returntreenode;
}
Tree *bulid_tree(data_t data[], int i, intn)
{
intj;
Tree*tree = NULL;
tree= init_tree();
if(!tree)
{
printf("Inittree fail!\n");
returnNULL;
}
tree->data= data[i];
j= 2*i;
if(j<= n && data[j] != '0')
{
tree->lchild= bulid_tree(data, j, n);
}
else
{
tree->lchild= NULL;
}
j= 2*i + 1;
if(j<= n && data[j] != '0')
{
tree->rchild= bulid_tree(data, j, n);
}
else
{
tree->rchild= NULL;
}
returntree;
}
int pre_order_traverse(Tree *root)
{
if(root== NULL)
{
printf("Binarytree is not exist!\n");
return-1;
}
printf("%c\t",root->data);
if(root->lchild)
{
pre_order_traverse(root->lchild);
}
if(root->rchild)
{
pre_order_traverse(root->rchild);
}
}
int in_order_traverse(Tree *root)
{
if(root== NULL)
{
printf("Binarytree is not exist!\n");
return-1;
}
if(root->lchild)
{
in_order_traverse(root->lchild);
}
printf("%c\t",root->data);
if(root->rchild)
{
in_order_traverse(root->rchild);
}
}
int post_order_traverse(Tree *root)
{
if(root== NULL)
{
printf("Binarytree is not exist!\n");
return-1;
}
if(root->lchild)
{
post_order_traverse(root->lchild);
}
if(root->rchild)
{
post_order_traverse(root->rchild);
}
printf("%c\t",root->data);
}
int main(int argc, const char *argv[])
{
Tree*root;
data_tarray[] = {0,
'A',
'B', 'C',
'D','E', 0, 'F',
0,0,'G','H',0,0,'I'
};
root= bulid_tree(array, 1, sizeof(array) / sizeof(data_t));
pre_order_traverse(root);
printf("\n");
in_order_traverse(root);
printf("\n");
post_order_traverse(root);
printf("\n");
return0;
}