数据结构—树和二叉树-2.二叉树的层次遍历(BFS)

上一篇文章对二叉树做了一个简单的小练习,也是对二叉树有了一个大概的了解,接下来这一篇便是二叉树中即为关键的算法——二叉树的层次遍历,即BFS
这个算法的重要性呢不再多说,主要用于求单源最短路径问题(无权值,即单权值的树)。


BFS——宽度优先遍历

顾名思义:先遍历完与初始状态最近的状态,然后再遍历与遍历完状态的最近的状态。从开始状态–>只需一次转移就到达的状态–>只需两次就到达的状态–>……..

如上一篇文章的二叉树

                1
           2          3
        4    5     6     7
       8 9 10 11 12 13 14 15

如果按照BFS如何遍历呢?
(1)从1开始遍历;(2)遍历与1最近的结点,即2和3;(3)遍历与2和3最近的结点,即4,5,6,7;(4)遍历与4,5,6,7最近的结点,即8,9,10,11,12,13,14,15。完成。


如何实现BFS?

答:队列。试想一下队列的特点——FIFO(先进先出),ok,那么我们模拟一下结点入队出队的过程。
(1)创建一个空队列q;
(2)将结点1入队;队列状态为:1
(3)循环(下面的步骤都在这个循环里完成),条件是判断队列q是否为空,因为如果所有结点都不再入队即遍历完成;
(4)取队头结点赋给新结点V,然后出队,即结点1出队,目前队列为空,结点V就是结点1;队列状态为:NULL
(5)找到与V相邻的所有结点,即结点2和3,然后入队;队列状态为:2 3
(6)取队头元素,即结点2,赋给V,然后出队;队列状态为:3
(7)找到与V相邻的所有结点,即结点4和5,然后入队:队列状态为:3 4 5
(8)。。。。。不再赘述过程

基本过程就是这样,求最短路(无权)的思路也是如此,每个结点有个dis值,表示从头结点开始到其中一个结点的最短距离。过程和上面基本一致,就是需要将所有结点的dis值先初始化为0,然后遍历到一个结点,就将此结点的dis等于它的父节点的dis+1。


-例题.树的层次遍历-UVA122

算法入门经典上给出一个例题,我们来分析一下。

问题描述:输入一个二叉树,然后从上到下从左到右的顺序输出各个结点的值。每个结点都按照从根结点到它的移动序列给出(L表示左,R表示右)。
样例输入:(11,LL) (7,LLL) (8,R) (5,) (4,L) (13,RL) (2,LLR) (1,RRR) (4,RR) ()
样例输出:5 4 8 11 13 4 7 2 1

这个题目的bfs就是按照我刚才整理的思路用队列来实现,其实我觉得难度在于如何按照题目要求进行输入,将结点保存起来。按照刘汝佳老师的代码进行分析。

#include<cstdio>
#include<cstring> 
#include<queue>
#include<vector>
using namespace std;
const int maxn = 256+10;

struct Node{
    bool have_value;
    int v;//用来保存结点值 
    Node *left,*right;
    Node():have_value(false),left(NULL),right(NULL){}
};//定义一个结点结构体 

Node* newnode()
{
    return new Node();
}//创建新结点函数 

char s[maxn];
Node* root;
bool failed;

void addnode(int v,char* s)
{
    int n = strlen(s);
    Node* u = root;
    for(int i=0;i<n;i++)
    {
        if(s[i]=='L')
        {
            if(u->left==NULL) u->left = newnode();//如果结点不存在,建立新结点 
            u = u->left;//往左走到达新建立的结点 
        }
        else if(s[i]=='R')
        {
            if(u->right==NULL) u->right = newnode();
            u = u->right;
        }
    }
    if(u->have_value) failed = true;//已经赋值过,表明输入有误 
    u->v = v;
    u->have_value = true;//做标记 
}

bool read_input()
{
    failed = false;
    root = newnode();
    for(;;)
    {
        if(scanf("%s",s)!=1) return false;
        if(!strcmp(s,"()")) break;//如果输入为"()",即输入结束,直接退出循环。
        int v;
        sscanf(&s[1],"%d",&v);//将字符串中的结点值读取出来赋给V
        addnode(v,strchr(s,',')+1);//strchr函数是返回,首次出现的位置,然后插入结点 
    }   
    return true; 
}

bool bfs(vector<int>& ans)
{
    queue<Node*> q;
    ans.clear();//每次遍历之前要先重置vector,即清空 
    q.push(root);//将根结点先放入队列中 
    while(!q.empty())//判断是否为空 
    {
        Node* u = q.front();q.pop();//取队头结点赋给u,并出队 
        if(!u->have_value) return false;//如果有结点没有赋值,则输入有误 
        ans.push_back(u->v);//将当期结点的值插入到向量中 
        if(u->left!=NULL) 
        {
            q.push(u->left);//如果左子结点不为空,则将左子结点入队    
        }
        if(u->right!=NULL)
        {
            q.push(u->right);
        }
    }
    return true;
} 
int main()
{
    vector<int> v;
    while(read_input())
    {
        if(!bfs(v)) failed = 1;
        if(failed) printf("not complete\n");
        else{
            for(int i=0;i<v.size();i++) 
            {
            if(i != 0) printf(" ");
            printf("%d", v[i]);
            }
            printf("\n");
        } 
    } 
    return 0;
}

这题价值还是非常大的,通过vector来保存遍历的结点值,一边遍历一边保存。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值