Best First Search is a heuristic search algorithm that selects the most promising node for expansion based on an evaluation function. It prioritizes nodes in the search space using a heuristic to estimate their potential. By iteratively choosing the most promising node, it aims to efficiently navigate towards the goal state, making it particularly effective for optimization problems.
We are given an edge list of a graph where every edge is represented as (u, v, w). Here u, v and w represent source, destination and weight of the edges respectively. We need to do Best First Search of the graph (Pick the minimum cost edge next).
Start at node 0. Among its neighbors, node 1 has the lowest cost (edge cost 3), so move from 0 to 1.
From node 1, since a better path forward isn’t available, backtrack to node 0.
From node 0, choose the next best neighbor—node 3 (edge cost 5)—and move to node 3.
At node 3, find that moving to node 2 leads to a lower incremental cost.
Then proceed from node 2 to node 8 (the target)
Approach:
The idea is to use priority queue or heap to store the costs of edges that have lowest evaluation function value and operate similar to BFS algorithm.
Follow the below given steps:
Initialize an empty Priority Queue named pq.
Insert the starting node into pq.
While pq is not empty:
Remove the node u with the lowest evaluation value from pq.
If u is the goal node, terminate the search.
Otherwise, for each neighbor v of u: If v has not been visited, Mark v as visited and Insert v into pq.
Mark u as examined.
End the procedure when the goal is reached or pq becomes empty.
Illustration:
Let us consider the below example:
Best First Search (Informed Search)
We start from source "S" and search for goal "I" using given costs and Best First search.
pq initially contains S
We remove S from pq and process unvisited neighbors of S to pq.
pq now contains {A, C, B} (C is put before B because C has lesser cost)
We remove A from pq and process unvisited neighbors of A to pq.
pq now contains {C, B, E, D}
We remove C from pq and process unvisited neighbors of C to pq.
pq now contains {B, H, E, D}
We remove B from pq and process unvisited neighbors of B to pq.
pq now contains {H, E, D, F, G}
We remove H from pq.
Since our goal "I" is a neighbor of H, we return.
Below is given the implementation:
C++
#include<bits/stdc++.h>usingnamespacestd;// Function to perform Best First Searchvector<int>bestFirstSearch(vector<vector<int>>edges,intsrc,inttarget,intn){// create the adjacency listvector<vector<vector<int>>>adj(n);for(inti=0;i<edges.size();i++){adj[edges[i][0]].push_back({edges[i][1],edges[i][2]});adj[edges[i][1]].push_back({edges[i][0],edges[i][2]});}// create a visited array to // keep track of visited nodesvector<bool>visited(n,false);// create the min heap to store the nodes// based on the costpriority_queue<vector<int>,vector<vector<int>>,greater<vector<int>>>pq;// push the source node in the min heappq.push({0,src});// mark the source node as visitedvisited[src]=true;// to store the path vector<int>path;// loop until the min heap is emptywhile(!pq.empty()){// get the top element of the min heapintx=pq.top()[1];// push the current node in the pathpath.push_back(x);// pop the top elementpq.pop();// if the current node is the target node// break the loopif(x==target)break;// loop through the edges of the current nodefor(inti=0;i<adj[x].size();i++){// if the node is not visitedif(!visited[adj[x][i][0]]){// mark the node as visitedvisited[adj[x][i][0]]=true;// push the node in the min heappq.push({adj[x][i][1],adj[x][i][0]});}}}returnpath;}intmain(){intn=14;vector<vector<int>>edgeList={{0,1,3},{0,2,6},{0,3,5},{1,4,9},{1,5,8},{2,6,12},{2,7,14},{3,8,7},{8,9,5},{8,10,6},{9,11,1},{9,12,10},{9,13,2}};intsource=0;inttarget=9;vector<int>path=bestFirstSearch(edgeList,source,target,n);for(inti=0;i<path.size();i++){cout<<path[i]<<" ";}return0;}
Java
// Function to perform Best First Searchimportjava.util.*;classGfG{// Function to perform Best First SearchstaticArrayList<Integer>bestFirstSearch(int[][]edges,intsrc,inttarget,intn){// create the adjacency listArrayList<ArrayList<int[]>>adj=newArrayList<>();for(inti=0;i<n;i++){adj.add(newArrayList<>());}for(inti=0;i<edges.length;i++){adj.get(edges[i][0]).add(newint[]{edges[i][1],edges[i][2]});adj.get(edges[i][1]).add(newint[]{edges[i][0],edges[i][2]});}// create a visited array to // keep track of visited nodesboolean[]visited=newboolean[n];Arrays.fill(visited,false);// create the min heap to store the nodes// based on the costPriorityQueue<int[]>pq=newPriorityQueue<>(newComparator<int[]>(){publicintcompare(int[]a,int[]b){returnInteger.compare(a[0],b[0]);}});// push the source node in the min heappq.add(newint[]{0,src});// mark the source node as visitedvisited[src]=true;// to store the path ArrayList<Integer>path=newArrayList<>();// loop until the min heap is emptywhile(!pq.isEmpty()){// get the top element of the min heapintx=pq.peek()[1];// push the current node in the pathpath.add(x);// pop the top elementpq.poll();// if the current node is the target node// break the loopif(x==target)break;// loop through the edges of the current nodefor(inti=0;i<adj.get(x).size();i++){if(!visited[adj.get(x).get(i)[0]]){// mark the node as visitedvisited[adj.get(x).get(i)[0]]=true;// push the node in the min heappq.add(newint[]{adj.get(x).get(i)[1],adj.get(x).get(i)[0]});}}}returnpath;}publicstaticvoidmain(String[]args){intn=14;int[][]edgeList={{0,1,3},{0,2,6},{0,3,5},{1,4,9},{1,5,8},{2,6,12},{2,7,14},{3,8,7},{8,9,5},{8,10,6},{9,11,1},{9,12,10},{9,13,2}};intsource=0;inttarget=9;ArrayList<Integer>path=bestFirstSearch(edgeList,source,target,n);for(inti=0;i<path.size();i++){System.out.print(path.get(i)+" ");}}}
Python
# Function to perform Best First Searchfromheapqimportheappush,heappopdefbestFirstSearch(edges,src,target,n):# create the adjacency listadj=[[]for_inrange(n)]foredgeinedges:adj[edge[0]].append([edge[1],edge[2]])adj[edge[1]].append([edge[0],edge[2]])# create a visited array to # keep track of visited nodesvisited=[False]*n# create the min heap to store the nodes# based on the costpq=[]# push the source node in the min heapheappush(pq,[0,src])# mark the source node as visitedvisited[src]=True# to store the path path=[]# loop until the min heap is emptywhilepq:# get the top element of the min heapx=heappop(pq)[1]# push the current node in the pathpath.append(x)# if the current node is the target node# break the loopifx==target:break# loop through the edges of the current nodeforedgeinadj[x]:ifnotvisited[edge[0]]:# mark the node as visitedvisited[edge[0]]=True# push the node in the min heapheappush(pq,[edge[1],edge[0]])returnpathif__name__=="__main__":n=14edgeList=[[0,1,3],[0,2,6],[0,3,5],[1,4,9],[1,5,8],[2,6,12],[2,7,14],[3,8,7],[8,9,5],[8,10,6],[9,11,1],[9,12,10],[9,13,2]]source=0target=9path=bestFirstSearch(edgeList,source,target,n)foriinrange(len(path)):print(path[i],end=" ")
C#
// Function to perform Best First SearchusingSystem;usingSystem.Collections;usingSystem.Collections.Generic;classGfG{// Function to build the adjacency liststaticList<List<int[]>>buildAdjacencyList(int[][]edges,intn){List<List<int[]>>adj=newList<List<int[]>>();for(inti=0;i<n;i++){adj.Add(newList<int[]>());}for(inti=0;i<edges.Length;i++){adj[edges[i][0]].Add(newint[]{edges[i][1],edges[i][2]});adj[edges[i][1]].Add(newint[]{edges[i][0],edges[i][2]});}returnadj;}// Function to get the minimum element from the list (simulated priority queue)staticTuple<int,int>get_min(LinkedList<Tuple<int,int>>pq){Tuple<int,int>curr_min=newTuple<int,int>(100000,100000);foreach(vareleinpq){if(ele.Item1==curr_min.Item1){if(ele.Item2<curr_min.Item2)curr_min=ele;}else{if(ele.Item1<curr_min.Item1)curr_min=ele;}}returncurr_min;}// Function to perform Best First Search// Gives output path having lowest coststaticList<int>bestFirstSearch(int[][]edges,intsrc,inttarget,intn){List<List<int[]>>adj=buildAdjacencyList(edges,n);// create a visited array to // keep track of visited nodesint[]visited=newint[n];for(inti=0;i<n;i++){visited[i]=0;}// create the min heap to store the nodes// based on the cost (simulated using LinkedList)LinkedList<Tuple<int,int>>pq=newLinkedList<Tuple<int,int>>();// push the source node in the min heappq.AddLast(newTuple<int,int>(0,src));// mark the source node as visitedvisited[src]=1;// to store the path List<int>path=newList<int>();// loop until the min heap is emptywhile(pq.Count>0){Tuple<int,int>curr_min=get_min(pq);intx=curr_min.Item2;pq.Remove(curr_min);// push the current node in the pathpath.Add(x);// if the current node is the target node// break the loopif(x==target)break;// loop through the edges of the current nodeforeach(varedgeinadj[x]){if(visited[edge[0]]==0){// mark the node as visitedvisited[edge[0]]=1;// push the node in the min heappq.AddLast(newTuple<int,int>(edge[1],edge[0]));}}}returnpath;}staticvoidMain(){intn=14;int[][]edgeList=newint[][]{newint[]{0,1,3},newint[]{0,2,6},newint[]{0,3,5},newint[]{1,4,9},newint[]{1,5,8},newint[]{2,6,12},newint[]{2,7,14},newint[]{3,8,7},newint[]{8,9,5},newint[]{8,10,6},newint[]{9,11,1},newint[]{9,12,10},newint[]{9,13,2}};intsource=0;inttarget=9;List<int>path=bestFirstSearch(edgeList,source,target,n);foreach(intxinpath){Console.Write(x+" ");}}}
JavaScript
// Function to perform Best First SearchfunctionbestFirstSearch(edges,src,target,n){// create the adjacency listletadj=newArray(n);for(leti=0;i<n;i++){adj[i]=[];}for(leti=0;i<edges.length;i++){adj[edges[i][0]].push([edges[i][1],edges[i][2]]);adj[edges[i][1]].push([edges[i][0],edges[i][2]]);}// create a visited array to // keep track of visited nodesletvisited=newArray(n).fill(false);// create the min heap to store the nodes// based on the costclassMinHeap{constructor(){this.heap=[];}push(item){this.heap.push(item);this.bubbleUp(this.heap.length-1);}pop(){if(this.heap.length===0)returnnull;lettop=this.heap[0];letend=this.heap.pop();if(this.heap.length>0){this.heap[0]=end;this.bubbleDown(0);}returntop;}bubbleUp(index){while(index>0){letparent=Math.floor((index-1)/2);if(this.heap[index][0]<this.heap[parent][0]){[this.heap[index],this.heap[parent]]=[this.heap[parent],this.heap[index]];index=parent;}else{break;}}}bubbleDown(index){letlength=this.heap.length;while(true){letleft=2*index+1;letright=2*index+2;letsmallest=index;if(left<length&&this.heap[left][0]<this.heap[smallest][0])smallest=left;if(right<length&&this.heap[right][0]<this.heap[smallest][0])smallest=right;if(smallest!==index){[this.heap[index],this.heap[smallest]]=[this.heap[smallest],this.heap[index]];index=smallest;}else{break;}}}size(){returnthis.heap.length;}}letpq=newMinHeap();// push the source node in the min heappq.push([0,src]);// mark the source node as visitedvisited[src]=true;// to store the path letpath=[];// loop until the min heap is emptywhile(pq.size()>0){// get the top element of the min heaplettop=pq.pop();letx=top[1];// push the current node in the pathpath.push(x);// if the current node is the target node// break the loopif(x===target)break;// loop through the edges of the current nodefor(leti=0;i<adj[x].length;i++){if(!visited[adj[x][i][0]]){// mark the node as visitedvisited[adj[x][i][0]]=true;// push the node in the min heappq.push([adj[x][i][1],adj[x][i][0]]);}}}returnpath;}letedgeList=[[0,1,3],[0,2,6],[0,3,5],[1,4,9],[1,5,8],[2,6,12],[2,7,14],[3,8,7],[8,9,5],[8,10,6],[9,11,1],[9,12,10],[9,13,2]];letsource=0;lettarget=9;letn=14;letpath=bestFirstSearch(edgeList,source,target,n);for(leti=0;i<path.length;i++){process.stdout.write(path[i]+" ");}
Output
0 1 3 2 8 9
Time Complexity: O(n * log n), where n is the number of nodes. In the worst case, we may have to visit all nodes before we reach goal. Note that priority queue is implemented using Min (or Max) Heap, and insert and remove operations take O(log n) time. Space Complexity: O(n + e), where n is the number of nodes, and e is the number of edges.