二叉树

二叉树的定义

首先需要知道什么是树,树是一种由顶点和边构成的一种数据结构。可以这样来定义满足连通,且边数等于定点数减一的结构就是树。在一棵树中只有一个根节点,并且树中一定是不存在环的。
二叉树的定义,这里给出二叉树的递归定义:

  • 要么二叉树没有根节点,是一棵空树
  • 要么二叉树是由根节点,左子树,右子树组成,且左子树和右子树又是一个二叉树
    在这里插入图片描述

树的性质

  • 树可以没有结点,这样的树叫作空树。
  • 结点的度:在一棵树中结点的子树棵树叫作度,树的度是指这棵树的结点中最大的度。
  • 结点的深度:结点的深度是指从根节点开始(深度为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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值