求宽度
宽度,就是将二叉树按到根节点的距离(层数)排好,一层中最多的节点个数叫做宽度
比如这个二叉树,宽度是4,在第三层达到最大。
思想:
利用队列和按行遍历的思想,同时记录下每一个结点的层数,最后数层数就好了。
怎么知道层数?将根节点定义为第一层,每一次压入孩子就加一层喽。
代码:
typedef struct Btree//树的结构体
{
char data;
struct Btree* lchild;
struct Btree* rchild;
}btree;
struct queue//队列
{
btree *Node;
int Nodelev;
} Q[20];
void get_width(btree* bt,int *k)//传入二叉树和一个int指针存储返回值
{
int front=0,rear=0;//队首队尾
int maxlev[10]={0};//每一层的元素个数
Q[front].Node=bt;//根节点压入,第一层
Q[front].Nodelev=1;
while(front<=rear)//按层遍历将每一个结点都标记上层数
{
if(Q[front].Node->lchild)
{
Q[++rear].Node=Q[front].Node->lchild;
Q[rear].Nodelev=Q[front].Nodelev+1;
}
if(Q[front].Node->rchild)
{
Q[++rear].Node=Q[front].Node->rchild;
Q[rear].Nodelev=Q[front].Nodelev+1;
}
front++;
}
for(int i=0;i<=rear;i++)//统计层数
maxlev[Q[i].Nodelev]++;
for(int i=1;i<10&&maxlev[i];i++)//找最值
{
if(*k<maxlev[i])
{
*k=maxlev[i];
}
}
}
任意结点的层数
在上一个题中我们已经在遍历的同时给出了每一个顶点的层数,如果是判断某一个确定的结点,在上面的基础上添加判断,判断是否找到了该节点。
不过方法不止一种,接下来这个题也可以实现层数的问题。
求祖先结点
这里的祖先结点和生活中的是相同的(爸爸的爸爸叫什么。。。)
说白了就是找到从根节点到给出结点的路径,当然唯一了。
比如下面这图,D的祖先节点是B和A(AB也没问题,这里反着和栈里面的内容能对上)
123这三个题目是有相似之处的,当然都可以用第一题的方法,但是今天我给出的思路却不太一样
还记得当时的一个老鼠走迷宫吗,对栈的应用,在那里面我们使用的方式是不断尝试和回退。
先给出栈的部分:
struct link//栈
{
btree* data;
struct link* next;
};
void input_zhan(struct link* head,btree* data)//入栈
{
struct link* p=(struct link* )malloc(sizeof(struct link));
p->data=data;
p->next=head->next;
head->next=p;
}
btree* output_zhan(struct link* head)//出栈
{
struct link* p=head->next;
btree* ret=head->next->data;
head->next=p->next;
free(p);
return ret;
}
函数:
void Find(btree *bt,char input)//找某一个元素的层数和所有祖先节点
{
struct link* head=(struct link* )malloc(sizeof(struct link));
btree* p=bt;
head->next=NULL;
do{
if(p->data==input)//找到了
{
printf("%c",p->data);
while(head->next)
{
btree* temp=output_zhan(head);
printf("<-%c",temp->data);
}
free(head);
return;
}
else
{
input_zhan(head,p);
if(p->lchild)
{
p=p->lchild;
}
else if(p->rchild)
{
p=p->rchild;
}
else//换一个路
{
while(!p->rchild&&head->next)
p=output_zhan(head);
p=p->rchild;
}
}
}while(head->next);
if(!head->next)
cout << "Sorry! Not find.";
}
分析一下:
和之前的老鼠走迷宫差不多,找到了就退栈结束程序,不然就接着找。
怎么找?先看左孩子,如果没有左孩子看一下右孩子,都没有(叶子)就退栈,因为之前的结点肯定左孩子走过了,所以直接走右孩子。
如果感觉自己听懂了,然后就结束了这篇博客,感觉你要错亿,为什么呢?
因为这个过程就是在遍历啊。
回忆一下之前的非递归过程,和这个就是相同的。这也再一次说明了二叉树的操作之间的关联。
完全二叉树判断
完全二叉树在之前也有涉及,放图:
思路:
还是按行遍历的思想,将每一个结点的两个孩子都压入,不管是否为空,然后判断队列里面的情况,如果有空结点,说明非完全二叉树,返回0,否则返回1
int complete(btree* bt)//判断完全二叉树1
{
if(bt==NULL)
return 1;
else
{
struct Queue* head=(struct Queue* )malloc(sizeof(struct Queue));
head->next=NULL;
struct information* inf=(struct information*)malloc(sizeof(struct information));
inf->head=NULL;//信息初始化别忘了,都是空!
inf->rear=NULL;
btree* p=bt;
input(head,inf,p);
while(p)//非空就压入孩子,看队列有没有空
{
p=output(head,inf);
if(p)
{
input(head,inf,p->lchild);//先入左很重要
input(head,inf,p->rchild);
}
}
while(inf->rear)
{
p=output(head,inf);
if(!p)//有空的
{
while(inf->rear)
{
p=output(head,inf);
}
free(head);
free(inf);
return 0;
}
}
free(head);
free(inf);
return 1;
}
}
看来不能用递归性质解决的问题,都可以考虑一下用层次遍历的方式,或者是三种非递归的思想。
不过,对于这个问题,我还看到过其他的想法:
对任一结点,如果其右子树的深度为j,则其左子树的深度必为j或j+1 即度为1的点只有1个或0个
的确,完全二叉树度为1的结点只能有一个,并且只能是有左孩子没有右孩子。
利用之前提到过的求深度函数来完成,
int flag=1,ret=1;//全局变量,用于判断是否为完全二叉树(ret 为最终的结果)
int complete(btree* bt)//判断完全二叉树2
{
if(!flag)
ret= 0;
if(!bt)
flag=1;
int l=depth(bt->lchild),r=depth(bt->rchild);
if(l==r||l==r+1)
flag=1;
else
flag=0;
}