二叉树学习笔记-深度和宽度
Posted Sunnix
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树学习笔记-深度和宽度相关的知识,希望对你有一定的参考价值。
二叉树这种数据结构的重要性不必多言,下面计算二叉树的深度和宽度。要计算二叉树的深度和宽度,先构造一课二叉树,为了方便验证结果的正确性,在这里构造二叉搜索树。二叉树由节点构成,所以先实现节点类:
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);
因为是二叉搜索树,插入值以后树的结构是明确的,插入以后的树如下图
树的深度为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个随机树插入到树中,用两种方法计算深度
均为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,看一下结果
结果正确。
以上是关于二叉树学习笔记-深度和宽度的主要内容,如果未能解决你的问题,请参考以下文章