树的概念
树(Tree)是n(n>=0)个结点的有限集。n=0的时候称为空树,在任意一颗非空树中:(1)有且仅有一个特定的称为根(root)的结点;(2)当n>1时,其余结点可以分为m(m>0)个互不相交的有限集T1、T2、T3…Tm,其中,每一个集合本身又是一棵树,并且称为跟的子树。
- 结点
树的结点包含一个数据元素及若干个指向其子树的分支。
*度
结点拥有的子树称为结点的度。
*叶结点
度为0的结点称为叶结点或者终端结点。
*分支结点
度不为0的结点称为非终端结点或者分支结点。
*孩子、双亲
结点的子树的跟称为该结点的孩子,相应的,该结点称为孩子的双亲。
*深度
树中结点最大层次称为树的深度。
二叉树
二叉树是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两颗互不相交的、分别称为根结点的左子树和右子树的二叉树组成。(通俗地讲就是一个结点最多有两个分支)
二叉树的特点
1.每个结点最多有两棵子树,所以二叉树中不存在度大于2的结点。
2.左子树和右子树是有顺序的,次序不能任意颠倒。
3.即使树中某结点只有一棵子树,也要区分它是左子树还是右子树。
二叉树的性质
1.在二叉树的第i层上至多有 2^(i - 1) 个结点
2.深度为k的二叉树至多有 2^k -1个结点
3.对任何一棵二叉树T,如果其终端结点数为n,度为2的结点数为m,则n=m+1
4.具有n个结点的完全二叉树的深度为 log2(n) + 1
二叉树的遍历
1、先序遍历
若二叉树为空, 则空操作返回,否则先访问根结点,然后先序遍历左子树,再先序遍历右子树,如图:ABDGHCEI
2、中序遍历
若树为空,则空操作返回,否则从根结点开始(注意并不是访问根结点),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树,如图:GDHBAEICF
3、后序遍历
若树为空,则空操作返回,否则从左到右,先叶子后结点的方式遍历访问左右子树,最后是访问根结点,如图:GHDBIEFCA
下面,我们用程序来实现二叉树的三种遍历:
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 10
typedef struct node
{
int data;
struct node *left, *right;
}TreeNode;
TreeNode *CreateTree (int *a, int len)
{
int i;
TreeNode *node[100] = {0};
for (i = 0; i < len; i++)
{
node[i] = (TreeNode *)malloc(sizeof(TreeNode));
if (NULL == node[i])
{
return NULL;
}
node[i]->data = a[i];
node[i]->left = NULL;
node[i]->right = NULL;
}
for (i = 0; i < len / 2; i++)
{
node[i]->left = node[2 * i + 1];
node[i]->right = node[2 * i + 2];
}
return node[0];
}
void PreOrderTree(TreeNode *R)
{
if (NULL == R)
{
return;
}
printf("%d ", R->data);
PreOrderTree(R->left); //递归调用
PreOrderTree(R->right);
}
void MidOrderTree(TreeNode *R)
{
if (NULL == R)
{
return;
}
MidOrderTree(R->left);
printf("%d ", R->data);
MidOrderTree(R->right);
}
void BackOrderTree(TreeNode *R)
{
if (NULL == R)
{
return;
}
BackOrderTree(R->left);
BackOrderTree(R->right);
printf("%d ", R->data);
}
int main()
{
int a[MAXSIZE] = {0};
int i;
int length = sizeof(a) / sizeof(a[0]);
TreeNode *Root = NULL;
printf("Please input 10 number:\n");
for (i = 0; i < MAXSIZE; i++)
{
scanf("%d", &a[i]);
}
/* 初始化一颗二叉树 */
Root = CreateTree(a, length);
/* 树的三种遍历 */
printf("先序遍历:\n");
PreOrderTree(Root);
printf("\n\n");
printf("中序遍历:\n");
MidOrderTree(Root);
printf("\n\n");
printf("后序遍历:\n");
BackOrderTree(Root);
printf("\n\n");
return 0;
}