Breadth first search and multi-source breadth first search 2021-01-24

Breadth first search and multi-source breadth first search




Preface

         Breadth-first search is mostly used for traversal of graphs and trees. The traversal of binary tree hierarchy is actually a special kind of breadth-first search.
         This article first introduces the typical breadth-first search, then summarizes the application of single-source breadth-first search, and finally summarizes the basic method of multi-source breadth-first search, and the template of two-dimensional grid breadth first search.

1. Title description

Take the following topic as an example (topic source leetcode)

brainless traversal template
1. N- ary tree hierarchy traversal
2. Print binary tree from top to bottom |
3. Print binary tree from top to bottom ||
4. From top to bottom Print binary tree|||


Single source point breadth-first search application
5. Binary tree cousin node
6. Fill the next right node pointer of each node.


Multi-source point breadth first search application (mostly used for two-dimensional grid search )
7. Rotten oranges
8. Map analysis


Global breadth-first search (special multi-source breadth-first search, but the application is different)
9. Water area size
10. Judgment bipartite graph
11. Course schedule ||

Two, method summary and code template

1. Single source breadth first search

    The single-source breadth-first search takes a point as the source point, puts it into the queue first, and uses the auxiliary data structure—queue, to achieve first-in-first-out access afterwards. The specific pseudo code is as follows:
void bfs(参数1 ...)
{
    
    
	queue<T> q;
	q.push(...);
	while(!q,empty())
	{
    
    
		//先出队 ,实现先进先出的访问
		T temp=q.front();
		q.pop();
		//在考虑刚刚出队的元素的相邻接点,将其相邻节点入队
		//入队时,如果是二叉树,则只需要考虑左右子节点即可
		//对于图或者n叉树,需要结合存储的方式进行遍历(多用for循环)
		for(...)
			q.push(...)		
		//特别注意,在相邻接点入队时需要根据题目要求做出相应调整
		//如当搜索到的某一个节点符合条件时需要及时返回,结束搜索
	}
}
第二种广度优先遍历遍历的模板:带有层次结构的广度优先搜索
void bfs(参数1 ...)
{
    
    
	queue<T> q;
	q.push(...);
	while(!q,empty())
	{
    
    
		int size=q.size();
		for(int i=0;i<size;++i)
		{
    
    
			//先出队 ,实现先进先出的访问
			T temp=q.front();
			q.pop();
			for(...)
				q.push(...)		
		//特别注意,在相邻接点入队时需要根据题目要求做出相应调整
		//如当搜索到的某一个节点符合条件时需要及时返回,结束搜索
		}
	}
}

1.1 The first type of typical sequence traversal: N-ary tree sequence traversal

This question only needs to apply the above pseudo-code template brainlessly. Code directly
class Solution {
    
    
public:
    vector<vector<int>> levelOrder(Node* root) 
    {
    
    
        vector<vector<int>> v;
        if(!root)
            return v;
        queue<Node*> q;
        q.push(root);
        while(!q.empty())
        {
    
    
            vector<int> v1;//用于保存每一层的节点的信息
            int size=q.size();
            for(int i=0;i<size;++i)
            {
    
    
                Node* ptr=q.front();
                q.pop();
                v1.push_back(ptr->val);
                //对应上述模板的入队过程
                for(int k=0;k<ptr->children.size();++k)
                    q.push(ptr->children[k]);
            }
            v.push_back(v1);
        }    
        return v;
    }
};

1.2 The second type of typical hierarchy traversal: print binary tree from top to bottom|&print binary tree from top to bottom||

        Both belong to the topic of applying the sequence traversal template, the difference is that the topic requirements need to be paid attention to. If the result of the traversal is required to maintain the hierarchical structure of the tree, the above pseudo code template needs to be improved, that is, a for loop is added on the original basis, and the function of each for loop is to empty the upper level of the element in the queue and load it The next level of elements makes the same level of elements traversed by a for loop, so that the traversal has a sense of hierarchy.
Directly on the code:
class Solution {
    
    
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
    
    
        vector<vector<int>> v;
        if(root==NULL)
            return v;
        queue<TreeNode*> q;
        q.push(root);
        while(!q.empty())
        {
    
    
            vector<int> v1;
            int size=q.size();
            for(int i=0;i<size;++i)
            {
    
    
                TreeNode* t=q.front();
                q.pop();
                v1.push_back(t->val);    
                if(t->left!=NULL)
                    q.push(t->left);
                if(t->right!=NULL)
                    q.push(t->right);
            }
            v.push_back(v1);
        }
        return v;
    }
};

1.3 The third type of hierarchy traversal:

请实现一个函数按照之字形顺序打印二叉树
即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印
第三行再按照从左到右的顺序打印,其他行以此类推。
        Only need to maintain a variable on the basis of the original template to mark whether the current layer is odd or even. Thereby adopting different access strategies. In addition, this question should use a deque according to demand. Directly on the code:
class Solution {
    
    
public:
    vector<vector<int>> levelOrder(TreeNode* root) 
    {
    
    
        vector<vector<int>> v;
        if(root==NULL)
            return v;
        deque<TreeNode*> q;
        q.push_back(root);
        int count=1;
        while(!q.empty())
        {
    
    
            int size=q.size();
            vector<int> v1;
            for(int i=0;i<size;++i)
            {
    
    
                if(count%2==0)
                {
    
    
                    TreeNode* ptr=q.back();
                    q.pop_back();
                    //注意从后面取出的,应该从队头插入
     //由于要求插入后左节点在右节点的前面,因此先插入右节点。
     //可以直接想想二叉树的结构进行插入               
                    if(ptr->right) q.push_front(ptr->right);
                    if(ptr->left) q.push_front(ptr->left);
                    v1.push_back(ptr->val);
                }
                else 
                {
    
    
                    TreeNode* ptr=q.front();
                    q.pop_front();
                    if(ptr->left) q.push_back(ptr->left);
                    if(ptr->right) q.push_back(ptr->right);
                    v1.push_back(ptr->val);
                }
            }
            count++;
            v.push_back(v1);
        }
        return v;
    }
};

2. Application of single-source breadth-first search

       I only provide ideas here:
For the first question: maintain two additional variables, the parent node of the element x and y to be searched is marked by the user. Then judge according to the definition of "cousin".
For the second question: on the basis of "breadth first search template with hierarchical structure", every time you start to traverse a new layer, maintain a head pointer, and then use this The root pointer links the nodes of a layer together. Post an elegant code:

class Solution {
    
    
public:
    Node* connect(Node* root) 
    {
    
    
        if(!root)
            return NULL;
        queue<Node*> q;
        q.push(root);
        Node node;
        while(!q.empty())
        {
    
    
            int size=q.size();
            Node* temp=&node;
            for(int i=0;i<size;++i)
            {
    
    
                Node* ptr=q.front();
                q.pop();
                //典型的链表操作
                temp->next=ptr;
                temp=temp->next;
                if(ptr->left)
                    q.push(ptr->left);
                if(ptr->right)
                    q.push(ptr->right);
            }
        }
        return root;
    }
};

3. Multi-source breadth first search

3.1 First give the definition

       Multi-source breadth-first search: Search from multiple starting points at the same time, and divide the entire original search domain into target points and source points. Each source point can start searching for the corresponding target point.

3.2 Method

       The easiest way to solve this kind of problem is to abstract a super source point, and then multi-source breadth-first search is a single-source breadth-first search.
       The traversal of the binary tree is equivalent to only one source point-root, so there is only one element root in the queue during initialization. The multi-source point search abstracts a super source point O, and the adjacent point of O point is the source point in the actual graph. Therefore, when the queue is initialized, all the source points that meet the conditions need to be enqueued to achieve the effect of searching all the source points at the same time.


For details, please refer to the link:
Rotten Oranges-Official Explanation

Map analysis-official explanation

       Here is a more elegant template for a two-dimensional grid search: Take the title "Map Analysis" as an example
class Solution {
    
    
public:
	int n,m;//定义成类中的成员,便于不同函数的直接访问
	int a[4][2]={
    
    {
    
    1,0},{
    
    -1,0},{
    
    0,1},{
    
    0,-1}};//用于标记之后可以移动的四个方向

	//vector<vector<int>> v
    //有些题目中可能维护一个等大的二维网格,先初始化为全零,之后用于标
    //记是否到达过了。
    //初始化是直接调用vector类的函数resize
    //v.resize(n,vector<m,0))即可
    int maxDistance(vector<vector<int>>& grid)
    {
    
    //多源广度优先搜索
        int n = grid.size();
        int m = grid[0].size();
        queue<pair<int, int>> q;
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < m; ++j)
                if (grid[i][j] == 1)
                    q.push({
    
     i,j });
        int count = -1;
        if(q.size()==n*m)
            return -1;
        while (!q.empty())
        {
    
    
            int size = q.size();
            for (int i = 0; i < size; ++i)
            {
    
    
                pair<int, int> cp = q.front();
                q.pop();
                for(int i=0;i<4;++i)
                {
    
    
                	int x=cp.first+a[i][0],y=cp.second+a[i][1];
                	if(x>=0&&x<n&&y>=0&&y<m&&grid[x][y]==0)
                	{
    
    
                		  q.push({
    
    x,y});
                    	  grid[x][y]=1;
                	}
                }
            }
            ++count;
        }
        return count;
    }
};


3. Summary

The above is the basic classification of breadth first search. This article only briefly introduces the basic applications of breadth first search. There are many kinds of algorithm topics, and the breadth-first template is to apply the auxiliary data structure-queue, to achieve the requirement of first-in-first-access, that is, first enter the source point into the queue, and then every element that pops up needs to consider whether the adjacent element of the element is Need to join the team.

Guess you like

Origin blog.csdn.net/sddxszl/article/details/113066477