计算二叉树的深度和宽度

二叉树这种数据结构的重要性不必多言,下面计算二叉树的深度和宽度。要计算二叉树的深度和宽度,先构造一课二叉树,为了方便验证结果的正确性,在这里构造二叉搜索树。二叉树由节点构成,所以先实现节点类:

template <typename T>
class stnode{
public:
	T nodeValue;//节点值
	stnode<T> *left,*right,*parent;//依次是指向当前节点的左子结点、右子节点、父节点的指针
	stnode(const T& item);//构造函数
};
template <typename T>//初始化nodeValue的值为item,三个指针均为NULL
stnode<T>::stnode(const T& item=T()):nodeValue(item){
	left=NULL;
	right=NULL;
	parent=NULL;
}

先说计算深度,这里引用一种<<数据结构C++语言描述--应用STL模板库>>这本书中的计算方法,采用的是递归的思想,即采用后序遍历二叉树,分别计算左子节点和右子节点的深度,取其中较大值加上1就得到自己的深度。比如下面的二叉树


计算A节点的深度首先计算左右子节点BC的深度,同理计算B节点的深度先计算左右子节点DE的深度。定义一个NULL节点的深度为-1,这样一个叶节点的深度就为0(取左右子节点的深度,均为-1,再加上1)。这样D节点的左右子节点的深度分别为-1和0,取较大值加上1,那么D的深度就为1,B的左右子节点的深度分别为1和0,取较大值加上1,B的深度就为2,。这样一层一层递归到根节点就得出了整个二叉树的深度。

int dep(stnode<int>* root){
	int leftDep,rightDep,totalDep;
	if(root==NULL)
		return -1;	//定义一个NULL节点的深度为-1
	else{			//采用后序遍历的方式,先计算左子节点的深度,再计算右子节点的深度
		leftDep=dep(root->left);
		rightDep=dep(root->right);
		totalDep=1+(leftDep>rightDep?leftDep:rightDep);//取左右子节点的深度值中较大值加上1就为自身的深度
	}
	return totalDep;//返回二叉树的深度
}
测试一下是否正确

void main(){
	unsigned int i;	
	stree<int> tree(5);
	tree.insert(4);
	tree.insert(3);
	tree.insert(6);
	cout<<dep(tree.root)<<endl;
	while(1);
}

因为是二叉搜索树,插入值以后树的结构是明确的,插入以后的树如下图

计算二叉树的深度和宽度_第1张图片

树的深度为2,看一下结果

计算二叉树的深度和宽度_第2张图片

另一种方法是非递归实现,树的遍历输出除了前中后序遍历输出还可以按层次输出,如下图所示

就像楼层一样是一层一层的,这种输出的思想就是用一个队列,先将根节点插入队列。随后循环取出队列中的所有元素,每取出一个元素,输出它的节点值,然后将它的左右子节点再插入到队列,这样当队列为空时,就遍历完了整个树。那么如果用两个队列,如上图所示,将p中的所有元素全部取出,每取出一个元素就把它的左右子节点全部插入到q队列,此时p为空。同理再将q中的全部元素取出,插入到p中,这样循环,一直到pq均为空,树遍历结束。如果每次循环记录下pq的size,取size的最大值就可以得到树的宽度,统计pq互相插值的次数,就可以得到“楼层数”,这个楼层数就是我们需要的深度。用代码实现上面的思想,先计算深度

<pre name="code" class="cpp">int depth(stnode<int>* root){
	int depth=-1;				//和声明一个空树的深度为-1一样
	queue<stnode<int> *> p,q;	//声明两个队列
	stnode<int> *temp;			//临时节点
	p.push(root);				//将根节点插入到p中
	while(!(p.empty()&&q.empty())){	//当pq均为空时退出整个循环,表示树遍历结束
		while(!p.empty()){		//取出p中的每个元素,然后将它不为空的左右子节点插入到q中
			temp=p.front();
			p.pop();
			if(temp->left!=NULL)
				q.push(temp->left);
			if(temp->right!=NULL)
				q.push(temp->right);
		}
		depth++;				//p往q中插值进行了一次,深度加1
		/*有时候p恰好是最后一层,即取出的元素的左右子节点均为空,这时q中没有元素,那么就跳出循环,
		否则下面的depth++会多执行一次,没有在上面的while循环前面加这句话的原因是:下面的while循环
		取出了q中的所有元素,所以q必为空,此时如果p也为空,那么就会跳出整个大的while循环*/
		if(q.empty())		
			break;
		while(!q.empty()){		//取出q中的每个元素,将它的左右子节点插入到p中
			temp=q.front();
			q.pop();
			if(temp->left!=NULL)
				p.push(temp->left);
			if(temp->right!=NULL)
				p.push(temp->right);
		}
		depth++;				//q往p中插值进行了一次,深度加1
	}
	return depth;
}


 测试一下两种计算深度方法的正确性

void main(){
	unsigned int i;	
	stree<int> tree(50);
	for(i=0;i<100;i++)
		tree.insert(rand()%100);
	cout<<dep(tree.root)<<endl;
	cout<<depth(tree.root)<<endl;
	while(1);
}
将0-99以内的100个随机树插入到树中,用两种方法计算深度

计算二叉树的深度和宽度_第3张图片

均为11。

按照这种思想,如果记录p和q的size值,取出其中的最大值就是要计算的宽度,用代码实现这种思想

int width(stnode<int>* root){
	int width=0;				//宽度
	queue<stnode<int> *> p,q;	//声明两个队列
	stnode<int> *temp;			//临时节点
	p.push(root);				//将根节点插入到p中
	while(!(p.empty()&&q.empty())){			//pq循环互相差值
		if(p.size()>width)		//记录p的size,如果大于width,那么就将p.size()赋值给width
			width=p.size();			
		while(!p.empty()){
			temp=p.front();
			p.pop();
			if(temp->left!=NULL)
				q.push(temp->left);
			if(temp->right!=NULL)
				q.push(temp->right);
		}
		if(q.size()>width)		//记录q的size,如果大于width,那么就将q.size()赋值给width
			width=q.size();
		while(!q.empty()){
			temp=q.front();
			q.pop();
			if(temp->left!=NULL)
				p.push(temp->left);
			if(temp->right!=NULL)
				p.push(temp->right);
		}
		
	}
	return width;				//这样,width中存放的是pq的size值中的最大值,也就是二叉树的宽度
}
测试一下

void main(){
	unsigned int i;	
	stree<int> tree(50);
	tree.insert(40);
	tree.insert(52);
	tree.insert(38);
	tree.insert(41);
	tree.insert(51);
	tree.insert(60);
	cout<<width(tree.root)<<endl;
	while(1);
}
这样插值后的宽度为4,看一下结果



结果正确。


你可能感兴趣的:(数据结构,二叉树,搜索,C语言)