队列相关定义

队列是一种线性存储表,元素数据的插入在表的一端进行,在另一端删除,从而构成了一个先进先出的FIFO(First In First Out)表。
队头&队尾:插入一端称为队尾,删除一端称为队头。

STL——queue

对象定义

*queue模版类的定义在<queue>头文件中。
*queue模版类需要两个模版参数,一个是元素类型,一个是容器类型。
定义queue对象的示例代码如下:
queue<int> q1;
queue<double> q2;
定义模版:queue<Type> S,Type可以是int,double,float,char,string等类型,还是是结构体类型的。

基本操作

入队(push):在队列末尾加入一个元素,例如:q.push(x)
出队(pop):删除/弹出队列第一个元素,即队首元素,例如:q.pop()
访问队首元素(front):返回队列第一个元素,例如:q.front()
访问队尾元素(back):返回队列最后一个元素,即队尾元素,例如:q.back()
判断队列空(empty):判断队列是否为空,如果空,则返回true,否则返回false,例如:q.empty()
访问队列中元素的个数(size):返回队列元素个数,例如:q.size()

代码实现

#include<iostream>
#include<queue>
using namespace std;
int main()
{
    queue<int> num;
    int c;
    cout<<"输入10个元素,并将其加入队列中:"<<endl;
    for(int i=0;i<10;i++)
    {
        cin>>c;
        num.push(c);
    }
    cout<<"计算队列中元素个数:"<<num.size()<<endl;
    cout<<"输出队列中10个元素:"<<endl;
    while(!num.empty())
    {
        int t=num.front();
        cout<<t<<" ";
        num.pop();
    }
    cout<<"队列是否空:";
    if(num.empty()) cout<<"Yes"<<endl;
    else cout<<"No"<<endl;
    return 0;

}

queue队列的实现

实现队列,需要操作push(),pop(),front(),empty()

广度优先搜索(BFS)

基本思想

广度优先搜索又称宽度优先搜索,一般用来解决最短路径问题。
广搜的目标是,一旦找到一条从起点到目标结点的路径,这条路径就一定是最优的(步数最少)的。
广搜是按怎样顺序来搜索的呢?
有这样一棵树:
队列+BFS
我们要想广度优先,那么首先搜索第一层1,然后搜索第二层,从左向右2,5,6,9,在搜索第三层,从左向右3,4,7,10,再搜索第四层8,很简单吧,这就是一个层次遍历。
程序的实现需要借助队列。
(1)首先,令树根1入队,如图:

1

**(2)**队头元素出队,输出1,同时令1的所有孩子(从左向右顺序)入队,如图:

2 5 6 9

**(3)**队头元素出队,输出2,同时令2的所有孩子(从左向右顺序)入队,如图:

5 6 9 3 4

**(4)**队头元素出队,输出5,同时令5的所有孩子(从左向右顺序)入队,5没有孩子,不操作,如图:

6 9 3 4

**(5)**队头元素出队,输出6,同时令6的所有孩子(从左向右顺序)入队,如图:

9 3 4 7

**(6)**队头元素出队,输出9,同时令9的所有孩子(从左向右顺序)入队,如图:

3 4 7 10

**(7)**队头元素出队,输出3,同时令3的所有孩子(从左向右顺序)入队,3没有孩子,不操作,如图:

4 7 10

**(8)**队头元素出队,输出4,同时令4的所有孩子(从左向右顺序)入队,4没有孩子,不操作,如图:

7 10

**(9)**队头元素出队,输出7,同时令7的所有孩子(从左向右顺序)入队,如图:

10 8

**(10)**队头元素出队,输出10,同时令10的所有孩子(从左向右顺序)入队,10没有孩子,不操作,如图:

8

**(11)**队头元素出队,输出8,同时令8的所有孩子(从左向右顺序)入队,8没有孩子,不操作,如图:

此时队列为空,结束。输出顺序为1、2、5、6、9、3、4、7、10、8,该顺序即是BFS搜索的顺序,全图遍历。如果找最优解,搜索过程中找到便结束。

例题讲解

排位赛题Catch My Pet
假设小A起始位于点3,宠物狗位于点5,即N=3,K=5,最右边是6,如何搜索出一条最短路径呢?
队列+BFS

1.深搜

从起点出发,随机挑一个方向,能往前走就往前走(拓展),走不动了则回溯。不能走已经走过的点(判重)
运气好的话:3->4->5或3->6->5
运气不好的话:3->2->4->5
运气最差的话:3->2->1->0->4->5
所以深搜就算找到了解,也不一定是最优解,当然也可以的,可以用各种手段优化的,比如,若已经找到路径长度为n 的解,则所有长度大于n的走法就不必尝试。但这样四处碰壁,效率上肯定就低了。

2.广搜

给节点分层。起点是第0层。从起点最少需n步就能到达的点属于第n层。
第1层:2,4,6
第2层:1,5
第3层:0
依层次顺序,从小到大扩展节点。
搜索过程(结点拓展过程):
3
2 4 6
1 5
问题解决。拓展时,不能拓展出已经走过的结点(要判重)
用队列来演示下:

1

队列+BFS

2

队列+BFS#### 3
队列+BFS#### 4
队列+BFS#### 5
队列+BFS

6

队列+BFS
目标结点5出列,问题解决。
为什么结果一定是最优解呢?广搜虽然是全图遍历,但一旦着找到解就就会终止。

代码

#include<iostream>
#include<queue>
using namespace std;
struct Step
{
    int x;
    int steps;
    Step(int xx=0,int ss=0):x(xx),steps(ss){}
};
queue<Step> q;
const int MAXN=100000;
int visited[MAXN]; //标记已走过的点
void bfs(int n,int k)
{
    Step p1,p2;
    p1.x=n;
    p1.steps=0;
    q.push(p1);
    visited[n]=1;
    while(!q.empty())
    {
        p1=q.front();//取出队首元素
        if(p1.x==k)
        {
            cout<<p1.steps<<endl;
            return;
        }
        
        else
        {
            //搜索符合的点,并加入到队列中
            if(p1.x-1>=0&&!visited[p1.x-1])
            {
                p2.x=p1.x-1;
                p2.steps=p1.steps+1;
                q.push(p2);
                visited[p1.x-1]=1;
            }
            if(p1.x+1<=MAXN&&!visited[p1.x+1])
            {
                p2.x=p1.x+1;
                p2.steps=p1.steps+1;
                q.push(p2);
                visited[p1.x+1]=1;
            }
            if(p1.x*2<=MAXN&&!visited[p1.x*2])
            {
                p2.x=p1.x*2;
                p2.steps=p1.steps+1;
                q.push(p2);
                visited[p1.x*2]=1;
            }
            q.pop();//抛出队首元素
        }
        
    }
}
int main()
{
    int n,k;
    cin>>n>>k;
    bfs(n,k);
    return 0;
}

习题

1370最少步数

相关文章: