Continuation, A*,dijkstra, performance comparison of bidirectional BFS algorithm and application of A * algorithm
Author: July March 10, 2011.
Source: Http://blog.csdn.net/v_JULY_v
--------------------------------------------------
Introduction:
The shortest path algorithm a * algorithm ,Dijkstra algorithm ,BFS algorithm , has been described in this blog. Among them,Dijkstra algorithm , and then wrote an article to continue to elaborate: two (continued), Understanding Dijkstra algorithm . However, presumably, there are still some readers of this kind of shortest path algorithm, not already clear in the chest, or, without a general approximate impression.
This article, that is, in the form of a demo diagram, compare their respective path-finding process, so that you have a clear and intuitive impression on them.
We compare the following five algorithms:
1. A * (using Manhattan distance)
2. A * (using Euclidean distance)
3. A * (using Chebyshev distance)
4. Dijkstra
5. Bi-directional breadth-first-search (bi-directional breadth First search)
Let's take the following picture as an example, the Green Square on the map represents the starting point, the red Square represents the target point, the purple squares represent obstacles, and the white squares represent the paths that can be used.
Below, we randomly place the starting point green block, the target point red block position, then, in the middle of them casually draw some obstacles,
Finally, run the program, compare using the above five algorithms, get their own different paths, each looking for the scope covered in the process, their own work flow , and from which they can see their efficiency.
A *, Dijkstra, BFS algorithm performance comparison demo:
OK, arbitrarily placed green block and red block three states (Demo tool Source: http://code.google.com/p/mycodeplayground/):
First, the starting point green block, and the target point red block on the same horizontal line:
The respective search paths are:
1. A * (using Manhattan distance)
2. A * (using Euclidean distance)
3. A * (using Chebyshev distance)
4. Dijkstra algorithm.//Obviously, Dijkstra search efficiency is significantly worse than the * * algorithm. (See it finally find the target point of the red block through the path, and coverage of the range, that can easily be seen, the following comparison, is based on the same reason.) Look at the path, look at the coverage range, evaluate the efficiency of an algorithm).
5. Bi-directional breadth-first-search (bi-directional breadth First search)
Second, the starting point of the green block, the target point red block on a slash:
the respective search paths are:
1. A * (using Manhattan distance)
2. A * (using Euclidean distance)
3. A * (using Chebyshev distance)
4. Dijkstra algorithm. Compared with the * * algorithm, the coverage range is large and the search efficiency is low.
5. Bi-directional breadth-first-search (bi-directional breadth First search)
Third, the starting point green block, the target point red block by multiple obstacles block:
the respective search path is ( same, from green to Red ):
1. A * (using Manhattan distance)
2. A * (using Euclidean distance).
3. A * (using Chebyshev distance)
4. Dijkstra ....
5. Bi-directional breadth-first-search (bi-directional breadth-first search)/coverage is as big and inefficient as the Dijkstra algorithm described above.
The efficiency of A * search algorithm
As above, is not a *, Dijkstra, bidirectional BFS algorithm performance has a general impression column? By the above demo, we can see that in the shortest path search efficiency, there are generally a*>dijkstra, two-way BFS, Dijkstra, Two-way BFS in the end which algorithm is better, but also depends on the specific situation.
From the above, we can also see that a * search algorithm is indeed a more efficient path-finding algorithm.
A * algorithm is the core of the process , at each selection of the next current search point, from all the identified but not search the point (may be different layers, or not the same path), select the lowest F value node to carry out.
All "discovered but not searched" points can be arranged by a queue (that is, the precedence queue) in ascending order F values.
Thus, in the overall search process, as long as a similar breadth-first algorithm framework, from the Priority queue pop-up team first element (f value), its possible sub nodes to calculate the G, H and F values, until the priority queue is empty (no solution) or to find the end point.
A * algorithm is related to breadth, depth first and Dijkstra algorithm : when G (n) =0, the algorithm is similar to DFS, when H (n) =0, the algorithm is similar to BFS. At the same time, if H (n) is 0, only need g (n), that is to find the shortest path from starting point to arbitrary vertex N, then convert to Single-source shortest path problem, namely Dijkstra algorithm. This can be achieved by setting H (n) to 0 or by setting g (n) to 0 through the process of searching the tree above.
Comparison of search algorithms for BFS, DFS and A *
Reference to the algorithm at the post section of the content:
No matter which search is discussed below, it is uniformly expressed in this form: the object of the search is a graph, it faces a problem, not necessarily have a clear form of storage, but it is a node may be a solution (feasible solution), the purpose of the search for two aspects, or to find feasible solutions, or from a feasible solution to solve the best solution.
We use two tables to search, one called the Open table, which indicates the set of nodes that have been expanded but not yet accessed, and the other is called the Close table, which represents the set of nodes that have been accessed.
Brute Force search (BFS,DFS)
BFS (breadth-first-search width First search)
First, put the start node into the Open table, the close table is empty, and the algorithm starts:
1, if the open table is not empty, start from the table to take a node s, if the null algorithm fails
2, S is the target solution. Yes, find a solution (continue looking, or terminate the algorithm); not to 3.
3. All subsequent nodes of s are expanded, that is, the nodes (sub nodes) that can be directly associated with s, if they are not in the close table, they are placed at the end of the open table, and S is placed in the close table, and the algorithm is repeated to 1.
DFS (depth-first-search depth First search)
First, put the start node into the Open table, the close table is empty, and the algorithm starts:
1, if the open table is not empty, start from the table to take a node s, if the null algorithm fails
2, S is the target solution. Yes, find a solution (continue looking, or terminate the algorithm); not to 3.
3. All subsequent nodes of s are expanded, that is, the nodes (sub nodes) that can be directly associated with s, if not in the close table, they are placed in the open table, and S is placed in the close table, and the algorithm is repeated to 1.
Whether it can be seen: The above BFS and DFS are different.
Carefully observe the form of the node to be accessed in the Open table, BFS from the table header, add nodes from the end of the table, that is, the open table is a queue, yes, BFS first let you think ' Queue '; Dfs, which takes a node from the open table header and adds a node from the table header, which means that the open table is a stack.
DFS used the stack, so there is a good implementation method, that is recursion, the system stack is one of the most important parts of computer programs. With recursion also has the advantage is that in the system stack only need to save the maximum depth so large space, that is, in the expansion of a node in the subsequent nodes can not be all expanded, with some environment variables record the current state, after the end of the recursive call to continue to expand.
DFS implemented using the system stack
function dfs (node s)
{
Does s exceed the maximum depth? is: corresponding processing, return;
is s the target node? to dispose of accordingly; otherwise:
{
s into the close table;
For (c=s. The first child node; C is not null; c=c. Next child node ())
if (c is not in the close table)
DFS (c); recursion
}
}
If you specify the maximum search depth of n, the system stack uses up to n units, which is equivalent to a state-indicated open table, the State is C, in the stack stored in the previous search in the middle variable C, after the end of recursion, c continue to move back. In the chess program, such as the game, is to use the basic mode of Dfs search chess situation tree, because if you use the Open table, it may not complete the search Open table is full, it is difficult to control the situation.
We say that both DFS and BFS are brute force search, because when they search for a node, they do not have any ' knowledge ' of its subsequent nodes, it thinks its children are the same ' excellent ', but the fact is not so, the subsequent nodes are good and bad. Well, that means it is ' close ' to the target node, and if it is treated as a priority, it will find the target node more quickly, thus improving the search performance as a whole.
heuristic Search
In order to improve the above algorithm, we need to expand the following node to understand the child node, here needs a valuation function, valuation function is the evaluation function, which is used to evaluate the quality of the sub node, because accurate evaluation is not possible, so called valuation. For example, the valuation function is like a microscope, a pair of ' eye ', which can tell the children who look the same hand, which is dirty, bacteria, which is not, is clean, and then to the clean children to reward. This is equivalent to the need to ' sort ', the sort is to have a price, and the time to do such work will not be helpful to the overall search efficiency, which depends entirely on the valuation function.
Sort, how to row. Which one to use. Come on, qsort. Not necessarily, to see how many nodes to row, if very few, simple sorting method is OK. Look at the specifics.
Sorting may be the whole of the open table, or the subsequent expansion of the child node ordering, the purpose of the order is to make the program heuristic, faster search of the target solution.
If the valuation function only considers the value of a certain performance of the node, regardless of the depth, the more famous is ordered search (Ordered-search), which focuses on whether the solution can be found without looking at the distance (depth) from the starting node.
If the value function takes into account the depth, or the weighted distance from the starting node to the target node, that is a *, for example, eight digital problem, if not to consider the depth, that is, do not require the minimum number of steps, moving one step is equivalent to more than one layer of the back to expand the node, depth of a layer, if the minimum number of steps, Then you need to use a *.
To put it simply, a * is to divide the valuation function into two parts, one part is the path value, the other is the general heuristic value, which is combined to estimate the value of the whole node.
from A * 's point of view look at the previous search method, if the path value of 0 is ordered search, if the path value of the node to the starting point of the distance (depth), and the heuristic value of 0, That is BFS or DFS, which is exactly the opposite, BFS from the Open table with the smallest depth to expand,
and DFS is the largest to expand from the open table. Of course only BFS is a special A *, so BFS can ask for the shortest path of the problem, but not any enlightening. Later, we will talk about a * search algorithm idea.
BFS, DFS, Kruskal, Prim, Dijkstra algorithm time complexity
Above, since mentioned A * algorithm and breadth, depth first search algorithm, then, in the following, also compare the next BFS, DFS, Kruskal, Prim, Dijkstra algorithm time complexity bar:
Generally, we know that the time complexity of the BFS,DFS algorithm is O (v+e),
The time complexity of minimum spanning tree algorithm Kruskal and prim algorithm is O (E*LGV).
If the prim algorithm is implemented by the Fibonacci heap, the algorithm time complexity is O (E+V*LGV), when | v|<<| When e|, the E+V*LGV is a big improvement.
//| v|<<| E|,=>o (E+V*LGV) << O (E*LGV), right. :D
Dijkstra algorithm, when the Fibonacci Ponachi is used as a priority queue, the algorithm time complexity is O (V*LGV + E).
See, the algorithm time complexity is the same with the prim algorithm using the Fibonacci heap implementation.
So we, say, BFS, Prime, Dijkstra algorithm is similar, single from the time complexity of each algorithm compared to see, can peep one or two.
The idea of a * search algorithm
OK, since, a * search algorithm as a good, efficient path-finding algorithm, we have to find a way to achieve it.
To implement an algorithm, first of all to clear its algorithm idea, as well as the algorithm steps and procedures, from my previous article, you can learn:
A * algorithm, as one of the most important heuristic algorithms, is widely used in the problem of optimal path solving and some strategy design.
The most important part of a * algorithm is the design of one of its valuation functions:
F (n) =g (n) +h (n)
where f (n) is the valuation of each possible test point, it has two components:
Part, G (N), which represents the cost from the starting search point to the current point (usually represented by the depth of a node in the search tree).
The other part, H (N), represents the most important part of the heuristic search, that is, the value of the current node to the target node,
The design of H (N) has a direct influence on whether the heuristic algorithm with this heuristic function can be called a * algorithm.
A heuristic algorithm with F (n) =g (n) +h (n) is a full condition for a * algorithm:
1, there is an optimal path from the starting point to the end point in the search tree.
2, the problem domain is limited.
3, the search generation value of all nodes is >0.
4, h (n) =
When all four conditions are met, a heuristic algorithm with F (n) =g (n) +h (n) is able to become a * algorithm, and the optimal solution can be found.
For a search problem, obviously, conditional 1,2,3 are very easy to meet, and conditional 4:h (n) <=h* (n) is carefully designed, because h* (n) is clearly not known, so, a satisfying condition 4 of the heuristic Strategy H (N) to come to the commendable.
However, for the optimal path search and the eight-digit problem, some related strategies h (n) are not only well understood, but also proved to be satisfying the condition 4 in theory, thus the generalization of this algorithm plays a decisive role.
The application of A * search algorithm
OK, we will apply a * search algorithm to achieve eight digital problems, the following is the main code, because the comments are detailed, no longer long-winded, have any questions, please do not hesitate to correct:
Node structure body
typedef struct NODE
{
int data[9];
Double f,g;
struct Node * parent;
}node,*lnode;
OPEN CLOSED Table Structure body
typedef struct STACK
{
Node * NPOINT;
struct Stack * NEXT;
}stack,* Lstack;
//Select the node with the lowest F value on the Open table, return the node address
nodes * Minf (Lstack * Open)
{
lstack temp = (*open)->next,min = (*open)- >NEXT,MINP = (*open);
node * MINX;
while (temp->next!= NULL)
{
if (Temp->next->npoint->f) < (min->npoint->f))
{
min = temp->next;
minp = temp;
}
temp = temp->next;
}
minx = min->npoint;
temp = minp->next;
minp->next = minp->next->next;
free (temp);
return Minx;
}
To judge whether or not to be solvable
int Canslove (node * suc, node * goal)
{
int a = 0,b = 0,i,j;
for (i = 1; i< 9;i++)
for (j = 0;j < i;j++)
{
if ((Suc->data[i] > Suc->data[j]) && Suc->data[j]!= 0)
a++;
if ((Goal->data[i] > Goal->data[j]) && Goal->data[j]!= 0)
b++;
}
if (a%2 = = b%2)
return 1;
Else
return 0;
}
Determine if nodes are equal, 1 equal, 0 unequal
int Equal (Node * Suc,node * goal)
{
for (int i = 0; i < 9; i + +)
if (Suc->data[i]!= goal->data[i]) return 0;
return 1;
}
Determines whether the node belongs to the Open table or closed table, returns the node address, or returns an empty address
Node * BELONG (node * suc,lstack * list)
{
Lstack temp = (*list)-> next;
if (temp = null) return null;
while (temp!= NULL)
{
if (Equal (Suc,temp->npoint)) return to temp-> npoint;
temp = temp->next;
}
return NULL;
}
Put the node in the open or closed table
void Putinto (Node * suc,lstack * list)
{
Stack * TEMP;
temp = (Stack *) malloc (sizeof (stack));
Temp->npoint = suc;
Temp->next = (*list)->next;
(*list)->next = temp;
}
Calculate F-Value part-Start//////////////////////////////
Double Fvalue (node suc, node goal, float speed)
{//Calculate F value
Double Distance (node,node,int);
Double h = 0;
for (int i = 1; I <= 8; i++)
H = h + Distance (suc, goal, I);
return h*speed + SUC.G; F = h + g (the search process takes precedence when the speed value increases and therefore may not return
Back to the best solution)
}
Double Distance (node suc, node goal, int i)
{//The dislocation distance of the calculation grid
int k,h1,h2;
for (k = 0; k < 9; k++)
{
if (suc.data[k] = = i) h1 = k;
if (goal.data[k] = = i) H2 = k;
}
Return double (Fabs (H1/3-H2/3) + fabs (h1%3-h2%3));
}
Calculate F-Value portion-end//////////////////////////////
function to extend the successor node-start/////////////////
int Belongprogram (Lnode * suc, Lstack * Open, Lstack * Closed, Node goal, float speed)
{//Judge whether the child node belongs to the open or closed table and make the corresponding processing
Node * temp = NULL;
int flag = 0;
if ((Belong (*suc,open)!= NULL) | | (Belong (*suc,closed)!= NULL))
{
if (Belong (*suc,open)!= NULL) temp = belong (*suc,open);
else temp = belong (*suc,closed);
if (((*SUC)->g) < (TEMP->G))
{
Temp->parent = (*SUC)->parent;
Temp->g = (*SUC)->g;
Temp->f = (*SUC)->f;
flag = 1;
}
}
Else
{
Putinto (* suc, Open);
(*suc)->f = Fvalue (**suc, goal, speed);
}
return flag;
}
void Spread (Lnode * suc, Lstack * Open, Lstack * Closed, Node goal, float speed)
{//Extended successor node Total function
int i;
Node * CHILD;
for (i = 0; i < 4; i++)
{
if (Canspread (**SUC, i+1))//To determine whether a child node in a direction can be extended
{
Child = (node *) malloc (sizeof (node)); Extended child nodes
Child->g = (*suc)->g +1; G Value of operator node
Child->parent = (*SUC); Child node parent pointer to parent node
Spreadchild (Child, I); Move spaces in this direction to generate child nodes
if (Belongprogram (&child, Open, Closed, goal, speed))//To determine whether a child node is a
In the open or closed table and make the corresponding processing
Free (child);
}
}
}
Functions extending the successor node-end//////////////////////////////////
Node * Process (lnode * org, Lnode * goal, Lstack * Open, Lstack * Closed, float speed)
{//Total executive function
while (1)
{
if ((*open)->next = = null) return null; To determine whether the open table is empty or empty, fail to exit
Node * Minf = Minf (Open); Remove the node with the lowest F value from the Open table
Putinto (Minf, Closed); Put a node into the closed table
if (Equal (Minf, *goal)) return minf; If the current node is the target node, it exits successfully
Spread (&minf, Open, Closed, **goal, speed); Extends the successor of the current node when the current node is not the target node
Node
}
}
Int Shownum (Node * result)
{//recursively displays the Move method from the initial state to the target State
if (result = NULL) return 0;
else
; {
int n = shownum (result->parent);
for (int i = 0; I