二叉树的一些非递归问题——求宽度、任意结点的层数、祖先节点、完全二叉树判断

求宽度

宽度,就是将二叉树按到根节点的距离(层数)排好,一层中最多的节点个数叫做宽度
在这里插入图片描述
比如这个二叉树,宽度是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;
}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值