什么是二叉树?!
二叉树是每个结点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
首先让我们了解一些树的术语吧!
树的结点(node) | 包含一个数据元素及若干指向子树的分支; |
---|---|
孩子结点(child node) | 结点的子树的根称为该结点的孩子; |
双亲结点 | B 结点是A 结点的孩子,则A结点是B 结点的双亲; |
兄弟结点 | 同一双亲的孩子结点; 堂兄结点:同一层上结点; |
祖先结点 | 从根到该结点的所经分支上的所有结点 |
子孙结点 | 以某结点为根的子树中任一结点都称为该结点的子孙 |
结点层 | 根结点的层定义为1;根的孩子为第二层结点,依此类推; |
树的深度 | 树中最大的结点层 |
结点的度 | 结点子树的个数 |
树的度 | 树中最大的结点度。 |
叶子结点 | 也叫终端结点,是度为 0 的结点; |
分枝结点 | 度不为0的结点; |
有序树 | 子树有序的树,如:家族树; |
无序树 | 不考虑子树的顺序; |
(看吧,兄弟姐妹,子孙祖先,活像一个族谱,,,,这命名的也特别有意思)。。。
二叉树的七大性质:
1、 在非空二叉树中,第i层的结点总数不超过(2^i - 1),( i>=1);
2、深度为k的二叉树最多有(2^k - 1)个结点(k>=1),最少有k个结点;
3、对于任意一棵二叉树,如果其叶结点数为N0,而度数为2的结点总数为N2,则 N0=N2+1;(各位同学注意一下该公式的推导过程,可以对你理解二叉树有很大的帮助哦!)
( #这里插放一下完全二叉树和满二叉树的概念:
满二叉树:
深度为k且含有2^k-1个结点的二叉树。
其特点为:每一层上的结点数都是最大结点数,即每一层 i 的结点数都具有最大值2^k - 1.
完全二叉树:
深度为 k 的有 n 个结点的二叉树,当且仅当其每一个结点都与深度为 k 的满二叉树中编号从 1 至 n 的结点一一对应时,称之为完全二叉树。
完全二叉树有两个特点:
(1)、叶子结点只可能在层次最大的两层出现。
(2)、对任一结点,若其右分支下的子孙的最大层次为 l ,则其左分支下的子孙最大层次必为 l 或 l+1.
)
4、 具有n个结点的完全二叉树的深度为
(注:[ ]表示向下取整)
5、有N个结点的完全二叉树各结点如果用顺序方式存储,则结点之间有如下关系:
(1)、若I为结点编号则 如果I>1,则其父结点的编号为I/2;
(2)、如果2I<=N,则其左孩子(即左子树的根结点)的编号为2I;若2I>N,则无左孩子;
(3)、如果2I+1<=N,则其右孩子的结点编号为2I+1;若2I+1>N,则无右孩子。
6、给定N个节点,能构成h(N)种不同的二叉树。h(N)为卡特兰数的第N项。h(n)=C(2*n,n)/(n+1)。
7、设有i个枝点,I为所有枝点的道路长度总和,J为叶的道路长度总和 J=I+2i [2]
二叉树的链式存储
typedef struct BiTnode
{
int data;//当然,你这里可以放你想要的数据
struct BiTnode *lchild, *rchild;
}BiTnode, *Bitree;
首先是遍历二叉树问题
遍历二叉树分为先序遍历、中序遍历和后序遍历(说白了,这个前中后是根据访问结点的顺序不同而命名的,其次就是遍历左子树位于遍历右子树之前,是不是很容易理解呢?!)
先序遍历:
(1)、访问根节点。
(2)、先序遍历左子树。
(3)、先序遍历右子树。
void first(Bitree T)
{
if(T)
{
cout << T->data;//这里你可以选择保存数据,,,
first(T->lchild);//递归先序遍历左子树
first(T->rchild);//递归先序遍历右子树
}
}
中序遍历:
(1)、中序遍历左子树。
(2)、访问根节点。
(3)、中序遍历右子树。
void middle(Bitree T)
{
if(T)
{
middle(T->lchild);
cout << T->data;//这里你可以选择保存数据,,,
middle(T->rchild);
}
}
后序遍历:
(1)、后序遍历左子树。
(2)、后序遍历右子树。
(3)、访问根结点。
(那么,聪明的读者,后序遍历的代码你们已经知道了嘛?!)
下面是先序遍历创建二叉链表
void CreatBitree(Bitree &T)
{
char ch;
cin >> ch;
if(ch == '#')//若ch为 # ,则二叉树为空树。
T = NULL;
else
{
T = (BiTnode *)malloc(sizeof(BiTnode));
T->data = ch;
CreatBitree(T->lchild);//递归先序创建左子树
CreatBitree(T->rchild);//递归先序创建右子树
}
}
(中序和后序请读者认真思考一下这么敲吧!这里就不给出来了)
此时输入“ABC##DE#G##F###” 即可得到一颗二叉树,图如下(自己画的,比较丑,,,,)
复制二叉树:
void Copy(Bitree T, Bitree &newT)//新树newT
{
if(T == NULL)
{
newT = NULL;
return ;
}
else
{
newT = (BiTnode *)malloc(sizeof(BiTnode));
newT->data = T->data;
Copy(T->lchild, newT->lchild);//复制左子树
Copy(T->rchild, newT->rchild);//复制右子树
}
}
计算二叉树的深度:
int depth(Bitree T)
{
int m, n;
if(T == NULL)
return 0;
else
{
m = depth(T->lchild);//搜左子树
n = depth(T->rchild);//搜右子树
return m>n ? m+1 : n+1;//加上根结点
}
}
统计二叉树中结点的个数:
int Nodecount(Bitree T)
{
if(T == NULL)//如果是空树,则结点个数为0,递归结束
return 0;
else
return Nodecount(T->lchild)+Nodecount(T->rchild)+1;
// 否则结点个数为左子树的结点个数+右子树的结点个数+1(根结点)
}
求叶子结点的个数:
int yezi(Bitree T)
{
int x = Nodecount(T);//先找根结点,如果不止一个结点的话
if(x > 1)
if(T == NULL)
return 0;
else if(T->lchild == NULL && T->rchild == NULL)//左右为空,证明的叶子结点,返回1.
return 1;
else
return yezi(T->lchild)+yezi(T->rchild);
else //否则它就是根节点,无叶子结点
return 0;
}
好了,恶心的递归就到此结束了,但是,算法肯定不止一种,而且你考研也不会让你递归写树或者遍历,所以,有一种用栈(stack)来模拟的,这个嘛,,我下次写吧,先用着递归。,,,,,,,,,哦,还有线索树。。。