//二叉树三种遍历模板(本文直接摘自天勤考研数据结构第六章)
void Travel(BTNode *p)
{
if (p != NULL)
{
//(1)
Travel(p->lchild);
//(2)
Travel(p->rchild);
//(3)
}
/************************************************************************/
/*
如果将对结点的访问操作写在(1)处,就是先序遍历
如果将对结点的访问操作写在(2)处,就是中序遍历
如果将对结点的访问操作写在(3)处,就是后序遍历
摘自天勤考研数据结构P142,下面看一个应用
*/
/************************************************************************/
}
//编写一个算法输出二叉树先序遍历中第k个结点的值
int n = 0;
void travel1(BTNode *p, int k)
{
if (p != NULL)
{
++n;//当程序第一次来到一个结点时进行计数,表示这是第n个结点
if (k == n)//当第一次来到这个结点时进行判断,看这个结点是不是先序序列中的第k个结点
{
cout << p->data << endl;//如果是则输出结点的值
return;//并且无需再进行遍历了,直接return返回
}
travel1(p->lchild, k);
travel1(p->rchild, k);
/************************************************************************/
/*
此处
++n;//当程序第一次来到一个结点时进行计数,表示这是第n个结点
if (k == n)//当第一次来到这个结点时进行判断,看这个结点是不是先序序列中的第k个结点
{
cout << p->data << endl;//如果是则输出结点的值
return;//并且无需再进行遍历了,直接return返回
}
相当于是对结点的访问函数,当题目变成求后续序列或者中序序列第k个结点是,把这段代码放到相应的位置即可
(1,2,3处)
*/
/************************************************************************/
}
}
//二叉树的层次遍历
/************************************************************************/
/*
二叉树要进行层次遍历,则需要建立一个循环队列。先将这颗二叉树头结点如队列然后出队列,访问该结点
,如果它有左子树,则将左子树的根结点入队列,如果它有右子树,则将右子树的根结点入队列。然后出队列
再对出队列的结点访问,如此反复,直到队列为空为止,对应的算法如下:
*/
/************************************************************************/
void LevelTravel(BTNode *p)
{
//定义一个循环队列,用来记录将要访问的层次上的结点
circular_buffer<BTNode* > circlequeue;//此处使用了在boost库中提供的循环队列
BTNode *q = NULL ;
if (p != NULL)
{
circlequeue.push_back(p); // 根结点入队列
//当队列不为空的时候进行循环
while ( !(circlequeue.empty() ) )
{
q = circlequeue.front() ;
circlequeue.pop_front();//头结点出队
visit(q);//访问头结点
if (q->lchild != NULL)//如果左子树不为空,则左子树的根结点入队
{
circlequeue.push_back(q->lchild);
}
if (q->rchild !=NULL)//如果右子树不为空,则右子树的根结点入队列
{
circlequeue.push_back(q->rchild);
}
}
}
}
//例题:求二叉树的宽度(宽度指的是具有结点数目最多的那一层的结点个数)
/************************************************************************/
/*
分析:要求含有最大结点数的层上的结点数,可以分别求出每层的结点数,然后从中选出最大的。要达到整儿目的,应该明白以下两个知识点:
1、对于非空树,根结点所在的层为第一层,并且通过层次遍历算法的程序中可以得知,有一个当由当前结点找到其左右孩子结点的操作。这就
提示我们,若果知道当前结点的层号,就可以推出其左右孩子结点的层号,即为当前结点的层号加1,进而可以求出所有结点的层号
2、在层次遍历过程中,用到了一个循环队列(队列用数组表示)。其出队和入队操作分别为front=(front+1)%maxsize;和rear=(rear+1)%maxsize;
两句。如果用来存储队列的数组长度够长,可以容纳树中所有结点,这时候遍历遍历操作中队头和队尾指针不会出现这回数组起始位置的情况,那么
fornt=(front+1)%MAXSIZE;就可以用++front;代替,rear=(rear+1)%mAXSIZE;就可以用++rea;代替。出队操作只是队头指针front想后移动了一位,
但并没有把队头元素删除。在数组长度足够长的情况下,队头元素也不会被新入队的元素覆盖。
搞清楚上面两点之后,这个题目就好解决了。由第一点可一算出所有结点的层号。由 第二点可以知道所访问的结点最终会保存在一个数组中。因此只
需要修改层次遍历算法的模板,在其中添上求层号的操作,并将循环队列的操作改为非循环队列的操作。在遍历结束以后,数组中记录了所有结点的
层号信息。进而可以求得含有最多的层上的结点数,上代码
*/
/************************************************************************/
typedef struct
{
BTNode* p; //结点指针
int lno; //结点所在的层次号
}ST;
int MaxNode(BTNode* b)
{
circular_buffer<ST > queue2; //boost库当中的循环队列
int front = 0, rear = -1;
int Lno, i, j, max;
BTNode *q = NULL;
if (NULL != b)
{
++rear;
queue2[rear].p=b; //树根入队
queue2[rear].lno = 1; //树根所在结点层次号设置为1,此为已知条件
while (front != rear)
{
++front;
q = (queue2.front() ).p;
Lno = (queue2.front()).lno; //关键语句,Lno用来存取当前结点的层次号
queue2.pop_front();
if (q->lchild != NULL)
{
++rear;
queue2[rear].p = q->lchild;
queue2[rear].lno = Lno + 1;//关键语句:根据当前结点的层次号推知其左孩子结点的层次号
}
if(q->rchild != NULL)
{
++rear;
queue2[rear].p = q->rchild;
queue2[rear].lno = Lno + 1;//关键语句:根据当前结点的层次号推知其右孩子结点的层次号
}
} //注意:循环结束的时候,Lno保存的是这颗二叉树的最大层数,下面才是开始求含有结点最多层次中的结点数
max = 0;
for ( i = 1; i <= Lno; ++i)
{
n = 0;
for (j = 1;j <= rear;++j)
{
if (queue2[j].lno == j)
++n;
if (max < n)
max = n;
}
}
return max;
}
else return 0; //空树直接返回0
}