目录
树的基本用语
(1)节点:
树中的一个独立单元。包含一个数据元素及若干指向其子树的分支,如图5.1 b)中的A、B、C、D等。(下面术语均以上图为例来说明。)
(2)节点的度:
节点拥有的子树数称为节点的度。例如,A的度为3,C的度为1,F的度为0。
(3)树的度:
树的度是树内各节点度的最大值。图5.1(b)所示的树的度为3。
(4)叶子:
度为0的节点称为叶子或终端节点。节点K、L、F、G、M、I、J都是树的叶子。
(5)非终端节点:
度不为0的节点称为非终端节点或分支节点。除根节点之外,非终端节点也称为内部节点。
(6)双亲和孩子:
节点的子树的根称为该节点的孩子,相应地,该节点称为孩子的双亲。例如,B的双亲为A,B的孩子有E和F。
(7)兄弟:
同一个双亲的孩子之间互称兄弟。例如,H、I和J互为兄弟。
(8)祖先:
从根到该节点所经分支上的所有节点。例如,M的祖先为A、D和H。
(9)子孙:
以某节点为根的子树中的任一节点都称为该节点的子孙。如B的子孙为E、K、L和F。
(10)层次:
节点的层次从根开始定义,根为第一层,根的孩子为第二层。树中任一节点的层次等于其双亲节点的层次加1。
(11)堂兄弟:
双亲在同一层的节点互为堂兄弟。例如,节点G与E、F、H、I、为堂兄弟。
(12)树的深度:
树中节点的最大层次称为树的深度或高度。图所示的树的深度为4
(13)有序树和无序树:
如果将树中节点的各子树看成从左至右是有次序的(不能互换),称该树为有序树,否则称为无序树。在有序树中最左边的子树的根称为第一个孩子,最右边的称为最后一个孩子。
(14)森林:
m(m≥0)棵互不相交的树的集合。对树中每个节点而言,其子树的集合即为森林。由此,也可以用森林和树相互递归的定义来描述树。
二叉树的性质
1.在二叉树的第i层上最多有2 i-1 个节点
2.二叉树中如果深度为k,那么最多有2k-1个节点
3.n0=n2+1 n0表示度数为0的节点 n2表示度数为2的节点
4.在完全二叉树中,具有n个节点的完全二叉树的深度为[log2n]+1,其中[log2n]+1是向下取整。
5.若对含 n 个结点的完全二叉树从上到下且从左至右进行 1 至 n 的编号,则对完全二叉树中任意一个编号为 i 的结点
二叉树的创建及遍历
存储结构
#include<bits/stdc++.h>
using namespace std;
typedef struct Tnode{
char str;
struct Tnode *l,*r;
}Tnode,*Tree;
创建二叉树
void creat(Tree &T)//创建二叉树
{
char ch;
cout<<"请输入节点(#代表节点为空):";
cin>>ch;
if(ch=='#')
T=NULL;
else
{
T=new Tnode;//开辟空间
T->str=ch;//节点赋值
creat(T->l );//递归创建左孩子
creat(T->r );//递归创建右孩子
}
}
递归遍历
void dlr(Tree T)//先序遍历——根左右
{
if(T==NULL) return ;
cout<<T->str ;//输出根节点
dlr(T->l );//递归输出左节点
dlr(T->r );//递归输出右节点
}
void ldr(Tree T)//中序遍历——左根右
{
if(T==NULL) return ;
ldr(T->l );//递归输出左节点
cout<<T->str ;//输出根节点
ldr(T->r );//递归输出右节点
}
void lrd(Tree T)//后序遍历——左右根
{
if(T==NULL) return ;
lrd(T->l );//递归输出左节点
lrd(T->r );//递归输出右节点
cout<<T->str ;//输出根节点
}
非递归遍历
void ldr2(Tree T)
{
stack<Tree>s;
Tree p,q;
p=T;
q=new Tnode;
while(p||!s.empty())
{
if(p)
{
s.push(p);
p=p->l ;
}
else
{
q=s.top();
s.pop();
cout<<q->str;
p=q->r;
}
}
}
调试代码
#include<bits/stdc++.h>
using namespace std;
typedef struct Tnode{
char str;
struct Tnode *l,*r;
}Tnode,*Tree;
void creat(Tree &T)//创建二叉树
{
char ch;
cout<<"请输入节点(#代表节点为空):";
cin>>ch;
if(ch=='#')
T=NULL;
else
{
T=new Tnode;//开辟空间
T->str=ch;//节点赋值
creat(T->l );//递归创建左孩子
creat(T->r );//递归创建右孩子
}
}
void dlr(Tree T)//先序遍历——根左右
{
if(T==NULL) return ;
cout<<T->str ;//输出根节点
dlr(T->l );//递归输出左节点
dlr(T->r );//递归输出右节点
}
void ldr(Tree T)//中序遍历——左根右
{
if(T==NULL) return ;
ldr(T->l );//递归输出左节点
cout<<T->str ;//输出根节点
ldr(T->r );//递归输出右节点
}
void lrd(Tree T)//后序遍历——左右根
{
if(T==NULL) return ;
lrd(T->l );//递归输出左节点
lrd(T->r );//递归输出右节点
cout<<T->str ;//输出根节点
}
void ldr2(Tree T)
{
stack<Tree>s;
Tree p,q;
p=T;
q=new Tnode;
while(p||!s.empty())
{
if(p)
{
s.push(p);
p=p->l ;
}
else
{
q=s.top();
s.pop();
cout<<q->str;
p=q->r;
}
}
}
int main()
{
Tree T;
cout<<"按先序遍历建立树:"<<endl;
creat(T);
cout<<"先序遍历输出:"<<endl;
dlr(T);
cout<<endl;
cout<<"中序遍历输出:"<<endl;
ldr(T);
cout<<endl;
cout<<"后序遍历输出:"<<endl;
lrd(T);
cout<<endl;
cout<<"中序遍历非递归输出:"<<endl;
ldr2(T);
cout<<endl;
}