二叉树这种数据结构的重要性不必多言,下面计算二叉树的深度和宽度。要计算二叉树的深度和宽度,先构造一课二叉树,为了方便验证结果的正确性,在这里构造二叉搜索树。二叉树由节点构成,所以先实现节点类:
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; }
计算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); }
树的深度为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个随机树插入到树中,用两种方法计算深度
按照这种思想,如果记录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,看一下结果
结果正确。