二叉树的定义
首先需要知道什么是树,树是一种由顶点和边构成的一种数据结构。可以这样来定义满足连通,且边数等于定点数减一的结构就是树。在一棵树中只有一个根节点,并且树中一定是不存在环的。
二叉树的定义,这里给出二叉树的递归定义:
- 要么二叉树没有根节点,是一棵空树
- 要么二叉树是由根节点,左子树,右子树组成,且左子树和右子树又是一个二叉树
树的性质
- 树可以没有结点,这样的树叫作空树。
- 结点的度:在一棵树中结点的子树棵树叫作度,树的度是指这棵树的结点中最大的度。
- 结点的深度:结点的深度是指从根节点开始(深度为1)自顶向下逐层累加到达该结点时的深度值。树的深度是指这棵树的结点中的最大深度。
- 结点的高度:结点的高度是指从最底层的叶子结点(高度为1)开始自底向上逐层累加到该结点的高度值。树的高度是指这棵树中的所有结点的高度的最大值。
二叉树的性质
满二叉树:是指树的每一层的结点数都达到了该层所能达到的结点数的最大值。如下图就是一棵满二叉树。
完全二叉树:是指除了最下面一层外,其余层的结点数都达到了该层所能达到的最大结点数。且最下面一层结点是从左到右连续存在,而这些连续存在的结点的右边的结点全部都不存在。
二叉树的应用
树的存储
对于二叉树,一般用链表的方式来存储,定义一个结构体来表示树的结点。
struct node{
node* lchild;
node* rchild;
int data;
}
在程序设计中,也会经常用到静态链表来存储树,就是用数组来表示树.(这种存储方式适用于一般的树)。这个时候需要在开始的时候开一个足够大的数组来存放所有的结点。
struct node{
int data;
vector<int>child;
}Node[maxn];
树的遍历
二叉树的遍历是二叉树最基本的应用之一,遍历方式有:先序遍历(根左右),中序遍历(左根右),后序遍历(左右根)和层序遍历。代码如下:
//先序
void preOrder(node* root){
if(root==NULL) return;
printf("%d",root->data);
preOrder(root->lchild);
preOrder(root->rchild);
}
//中序
void inOrder(node* root){
if(root==NULL)return;
inOrder(root->lchild);
printf("%d",root->data);
inOrder(root->rchild);
}
//后序
void postOrder(node* root){
if(root == NULL)return;
postOrder(root->left);
postOrder(root->right);
printf("%d",root->data);
}
//层序
void layerOrder(node* root){
queue<node*>Q;
Q.push(root);
while(!Q.empty()){
node* now = Q.front();
Q.pop();
printf("%d",now->data);
if(now->lchild != NULL) Q.push(now->lchild);
if(now->rchild != NULL) Q.push(now->rchild);
}
}
建立二叉树
当已知了一棵树的中序序列后,只需要再知道它的先序或者是后序序列,就可以确定唯一棵二叉树。下面给出一直先序和中序确定二叉树的代码
const int maxn = 100;
char pre[maxn],in[maxn],post[maxn];
struct node{//树的结点
node* lchild;
char data;
node* rchild;
};
//返回二叉树的根节点地址
node* create(int preL, int preR, int inL, int inR){
if(preL > preR) return NULL; //结束条件
node* root = new node;
root->data = pre[preL];//根节点的数据域
int k; //用来记录根节点在中序序列中的位置
for(k=inL;k<=inR;k++){
if(pre[preL] == in[k])
break;
}
int leftNum = k - inL; //计算出左子树节点总数
//左子树在先序的区间为[preL+1,preL+leftNum],在中序的区间为[inL,k-1]
root->lchild = create(preL+1,preL+leftNum,inL,k-1);
//右子树在先序的区间为[preL+leftNum+1,preR],在中序的区间为[k+1,inR]
root->rchild = create(preL+leftNum+1,preR,k+1,inR);
return root;
}
树的深度,节点数目计算
深度的计算
#include<cstdio>
#include<queue>
#include<vector>
const int maxn = 10000;
//计算树的深度,一种方法是在建树的过程中对每个节点都增加一个记录深度的变量
struct node{
int layer; //层号
vector<int>child;
}Node[maxn];
//层序
void layerOrder(int root){
queue<int>Q;
Node[root].layer = 1;
Q.push(root);
while(!Q.empty()){
int top = Q.front();
Q.pop();
for(int i=0; i<Node[top].child.size(); i++){
int child = Node[top].child[i];
Node[child].layer = Node[top].layer+1;
Q.push(child);
}
}
}
//
int main(){
int n;
scanf("%d",&n);
int a,b;
for(int i=0; i<n-1; i++){
scanf("%d%d",&a,&b);
Node[a].child.push_back(b);
}
layerOrder(1);
int height = 0;
for(int i=1; i<=n; i++){
height = max(height,Node[i].layer);
}
printf("%d",height);
return 0;
}
结点的个数计算
int cal(node* root){
if(root==NULL) return 0;
else return cal(root->lchild)+cal(root->rchild)+1;
}