关于A*(Astar)算法的介绍可以参考另一篇博文: A*(Astar)搜索算法的实现(C语言)
1.问题描述
在3×3的棋盘,摆有八个棋子,每个棋子上标有1至8的某一数字,不同棋子上标的数字不相同。棋盘上还有一个空格,与空格相邻的棋子可以移到空格中。要求解决的问题是:给出一个初始状态和一个目标状态,找出一种从初始转变成目标状态的移动棋子步数最少的移动步骤。
2.问题可解性
八数码问题的一个状态实际上是0~9的一个排列,对于任意给定的初始状态和目标,不一定有解,也就是说从初始状态不一定能到达目标状态。因为排列有奇排列和偶排列两类,从奇排列不能转化成偶排列或相反。 如果一个数字0~8的随机排列871526340,用F(X)表示数字X前面比它小的数的个数,全部数字的F(X)之和为Y=∑(F(X)),如果Y为奇数则称原数字的排列是奇排列,如果Y为偶数则称原数字的排列是偶排列。 例如871526340这个排列的 Y=0+0+0+1+1+3+2+3+0=10 10是偶数,所以他偶排列。871625340 Y=0+0+0+1+1+2+2+3+0=9 9是奇数,所以他奇排列。 因此,可以在运行程序前检查初始状态和目标状态的窘是否相同,相同则问题可解,应当能搜索到路径。否则无解。
3.求解步骤
1)建立一个队列,计算初始结点的估价函数f,并将初始结点入队,设置队列头和尾指针。 2)取出队列头(队列头指针所指)的结点,如果该结点是目标结点,则输出路径,程序结束。否则对结点进行扩展。 3)检查扩展出的新结点是否与队列中的结点重复,若与不能再扩展的结点重复(位于队列头指针之前),则将它抛弃;若新结点与待扩展的结点重复(位于队列头指针之后),则比较两个结点的估价函数中g的大小,保留较小g值的结点。跳至第五步。 4)如果扩展出的新结点与队列中的结点不重复,则按照它的估价函数f大小将它插入队列中的头结点后待扩展结点的适当位置,使它们按从小到大的顺序排列,最后更新队列尾指针。 5)如果队列头的结点还可以扩展,直接返回第二步。否则将队列头指针指向下一结点,再返回第二步。
4.代码实现
二叉堆代码就不贴出来了,在另一篇博文 A*(Astar)搜索算法的实现(C语言) 中已经给出,在本文最后有资源下载的链接。可以拿到完整的代码 astar_8.h
/*
* author: Atom
* date: 2012/12/04
* file: astar_8.h
*/
#ifndef ASTAR_8_H
#define ASTAR_8_H
#include "bheap.h"
#define MALLOC(type,n) (type *)malloc((n)*sizeof(type))
#define MAX(a,b) ((a)>(b))?(a):(b)
#define UP -3
#define RIGHT 1
#define DOWN 3
#define LEFT -1
int node_distance[9][9];
struct step_node
{
int step_status[9];
int f;
int g;
int h;
struct step_node* parent;
};
int _comp(struct Bheap_node* n1, struct Bheap_node* n2);
int _eq(struct Bheap_node* n1, struct Bheap_node* n2);
void astar_8(int start[9], int end[9]);
static int calc_distance(int step_status[9], int end[9]);
static int arr_idx(int n, int step_status[9]);
static void init_node_distance(int node_distance[9][9]);
static int is_end(int step_status[9], int end[9]);
static int is_reachable(int space_idx, int flag);
static int move_space(int step_status[9], int flag);
static void print_step_status(int step_status[9]);
static int check_whether_reach(int start[9], int end[9]);
#endif
astar_8.c
/*
* author: Atom
* date: 2012/12/04
* file: astar_8.c
*/
#include "astar_8.h"
int main(int argc, char* argv[])
{
int i,j;
init_node_distance(node_distance);
int start[] = {2,3,4,1,8,5,0,7,6};
int end[] = {1,2,3,8,0,4,7,6,5};
#if 1
if(check_whether_reach(start, end))
{
printf("sorry,No solution!\n");
}
else
astar_8(start, end);
#else
astar_8(start, end);
#endif
return (0);
}
static int check_whether_reach(int start[9], int end[9])
{
int re_st = 0, re_end = 0;
int tmp = 0;
int i, j;
for (i = 0; i < 9; i++)
{
for(j = 0; j < i; j++)
if (start[i] > start[j])
re_st++;
}
for (i = 0; i < 9; i++)
{
for(j = 0; j < i; j++)
if (end[i] > end[j])
re_end++;
}
return ((re_st^re_end)&0x01);
}
void astar_8(int start[9], int end[9])
{
int space_idx;
int* tmp_step = NULL;
struct Bheap *o_heap = NULL, *c_heap = NULL;
struct Bheap_node *inode = NULL, *onode = NULL;
struct step_node *fnode = NULL;
struct step_node *omnode = NULL;
struct Bheap_node *exist_node = NULL;
size_t idx;
o_heap = Bheap_create(128, BHEAP_TYPE_SMALL);
c_heap = Bheap_create(128, BHEAP_TYPE_SMALL);
/* 第一步判断可否由start状态到end状态 */
/* 将起始点入open heap */
if (NULL == (fnode = MALLOC(struct step_node, 1)))
{
fprintf(stderr, "malloc fnode error!\n");
return;
}
if (NULL == (inode = MALLOC(struct Bheap_node, 1)))
{
fprintf(stderr, "malloc inode error!\n");
return;
}
if (NULL == (tmp_step = MALLOC(int, 9)))
{
fprintf(stderr, "malloc tmp_step error!\n");
return;
}
memset(fnode, 0x00, sizeof(struct step_node));
memset(inode, 0x00, sizeof(struct Bheap_node));
memset(tmp_step, 0x00, sizeof(int) * 9);
memcpy(fnode->step_status, start, sizeof(int) * 9);
fnode->g = 0;
fnode->h = calc_distance(fnode->step_status, end);
fnode->f = fnode->g + fnode->h;
fnode->parent = NULL;
inode->value = fnode;
Bheap_push(o_heap, inode, _comp);
for ( ; ; )
{
omnode = NULL;
if (NULL == (onode = Bheap_pop(o_heap, _comp)))
{
break;
}
else
{
omnode = (struct step_node*)onode->value;
if (is_end(omnode->step_status, end))
break;
Bheap_push(c_heap, onode, _comp);
memset(tmp_step, 0x00, sizeof(int) * 9);
memcpy(tmp_step, omnode->step_status, sizeof(int) * 9);
space_idx = arr_idx(0, tmp_step);
/* 上 */
if (is_reachable(space_idx, (UP)))
{
fnode = NULL;
inode = NULL;
if (NULL == (fnode = MALLOC(struct step_node, 1)))
{
fprintf(stderr, "malloc fnode error!\n");
return;
}
if (NULL == (inode = MALLOC(struct Bheap_node, 1)))
{
fprintf(stderr, "malloc inode error!\n");
return;
}
move_space(tmp_step, (UP));
memcpy(fnode->step_status, tmp_step, sizeof(int) * 9);
fnode->g = omnode->g + 1;
fnode->h = calc_distance(tmp_step, end);
fnode->f = fnode->g + fnode->h;
fnode->parent = omnode;
inode->value = fnode;
/* 不在open heap和closed heap 中 */
if (-1 == is_Bheap_contain(o_heap, inode, _eq)
&& -1 == is_Bheap_contain(c_heap, inode, _eq))
{
Bheap_push(o_heap, inode, _comp);
if (is_end(tmp_step, end))
continue;
}
else if(-1 != (idx = is_Bheap_contain(o_heap, inode, _eq)))
{
/* 在open heap 中*/
if (NULL != (exist_node = Bheap_get(o_heap, idx)))
{
if (fnode->f < ((struct step_node *)exist_node->value)->f)
{
((struct step_node *)(exist_node->value))->f = fnode->f;
((struct step_node*)(exist_node->value))->parent = fnode->parent;
}
}
free(fnode);
free(inode);
}
else
{
free(fnode);
free(inode);
}
Bheap_push(c_heap, onode, _comp);
}
memset(tmp_step, 0x00, sizeof(int) * 9);
memcpy(tmp_step, omnode->step_status, sizeof(int) * 9);
space_idx = arr_idx(0, tmp_step);
/* 下 */
if (is_reachable(space_idx, (DOWN)))
{
fnode = NULL;
inode = NULL;
if (NULL == (fnode = MALLOC(struct step_node, 1)))
{
fprintf(stderr, "malloc fnode error!\n");
return;
}
if (NULL == (inode = MALLOC(struct Bheap_node, 1)))
{
fprintf(stderr, "malloc inode error!\n");
return;
}
move_space(tmp_step, (DOWN));
memcpy(fnode->step_status, tmp_step, sizeof(int) * 9);
fnode->g = omnode->g + 1;
fnode->h = calc_distance(tmp_step, end);
fnode->f = fnode->g + fnode->h;
fnode->parent = omnode;
inode->value = fnode;
/* 不在open heap和closed heap 中 */
if (-1 == is_Bheap_contain(o_heap, inode, _eq)
&& -1 == is_Bheap_contain(c_heap, inode, _eq))
{
Bheap_push(o_heap, inode, _comp);
if (is_end(tmp_step, end))
continue;
}
else if(-1 != (idx = is_Bheap_contain(o_heap, inode, _eq)))
{
/* 在open heap 中*/
if (NULL != (exist_node = Bheap_get(o_heap, idx)))
{
if (fnode->f < ((struct step_node *)exist_node->value)->f)
{
((struct step_node *)(exist_node->value))->f = fnode->f;
((struct step_node*)(exist_node->value))->parent = fnode->parent;
}
}
free(fnode);
free(inode);
}
else
{
free(fnode);
free(inode);
}
Bheap_push(c_heap, onode, _comp);
}
memset(tmp_step, 0x00, sizeof(int) * 9);
memcpy(tmp_step, omnode->step_status, sizeof(int) * 9);
space_idx = arr_idx(0, tmp_step);
/* 左 */
if (is_reachable(space_idx, (LEFT)))
{
fnode = NULL;
inode = NULL;
if (NULL == (fnode = MALLOC(struct step_node, 1)))
{
fprintf(stderr, "malloc fnode error!\n");
return;
}
if (NULL == (inode = MALLOC(struct Bheap_node, 1)))
{
fprintf(stderr, "malloc inode error!\n");
return;
}
move_space(tmp_step, (LEFT));
memcpy(fnode->step_status, tmp_step, sizeof(int) * 9);
fnode->g = omnode->g + 1;
fnode->h = calc_distance(tmp_step, end);
fnode->f = fnode->g + fnode->h;
fnode->parent = omnode;
inode->value = fnode;
/* 不在open heap和closed heap 中 */
if (-1 == is_Bheap_contain(o_heap, inode, _eq)
&& -1 == is_Bheap_contain(c_heap, inode, _eq))
{
Bheap_push(o_heap, inode, _comp);
if (is_end(tmp_step, end))
continue;
}
else if(-1 != (idx = is_Bheap_contain(o_heap, inode, _eq)))
{
/* 在open heap 中*/
if (NULL != (exist_node = Bheap_get(o_heap, idx)))
{
if (fnode->f < ((struct step_node *)exist_node->value)->f)
{
((struct step_node *)(exist_node->value))->f = fnode->f;
((struct step_node*)(exist_node->value))->parent = fnode->parent;
}
}
free(fnode);
free(inode);
}
else
{
free(fnode);
free(inode);
}
Bheap_push(c_heap, onode, _comp);
}
memset(tmp_step, 0x00, sizeof(int) * 9);
memcpy(tmp_step, omnode->step_status, sizeof(int) * 9);
space_idx = arr_idx(0, tmp_step);
/* 右 */
if (is_reachable(space_idx, (RIGHT)))
{
fnode = NULL;
inode = NULL;
if (NULL == (fnode = MALLOC(struct step_node, 1)))
{
fprintf(stderr, "malloc fnode error!\n");
return;
}
if (NULL == (inode = MALLOC(struct Bheap_node, 1)))
{
fprintf(stderr, "malloc inode error!\n");
return;
}
move_space(tmp_step, (RIGHT));
memcpy(fnode->step_status, tmp_step, sizeof(int) * 9);
fnode->g = omnode->g + 1;
fnode->h = calc_distance(tmp_step, end);
fnode->f = fnode->g + fnode->h;
fnode->parent = omnode;
inode->value = fnode;
/* 不在open heap和closed heap 中 */
if (-1 == is_Bheap_contain(o_heap, inode, _eq)
&& -1 == is_Bheap_contain(c_heap, inode, _eq))
{
Bheap_push(o_heap, inode, _comp);
if (is_end(tmp_step, end))
continue;
}
else if(-1 != (idx = is_Bheap_contain(o_heap, inode, _eq)))
{
/* 在open heap 中*/
if (NULL != (exist_node = Bheap_get(o_heap, idx)))
{
if (fnode->f < ((struct step_node *)exist_node->value)->f)
{
((struct step_node *)(exist_node->value))->f = fnode->f;
((struct step_node*)(exist_node->value))->parent = fnode->parent;
}
}
free(fnode);
free(inode);
}
else
{
free(fnode);
free(inode);
}
Bheap_push(c_heap, onode, _comp);
}
}
}
if (NULL == omnode)
{
printf("not found!\n");
}
else
{
while(NULL != omnode)
{
print_step_status(omnode->step_status);
printf("\n");
omnode = omnode->parent;
}
}
}
static int arr_idx(int n, int step_status[9])
{
int cnt;
for(cnt = 0; cnt < 9; cnt++)
if (n == step_status[cnt])
return cnt;
return (-1);
}
static void init_node_distance(int node_distance[9][9])
{
int i, j, val;
for (i = 0; i < 9; i++)
{
for (j = 0; j < 9; j++)
{
val = abs(i - j);
node_distance[i][j] = (int)val/3 + val%3;
}
}
}
static int calc_distance(int step_status[9], int end[9])
{
int i, tmp, ret_val = 0;
for (i = 0; i < 9; i++)
if (-1 != (tmp = arr_idx(step_status[i], end)))
ret_val += node_distance[i][tmp];
return (ret_val);
}
static int is_end(int step_status[9], int end[9])
{
int i;
for (i = 0; i < 9; i++)
if (step_status[i] != end[i])
return (0);
return (1);
}
static int is_reachable(int space_idx, int flag)
{
int x,y;
x = space_idx/3;
y = space_idx%3;
if(((UP) == flag) && (x > 0))
return (1);
else if (((DOWN) == flag) && (x < 2))
return (1);
else if (((LEFT) == flag) && (y > 0))
return (1);
else if(((RIGHT) == flag) && (y < 2))
return (1);
else
return (0);
}
static int move_space(int step_status[9], int flag)
{
int zero_idx, tmp;
zero_idx = arr_idx(0, step_status);
tmp = step_status[zero_idx];
/* 交换空格的位置 */
if (((UP) == flag) || ((DOWN) == flag) || ((LEFT) == flag) || ((RIGHT) == flag))
{
step_status[zero_idx] = step_status[zero_idx + flag];
step_status[zero_idx + flag] = tmp;
return (0);
}
return (-1);
}
static void print_step_status(int step_status[9])
{
int i;
for(i = 0; i < 9; i++)
{
printf("%d ", step_status[i]);
if (0 == ((i+1)%3) && (i != 0))
printf("\n");
}
}
/* Bheap_compare_t 函数实现 */
int _comp(struct Bheap_node* n1, struct Bheap_node* n2)
{
struct step_node *sn1 = NULL, *sn2 = NULL;
if ((NULL != n1) && (NULL != n2))
{
sn1 = (struct step_node*)n1->value;
sn2 = (struct step_node*)n2->value;
if (sn1->f > sn2->f)
return (1);
else if(sn1->f == sn2->f)
return (0);
else
return (-1);
}
else
return (0);
}
/* Bheap_equal_t 函数实现 */
int _eq(struct Bheap_node* n1, struct Bheap_node* n2)
{
struct step_node *sn1 = NULL, *sn2 = NULL;
if ((NULL != n1) && (NULL != n2))
{
sn1 = (struct step_node*)(n1->value);
sn2 = (struct step_node*)(n2->value);
return calc_distance(sn1->step_status, sn2->step_status);
}
else
return (0);
}
执行结果:
代码包下载: 八数码问题实现(C语言) Github地址: https://github.com/xielianghai/astar_8