二叉树
节点的定义和创建
当我们对动态内存的申请和释放的写法没有把握时,可以利用静态数组,将数组元素分配给相应节点。
struct Node{
Node *lchild;//左
Node *rchild;//右
char c;//节点信息
}Tree[50];//静态内存分配数组
int loc;//静态数组中已经分配的节点数,在创建一棵树前记得初始化为0
Node *create(){//申请一个节点空间,并返回指向该节点的指针
Tree[loc].lchild = Tree[loc].rchild = NULL;
return &Tree[loc++];
}
二叉树的构建
前/后序序列+中序序列可以唯一确定一个二叉树。
我们可以根据给出的两个遍历序列(必包含中序)来构造二叉树。
string str1, str2;//str1: 前序遍历的输出,str2: 中序遍历的输出
Node *build(int s1, int e1, int s2, int e2){//根据前序和中序便利的到的输出构建BST
Node *r = create();
r->c = str1[s1];//前序遍历的第一个字符一定为根节点
int rIndex;
for(int i = s2; i <= e2; i++){//在中序序列中找到根节点,他左边为它的左子树,右边为它的右子树
if(str2[i]==str1[s1]){
rIndex = i;
break;
}
}
//左右子树在create()函数中已经初始化成了NULL
if(rIndex != s2)//左子树不为空
r->lchild = build(s1+1,s1+(rIndex-s2),s2,rIndex-1);//递归还原左子树
if(rIndex != e2)//右子树不为空
r->rchild = build(s1+(rIndex-s2)+1,e1,rIndex+1,e2);//递归还原右子树
return r;
}
int main(){
while(cin>>str1){
cin>>str2;
loc = 0;//初始化静态内存空间中已使用节点个数为0
Node *T = build(0,str1.length()-1,0,str2.length()-1);//记得结尾下标=长度-1
//可以遍历输出看一下构建的二叉树
}
return 0;
}
二叉树的高度/深度
我们从根节点和左右子树来理解二叉树的深度:对于任意一棵非空二叉树,有如下四种情况:
- 如果一颗树只有一个节点,它的深度是1;
- 如果根节点只有左子树而没有右子树,则二叉树的深度为其左子树的深度+1;
- 如果根节点只有右子树而没有左子树,则二叉树的深度为其右树的深度+1;
- 如果根节点既有左子树又有右子树,则二叉树的深度为其左右子树的深度较大值+1;
递归实现
int getHight(Node *T){
if(T==NULL) return 0;
int lhight = getHight(T->lchild);//左子树高度
int rhight = getHight(T->rchild);//右子树高度
return lhight>rhight? lhight+1:rhight+1;
}
二叉树的宽度
宽度:具有最多结点数的层中包含的结点数。
我们需要记录每一层的节点数,来获取宽度(可以保留所有层,也可以只保留上一层)。所以需要用到二叉树的层次遍历,即广度优先周游。
广度优先周游:按层次从上到下,从左到右的逐层访问,可以利用队列实现。
- 首先把二叉树的根节点送入队列;
- 队首节点出队列并访问,然后把它的左右子节点分别入队列;
- 重复上面两步操作,直至队空。
int getWidth(Node *T){
if(T==NULL) return 0;
int preWidth = 0, curWidth = 0, width;
queue<Node*> q;
Node *temp = NULL;
q.push(T);//根节点入队
width = 1;
while(!q.empty()){
while(preWidth--){//依次取出这一层的所有节点
temp = q.front();//取出队首
q.pop();
if(temp->lchild!=NULL) q.push(temp->lchild);//左右子树入队
if(temp->rchild!=NULL) q.push(temp->rchild);
}
curWidth = q.size();
width = curWidth>width? curWidth:width;//比较宽度
preWidth = curWidth;//记录本层宽度,给下层使用
}
return width;
}