【机器学习】人工智能实验一:A*算法求解 8 数码问题(启发式搜索)(纯代码)

这篇文章主要由三个C/C++代码和1个MATLAB代码构成,一方面用于我个人的知识记录,另一方面用于交流学习

一、网上代码修改版:
1、直接上代码:
代码参考于:A*算法(解决八数码问题)

#include<bits/stdc++.h>
#define maxn 1010 //用于设置OPEN表和COLSE表(顺序表)结点的个数 
#define N 3	//4

typedef struct node { 	//八数码结构体
	int a[N][N];		//二维数组表示八数码的主要状态
	int i_0, j_0;		//空格的下标
	int d, w, f;		//搜索深度,各棋子不在正确位置的数目,总代价
	struct node *father;//指向父节点指针
} node, *p_node;

typedef struct list { 	//顺序表结构体
	p_node a[maxn];		//定义八数码结构体数组
	int length;			//记录当前顺序表中有多少结点
	int cre_node_num; 	//生成结点的个数
} list, *p_list;

//预先定义好初始和目标八数码结点(可根据具体情况自己设置)
static int si[N][N] = {2,8,3,1,6,4,7,0,5};	//初始结点
//static int si[N][N] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0 };
static int sg[N][N] = {1,2,3,8,0,4,7,6,5};	//目标结点
//static int sg[N][N] = { 1,2,3,4,6,7,8,0,5,10,11,12,9,13,14,15 };
/*  初始八数码   目标八数码
	  2 8 3			1 2 3
	  1 6 4			8 0 4
	  7 0 5			7 6 5
*/

//给初始状态八数码和目标状态八数码结构体开辟空间
p_node s_i = (p_node)malloc(sizeof(node));		//初始节点
p_node s_g = (p_node)malloc(sizeof(node));		//目标节点
//给OPEN表和CLOSE表构体开辟空间
p_list OPEN = (p_list)malloc(sizeof(list));		//OPEN表
p_list CLOSE = (p_list)malloc(sizeof(list));	//CLOSE表

//声明函数
int w(p_node s);						//1、启发函数(即h(x),可结合实际情况调整)
int f(p_node s);						//2、估价函数
void init_node();						//3、初始化
void out_node(p_node s);				//4、输出八数码
void list_reverse(p_node &p);			//5、将链表逆序
void out_list(p_list &l,int num);		//6、输出OPEN表
bool search_list(p_list &l, p_node s);  //7、对表进行查找,成功返回true
void sort_list(p_list &l);				//8、对OPEN表进行排序(按f从小到大)
void add_list(p_list &l, p_node s);		//9、加入结点到OPEN表中或CLOSE表中
void copy_node(p_node s1, p_node &s2);	//10、生成新的结点(将s2赋值给s1)
void delete_list(p_list &l);			//11、从OPEN表或CLOSE中删除结点
bool is_equal(p_node s1, p_node s2);	//12、判断两节点是否相等
bool up_mov(p_node &s);					//13、空格上移
bool down_mov(p_node &s);				//14、空格下移
bool left_mov(p_node &s);				//15、空格左移
bool right_mov(p_node &s);				//16、空格右移
void move(p_list &l,p_node s);			//17、移动父节点并加入未探索表中(扩展结点)
int find_ij(int a,int flag);			//18、找到目标函数函数对应的位置

int main()
{
	init_node();//初始化
	int num=1; 	//判断当前是第几次输出的OPEN表
	printf("\nA*算法求解八数码问题求解过程如下:\n");

	while (OPEN->length != 0 && CLOSE->length <maxn) {	//循环到CLOSE->length>=maxn的时候退出
		p_node n = OPEN->a[0];	//把Open表的第一个节点取出放入Close表,并记该节点为n
		delete_list(OPEN); //将刚取出的第一个节点删除
		CLOSE->cre_node_num++;
		add_list(CLOSE, n);//将取出的结点加CLOSE表中
		if (is_equal(n, s_g)) {	//考察节点n是否为目标节点。若是,则找到了问题的解,成功退出;
			list_reverse(n);
			while (n) {
				printf("第 %d 步:\n", n->d + 1);
				out_node(n);
				n = n->father;
			}
			printf("生成结点数:%d\n",OPEN->cre_node_num);
			printf("扩展结点数:%d\n",CLOSE->cre_node_num-1);
			break;
		}
		move(OPEN,n);			//扩展节点
		sort_list(OPEN);		//OPEN表按照f值从小到大排序 
		out_list(OPEN,num++);	//输出OPEN表 				
	}
	if (OPEN->length == 0) {
		printf("\n从初始结点无法到达目标结点!\n\n");
	}
	return 0;
}

//启发函数1:曼哈顿距离
int w(p_node s)
{
	int r = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			r += abs(i - find_ij(s->a[i][j],0)) + abs(j - find_ij(s->a[i][j],1));
		}
	}
	return r;
}

//启发函数2:返回不在对应位置数字的个数
int w1(p_node s)
{
	int r = 0;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (s->a[i][j] != sg[i][j])
				r++;
		}
	}
	if (s->a[1][1] == sg[1][1])
		r++;
	return r-1;
}

int f(p_node s)
{
	return (s->d + s->w );
}

//初始化开始状态和目标状态八数码结构体
void init_node()
{
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			s_i->a[i][j] = si[i][j];
			if (s_i->a[i][j] == 0) {
				s_i->i_0 = i;
				s_i->j_0 = j;
			}
		}
	}
	s_i->d = 0;
	s_i->w = w(s_i);
	s_i->f = f(s_i);
	s_i->father = NULL;
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			s_g->a[i][j] = sg[i][j];
			if (s_g->a[i][j] == 0) {
				s_g->i_0 = i;
				s_g->j_0 = j;
			}
		}
	}
	s_g->d = 0;
	s_g->w = w(s_g);
	s_g->f = f(s_g);
	OPEN->length = 0;
	CLOSE->length = 0;
	OPEN->cre_node_num=0;
	CLOSE->cre_node_num=0;
	add_list(OPEN, s_i);	//初始节点加入OPEN表中
	printf("初始节点为:\n");	//打印初始节点
	out_node(s_i);
	printf("目标节点为:\n");	//打印目标节点
	out_node(s_g);
}

//输出八数码
void out_node(p_node s)
{
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			printf("%d ", s->a[i][j]);
		}
		printf("\n");
	}
	printf("d=%d,f=%d\n", s->d,  s->f);
}

//将链表逆序
void list_reverse(p_node & p)
{
	p_node p_pre, p_suc;
	p_pre = NULL;
	p_suc = p->father;

	while (p) {
		p->father = p_pre;
		p_pre = p;
		if (p_suc == NULL)
			break;
		p = p_suc;
		p_suc = p_suc->father;
	}
}

//输出OPEN表
void out_list(p_list &l,int num)
{
	printf("**********************第%d次输出OPEN表**************************\n",num);
	for (int i = 0; i < l->length; i++) {
		out_node(l->a[i]);
	}
	printf("**************************************************************\n");
}

//对表进行查找,成功返回true
bool search_list(p_list &l, p_node s)
{
	for (int i = 0; i < l->length; i++) {
		if (is_equal(l->a[i], s))
			return true;
	}
	return false;
}

//对OPEN表进行排序(按f从小到大)(插入)
void sort_list(p_list &l)
{
	p_node temp = (p_node)malloc(sizeof(node));

	for (int i = 1; i < l->length; i++) {
		int j = i - 1;
		copy_node(temp, l->a[i]);
		while (j >= 0 && (temp->f < l->a[j]->f)) {
			copy_node(l->a[j + 1], l->a[j]);//l->a[j + 1] = l->a[j];
			j--;
		}
		copy_node(l->a[j + 1], temp);
	}
}

//加入结点到OPEN表中或CLOSE表中
void add_list(p_list & l, p_node s)
{
	l->a[l->length++] = s;
}

//生成新的结点(将s2赋值给s1)
void copy_node(p_node s1, p_node &s2)
{
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			s1->a[i][j] = s2->a[i][j];
		}
	}

	s1->i_0 = s2->i_0;
	s1->j_0 = s2->j_0;

	s1->d = s2->d;
	s1->w = s2->w;
	s1->f = s2->f;
	s1->father = s2->father;
}

//从OPEN表或CLOSE中删除结点
void delete_list(p_list & l)
{
	for (int i = 0; i < l->length; i++) {
		l->a[i] = l->a[i + 1];
	}
	l->length--;
}

//判断两结点是否相等
bool is_equal(p_node s1, p_node s2)
{
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (s1->a[i][j] != s2->a[i][j]) {
				return false;
			}
		}
	}

	return true;
}

//空格左移
bool left_mov(p_node &s)
{
	if (s->j_0 == 0)
		return false;
	int temp;
	temp = s->a[s->i_0][s->j_0];
	s->a[s->i_0][s->j_0] = s->a[s->i_0][s->j_0 - 1];
	s->a[s->i_0][s->j_0 - 1] = temp;

	s->j_0--;
	return true;
}

//空格右移
bool right_mov(p_node &s)
{
	if (s->j_0 == N - 1)
		return false;

	int temp;
	temp = s->a[s->i_0][s->j_0];
	s->a[s->i_0][s->j_0] = s->a[s->i_0][s->j_0 + 1];
	s->a[s->i_0][s->j_0 + 1] = temp;

	s->j_0++;
	return true;
}

//空格上移
bool up_mov(p_node &s)
{
	if (s->i_0 == 0)
		return false;

	int temp;
	temp = s->a[s->i_0][s->j_0];
	s->a[s->i_0][s->j_0] = s->a[s->i_0 - 1][s->j_0];
	s->a[s->i_0 - 1][s->j_0] = temp;

	s->i_0--;
	return true;
}

//空格下移
bool down_mov(p_node &s)
{
	if (s->i_0 == N - 1)
		return false;

	int temp;
	temp = s->a[s->i_0][s->j_0];
	s->a[s->i_0][s->j_0] = s->a[s->i_0 + 1][s->j_0];
	s->a[s->i_0 + 1][s->j_0] = temp;

	s->i_0++;
	return true;
}

//移动父节点并加入未探索表中(扩展结点)
void move(p_list &l,p_node s)
{
	p_node p1 = (p_node)malloc(sizeof(node));
	p_node p2 = (p_node)malloc(sizeof(node));
	p_node p3 = (p_node)malloc(sizeof(node));
	p_node p4 = (p_node)malloc(sizeof(node));

	copy_node(p1, s);
	copy_node(p2, s);
	copy_node(p3, s);
	copy_node(p4, s);

	p1->father = s;
	p2->father = s;
	p3->father = s;
	p4->father = s;

	//如果能够移动且在CLOSE表中不存在,则加入OPEN表中
	if (left_mov(p1) && !is_equal(p1, p1->father) && !search_list(CLOSE, p1) && !search_list(OPEN, p1)) {
		p1->d++;
		p1->w = w(p1);
		p1->f = f(p1);
		l->cre_node_num++;
		add_list(OPEN, p1);
	} else
		free(p1);

	if (right_mov(p2) && !is_equal(p2, p2->father) && !search_list(CLOSE, p2) && !search_list(OPEN, p2)) {
		p2->d++;
		p2->w = w(p2);
		p2->f = f(p2);
		l->cre_node_num++;
		add_list(OPEN, p2);
	} else
		free(p2);

	if (up_mov(p3) && !is_equal(p3, p3->father) && !search_list(CLOSE, p3) && !search_list(OPEN, p3)) {
		p3->d++;
		p3->w = w(p3);
		p3->f = f(p3);
		l->cre_node_num++;
		add_list(OPEN, p3);
	} else
		free(p3);

	if (down_mov(p4) && !is_equal(p4, p4->father) && !search_list(CLOSE, p4) && !search_list(OPEN, p4)) {
		add_list(OPEN, p4);
		p4->d++;
		p4->w = w(p4);
		p4->f = f(p4);
		l->cre_node_num++;

	} else
		free(p4);
}

int find_ij(int a,int flag)
{
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (sg[i][j] == a)
				if(flag==0)
					return i;
				else
					return j;
		}
	}
}

2、部分运行结果
在这里插入图片描述
二、他山之石:简略版
这个代码给人的主要启发是:其实照着BFS(广度搜索)的思路直接敲完,核心框架也就出来了

#include<bits/stdc++.h>
#include<queue> 
using namespace std;
const int N=3;
int fl=0;//哪种 
struct node{
	int id,fval,gval,hval;
	int faid,x,y;
	int state[N][N];
	friend bool operator<(node a,node b){
		return a.fval>b.fval;
	}
}st,ed;
int sta[N][N]={2,8,3,1,6,4,7,0,5};
int eda[N][N]={1,2,3,8,0,4,7,6,5};
//int sta[N][N]={0,1,2,3,4,5,6,7,8};
//int eda[N][N]={1,4,2,3,5,8,6,7,0};
int tar[N*N][2];
int idnum=0;
int nxt[4][2]={0,1,0,-1,1,0,-1,0};
int h(node a,int fl){
	int num=0,id=1;
	if(fl==0){//h(n)
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
//				if(i==2&&j==2&&a.state[i][j]==0) continue;
				if(a.state[i][j]!=eda[i][j])num++;
				id++;
			}
		}
	}
	else{//p(n)
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				if(a.state[i][j]==0) continue;
				int val=a.state[i][j];
				num+=abs(i-tar[val][0])+abs(j-tar[val][1]);
			}
		}
	}
	return num;
}

void init(){
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			tar[eda[i][j]][0]=i;
			tar[eda[i][j]][1]=j;
			if(sta[i][j]==0) st.x=i,st.y=j;
			st.state[i][j]=sta[i][j];
			ed.state[i][j]=eda[i][j];
		} 
	}
	st.id=idnum++;
	st.gval=0;
	st.hval=h(st,fl);
	st.fval=st.hval+st.gval;
	st.faid=-1;
} 
priority_queue<node> q;//q-open 
vector<node> close;
map<string,int> mp,mq;//close  open 
void Astar(){
	string ed1="";
	for(int i=0;i<3;i++)
		for(int j=0;j<3;j++)
			ed1+=eda[i][j];
	q.push(st);
	string ss="";
	for(int i=0;i<3;i++){
		for(int j=0;j<3;j++){
			ss+=sta[i][j];
		}
	}
	mq[ss]=1;
	while(!q.empty()){
		node nn=q.top();
		q.pop(); 
		close.push_back(nn);
		ss="";
		for(int i=0;i<3;i++){
			for(int j=0;j<3;j++){
				ss+=nn.state[i][j];
			}
		}
		if(ss==ed1){
			break;
		}
		mq[ss]=0;
		if(mp[ss]) continue;
		mp[ss]=1;
		for(int k=0;k<4;k++){
			int tx=nn.x+nxt[k][0];
			int ty=nn.y+nxt[k][1];
			if(tx<0||ty<0||tx>=N||ty>=N)continue;
			node tmp=nn;
			swap(tmp.state[tx][ty],tmp.state[nn.x][nn.y]);
			ss="";
			for(int i=0;i<3;i++)
				for(int j=0;j<3;j++)
					ss+=tmp.state[i][j];
			if(mq[ss]||mp[ss]) continue;
			tmp.faid=tmp.id;
			tmp.id=idnum++;
			tmp.gval++;
			tmp.x=tx;
			tmp.y=ty;
			tmp.hval=h(tmp,fl);
			tmp.fval=tmp.gval+tmp.hval;
			q.push(tmp);
		}
		
		
	} 
	
}
void out(){
	printf("一共扩展多少结点:%d\n",q.size()+close.size()); 
	
	printf("从初始到目标经历多少结点:%d\n",close.size()); 
	
	printf("扩展过程:\n");
	for(int i=0;i<close.size();i++){
		printf("第%d个结点为:\n",i+1);
		for(int j=0;j<N;j++){
			for(int k=0;k<N;k++)
				printf("%d ",close[i].state[j][k]); 
			puts("");
		}
	}
} 
int main()
{
	int t,i,j,k;
	init();
	Astar();
	out();
	return 0;
}

三、不知道具体出处的代码,粘贴就完事了
1、五百多行的代码即将来袭:

#include <iostream>  
#include <stdlib.h>  
#define size 3  
using namespace std;  
//定义二维数组来存储数据表示某一个特定状态  
typedef int status[size][size];  
struct SpringLink;  
  
//定义状态图中的结点数据结构  
typedef struct Node  
{  
    status data;//结点所存储的状态  
    struct Node *parent;//指向结点的父亲结点  
    struct SpringLink *child;//指向结点的后继结点  
    struct Node *next;//指向open或者closed表中的后一个结点  
    int fvalue;//结点的总的路径  
    int gvalue;//结点的实际路径  
    int hvalue;//结点的到达目标的困难程度  
}NNode , *PNode;  
  
  
//定义存储指向结点后继结点的指针的地址  
typedef struct SpringLink  
{  
    struct Node *pointData;//指向结点的指针  
    struct SpringLink *next;//指向兄弟结点  
}SPLink , *PSPLink;  
  
  
PNode open;  
PNode closed;  
  
  
//开始状态与目标状态  
status startt = {0,1,2,3,4,5,6,7,8};  
status target = {1,4,2,3,5,8,6,7,0};  
  
  
//初始化一个空链表  
void initLink(PNode &Head)  
{  
    Head = (PNode)malloc(sizeof(NNode));  
    Head->next = NULL;  
}  
  
//判断链表是否为空  
bool isEmpty(PNode Head)  
{  
    if(Head->next == NULL)  
        return true;  
    else  
        return false;  
}  
   
//从链表中拿出一个数据  
void popNode(PNode &Head , PNode &FNode)  
{  
    if(isEmpty(Head))  
    {  
        FNode = NULL;  
        return;  
    }  
    FNode = Head->next;  
    Head->next = Head->next->next;  
    FNode->next = NULL;  
}  
  
  
  
//向结点的最终后继结点链表中添加新的子结点  
void addSpringNode(PNode &Head , PNode newData)  
{  
    PSPLink newNode = (PSPLink)malloc(sizeof(SPLink));  
    newNode->pointData = newData;  
  
    newNode->next = Head->child;  
    Head->child = newNode;  
}  
  
  
//释放状态图中存放结点后继结点地址的空间  
void freeSpringLink(PSPLink &Head)  
{  
    PSPLink tmm;  
  
    while(Head != NULL)  
    {  
        tmm = Head;  
        Head = Head->next;  
        free(tmm);  
    }  
}  
  
  
//释放open表与closed表中的资源  
void freeLink(PNode &Head)  
{  
    PNode tmn;  
  
    tmn = Head;  
    Head = Head->next;  
    free(tmn);  
  
    while(Head != NULL)  
    {  
        //首先释放存放结点后继结点地址的空间  
        freeSpringLink(Head->child);  
        tmn = Head;  
        Head = Head->next;  
        free(tmn);  
    }  
}  
  
  
//向普通链表中添加一个结点  
void addNode(PNode &Head , PNode &newNode)  
{  
    newNode->next = Head->next;  
    Head->next = newNode;  
}  
  
  
//向非递减排列的链表中添加一个结点  
void addAscNode(PNode &Head , PNode &newNode)  
{  
    PNode P;  
    PNode Q;  
  
    P = Head->next;  
    Q = Head;  
    while(P != NULL && P->fvalue < newNode->fvalue)  
    {  
        Q = P;  
        P = P->next;  
    }  
    //上面判断好位置之后,下面就是简单的插入了  
    newNode->next = Q->next;  
    Q->next = newNode;  
}  
  
  
//计算结点额h值  
int computeHValue(PNode theNode)  
{  
    int num = 0;  
  
    for(int i = 0 ; i < 3 ; i++)  
    {  
        for(int j = 0 ; j < 3 ; j++)  
        {  
            if(theNode->data[i][j] != target[i][j])  
                num++;  
        }  
    }  
    return num;  
}  
  
  
//计算结点的f,g,h值  
void computeAllValue(PNode &theNode , PNode parentNode)  
{  
    if(parentNode == NULL)  
        theNode->gvalue = 0;  
    else  
        theNode->gvalue = parentNode->gvalue + 1;  
  
    theNode->hvalue = computeHValue(theNode);  
    theNode->fvalue = theNode->gvalue + theNode->hvalue;  
}  
  
  
  
//初始化函数,进行算法初始条件的设置  
void initial()  
{  
    //初始化open以及closed表  
    initLink(open);  
    initLink(closed);  
  
    //初始化起始结点,令初始结点的父节点为空结点  
    PNode NULLNode = NULL;  
    PNode Start = (PNode)malloc(sizeof(NNode));  
    for(int i = 0 ; i < 3 ; i++)  
    {  
        for(int j = 0 ; j < 3 ; j++)  
        {  
            Start->data[i][j] = startt[i][j];  
        }  
    }  
    Start->parent = NULL;  
    Start->child = NULL;  
    Start->next = NULL;  
    computeAllValue(Start , NULLNode);  
  
    //起始结点进入open表  
    addAscNode(open , Start);  
}  
  
  
//将B节点的状态赋值给A结点  
void statusAEB(PNode &ANode , PNode BNode)  
{  
    for(int i = 0 ; i < 3 ; i++)  
    {  
        for(int j = 0 ; j < 3 ; j++)  
        {  
            ANode->data[i][j] = BNode->data[i][j];  
        }  
    }  
}  
  
  
//两个结点是否有相同的状态  
bool hasSameStatus(PNode ANode , PNode BNode)  
{  
    for(int i = 0 ; i < 3 ; i++)  
    {  
        for(int j = 0 ; j < 3 ; j++)  
        {  
            if(ANode->data[i][j] != BNode->data[i][j])  
                return false;  
        }  
    }  
    return true;  
}  
  
  
  
//结点与其祖先结点是否有相同的状态  
bool hasAnceSameStatus(PNode OrigiNode , PNode AnceNode)  
{  
    while(AnceNode != NULL)  
    {  
        if(hasSameStatus(OrigiNode , AnceNode))  
            return true;  
        AnceNode = AnceNode->parent;  
    }  
    return false;  
}  
  
  
//取得方格中空的格子的位置  
void getPosition(PNode theNode , int &row , int &col)  
{  
    for(int i = 0 ; i < 3 ; i++)  
    {  
        for(int j = 0 ; j < 3 ; j++)  
        {  
            if(theNode->data[i][j] == 0)  
            {  
                row = i;  
                col = j;  
                return;  
            }  
        }  
    }  
}  
  
  
//交换两个数字的值  
void changeAB(int &A , int &B)  
{  
    int C;  
    C = B;  
    B = A;  
    A = C;  
}  
  
  
//检查相应的状态是否在某一个链表中  
bool inLink(PNode spciNode , PNode theLink , PNode &theNodeLink , PNode &preNode)  
{  
    preNode = theLink;  
    theLink = theLink->next;  
  
    while(theLink != NULL)  
    {  
        if(hasSameStatus(spciNode , theLink))  
        {  
            theNodeLink = theLink;  
            return true;  
        }  
        preNode = theLink;  
        theLink = theLink->next;  
    }  
    return false;  
}  
  
  
  
//产生结点的后继结点(与祖先状态不同)链表  
void SpringLink(PNode theNode , PNode &spring)  
{  
    int row;  
    int col;  
  
    getPosition(theNode , row , col);  
  
    //空的格子右边的格子向左移动  
    if(col != 2)  
    {  
        PNode rlNewNode = (PNode)malloc(sizeof(NNode));  
        statusAEB(rlNewNode , theNode);  
        changeAB(rlNewNode->data[row][col] , rlNewNode->data[row][col + 1]);  
        if(hasAnceSameStatus(rlNewNode , theNode->parent))  
        {  
            free(rlNewNode);//与父辈相同,丢弃本结点  
        }  
        else  
        {  
            rlNewNode->parent = theNode;  
            rlNewNode->child = NULL;  
            rlNewNode->next = NULL;  
            computeAllValue(rlNewNode , theNode);  
            //将本结点加入后继结点链表  
            addNode(spring , rlNewNode);  
        }  
    }  
    //空的格子左边的格子向右移动  
    if(col != 0)  
    {  
        PNode lrNewNode = (PNode)malloc(sizeof(NNode));  
        statusAEB(lrNewNode , theNode);  
        changeAB(lrNewNode->data[row][col] , lrNewNode->data[row][col - 1]);  
        if(hasAnceSameStatus(lrNewNode , theNode->parent))  
        {  
            free(lrNewNode);//与父辈相同,丢弃本结点  
        }  
        else  
        {  
            lrNewNode->parent = theNode;  
            lrNewNode->child = NULL;  
            lrNewNode->next = NULL;  
            computeAllValue(lrNewNode , theNode);  
            //将本结点加入后继结点链表  
            addNode(spring , lrNewNode);  
        }  
    }  
    //空的格子上边的格子向下移动  
    if(row != 0)  
    {  
        PNode udNewNode = (PNode)malloc(sizeof(NNode));  
        statusAEB(udNewNode , theNode);  
        changeAB(udNewNode->data[row][col] , udNewNode->data[row - 1][col]);  
        if(hasAnceSameStatus(udNewNode , theNode->parent))  
        {  
            free(udNewNode);//与父辈相同,丢弃本结点  
        }  
        else  
        {  
            udNewNode->parent = theNode;  
            udNewNode->child = NULL;  
            udNewNode->next = NULL;  
            computeAllValue(udNewNode , theNode);  
            //将本结点加入后继结点链表  
            addNode(spring , udNewNode);  
        }  
    }  
    //空的格子下边的格子向上移动  
    if(row != 2)  
    {  
        PNode duNewNode = (PNode)malloc(sizeof(NNode));  
        statusAEB(duNewNode , theNode);  
        changeAB(duNewNode->data[row][col] , duNewNode->data[row + 1][col]);  
        if(hasAnceSameStatus(duNewNode , theNode->parent))  
        {  
            free(duNewNode);//与父辈相同,丢弃本结点  
        }  
        else  
        {  
            duNewNode->parent = theNode;  
            duNewNode->child = NULL;  
            duNewNode->next = NULL;  
            computeAllValue(duNewNode , theNode);  
            //将本结点加入后继结点链表  
            addNode(spring , duNewNode);  
        }  
    }  
}  
  
  
//输出给定结点的状态  
void outputStatus(PNode stat)  
{  
    for(int i = 0 ; i < 3 ; i++)  
    {  
        for(int j = 0 ; j < 3 ; j++)  
        {  
            cout << stat->data[i][j] << " ";  
        }  
        cout << endl;  
    }  
}  
  
  
  
//输出最佳的路径  
void outputBestRoad(PNode goal)  
{  
    int deepnum = goal->gvalue;  
  
    if(goal->parent != NULL)  
    {  
        outputBestRoad(goal->parent);  
    }  
    cout << "第" << deepnum-- << "层的状态:" << endl;  
    outputStatus(goal);  
}  
  
  
void AStar()  
{  
    PNode tmpNode;//指向从open表中拿出并放到closed表中的结点的指针  
    PNode spring;//tmpNode的后继结点链  
    PNode tmpLNode;//tmpNode的某一个后继结点  
    PNode tmpChartNode;  
    PNode thePreNode;//指向将要从closed表中移到open表中的结点的前一个结点的指针  
    bool getGoal = false;//标识是否达到目标状态  
    long numcount = 1;//记录从open表中拿出结点的序号  
  
    initial();//对函数进行初始化  
    initLink(spring);//对后继链表的初始化  
    tmpChartNode = NULL;  
  
    cout << "从open表中拿出的结点的状态及相应的值" << endl;  
    while(!isEmpty(open))  
    {  
        //从open表中拿出f值最小的元素,并将拿出的元素放入closed表中  
        popNode(open , tmpNode);  
        addNode(closed , tmpNode);  
  
  
        cout << "第" << numcount++ << "个状态是:" << endl;  
        outputStatus(tmpNode);  
        cout << "其f值为:" << tmpNode->fvalue << endl;  
        cout << "其g值为:" << tmpNode->gvalue << endl;  
        cout << "其h值为:" << tmpNode->hvalue << endl;  
  
  
        //如果拿出的元素是目标状态则跳出循环  
        if(computeHValue(tmpNode) == 0)  
        {  
            getGoal = true;  
            break;  
        }  
  
        //产生当前检测结点的后继(与祖先不同)结点列表,产生的后继结点的parent属性指向当前检测的结点  
        SpringLink(tmpNode , spring);  
  
        //遍历检测结点的后继结点链表  
        while(!isEmpty(spring))  
        {  
            popNode(spring , tmpLNode);  
            //状态在open表中已经存在,thePreNode参数在这里并不起作用  
            if(inLink(tmpLNode , open , tmpChartNode , thePreNode))  
            {  
                addSpringNode(tmpNode , tmpChartNode);  
                if(tmpLNode->gvalue < tmpChartNode->gvalue)  
                {  
                    tmpChartNode->parent = tmpLNode->parent;  
                    tmpChartNode->gvalue = tmpLNode->gvalue;  
                    tmpChartNode->fvalue = tmpLNode->fvalue;  
                }  
                free(tmpLNode);  
            }  
            //状态在closed表中已经存在  
            else if(inLink(tmpLNode , closed , tmpChartNode , thePreNode))  
            {  
                addSpringNode(tmpNode , tmpChartNode);  
                if(tmpLNode->gvalue < tmpChartNode->gvalue)  
                {  
                    PNode commu;  
                    tmpChartNode->parent = tmpLNode->parent;  
                    tmpChartNode->gvalue = tmpLNode->gvalue;  
                    tmpChartNode->fvalue = tmpLNode->fvalue;  
                    freeSpringLink(tmpChartNode->child);  
                    tmpChartNode->child = NULL;  
                    popNode(thePreNode , commu);  
                    addAscNode(open , commu);  
                }  
                free(tmpLNode);  
            }  
            //新的状态即此状态既不在open表中也不在closed表中  
            else  
            {  
                addSpringNode(tmpNode , tmpLNode);  
                addAscNode(open , tmpLNode);  
            }  
        }  
    }  
  
    //目标可达的话,输出最佳的路径  
    if(getGoal)  
    {  
        cout << endl;  
        cout << "最佳路径长度为:" << tmpNode->gvalue << endl;
		cout << "最佳路径为:" <<endl;
        outputBestRoad(tmpNode);  
    }  
  
    //释放结点所占的内存  
    freeLink(open);  
    freeLink(closed);  
    getchar();  
}  
  
  
int main()  
{  
    AStar();  
    return 0;  
}  


2、部分运行代码:
在这里插入图片描述

四、MATLBA"实现"

%八数码A*算法程序
function [a1,b1]=shang(a)  
[x,y]=find(a==0);
a1=a;
a1(x,y)=a(x-1,y);
a1(x-1,y)=0;
b1=zhao(a1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [a1,b1]=xia(a)
[x,y]=find(a==0);
a1=a;
a1(x,y)=a(x+1,y);
a1(x+1,y)=0;
b1=zhao(a1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [a1,b1]=zuo(a)
[x,y]=find(a==0);
a1=a;
a1(x,y)=a(x,y-1);
a1(x,y-1)=0;
b1=zhao(a1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [a1,b1]=you(a)
[x,y]=find(a==0);
a1=a;
a1(x,y)=a(x,y+1);
a1(x,y+1)=0;
b1=zhao(a1);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function z=panduan(a)
global E;
global I;
I=2;
[x,y]=size(E);
z=1;
for i=1:y
    b=E{i};
    v=(b-a).^2;
    if sum(sum(v))==0
        z=0;
        break;
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function y=zhao(a)
wan=[1 2 3;8 0 4;7 6 5];
y=0;
b=a-wan;
for i=1:3
    for j=1:3
        if b(i,j)~=0
            y=y+1;
        end
    end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global E
global I
a=[2 8 3;1 0 4;7 6 5];
b=[1 2 3;8 0 4;7 6 5];
I=1;
E(1)={a};
for i=2:20
   q=b-E{i};
 if sum(sum(q.^2))   
 E(i)={kaka(E{i-1})};
 celldisp(E(i))
 else 
     break;
 end
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [a1]=kaka(a)
global I;
global E;
c=[2 8 3;1 0 4;7 6 5];
E(1)={c};
[x,y]=find(a==0);
z=9;
if x==1
    if y==1
        [x1,y1]=xia(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x2,y2]=you(a);
        if y2<z
            if panduan(x2)
            b=x2;
            z=y2;
            end
        end
        a1=b;
    end
    if y==2
        [x1,y1]=xia(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x2,y2]=zuo(a);
        if y2<z
            if panduan(x2)
            b=x2;
            z=y2;
            end
        end
        [x3,y3]=you(a);
        if y3<z
            if panduan(x3)
            b=x3;
            z=y3;
            end
        end
        a1=b;
    end
    if y==3
        [x1,y1]=xia(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x2,y2]=zuo(a);
        if y2<z
            if panduan(x2)
            b=x2;
            z=y2;
            end
        end
        a1=b;
    end
end
if x==2
    if y==1
        [x1,y1]=shang(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x2,y2]=xia(a);
        if y2<z
            if panduan(x2)
            b=x2;
            z=y2;
            end
        end
        [x3,y3]=you(a);
        if y3<z
            if panduan(x3)
            b=x3;
            z=y3;
            end
        end
        a1=b;
    end
    if y==2
        [x1,y1]=shang(a);
        if y1<z
            if panduan(x1);
            b=x1;
            z=y1;
            end
        end
        [x2,y2]=xia(a);
        if y2<z
            if panduan(x2);
            b=x2;
            z=y2;
            end
        end
        [x3,y3]=zuo(a);
        if y3<z
            if panduan(x3);
            b=x3;
            z=y3;
            end
        end
        [x4,y4]=you(a);
        if y4<z;
            if panduan(x4)
            b=x4;
            z=y4;
            end
        end
        a1=b;
    end
    if y==3
        [x1,y1]=shang(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x2,y2]=xia(a);
        if y2<z
            if panduan(x2)
            b=x2;
            z=y2;
            end
        end
        [x3,y3]=zuo(a);
        if y3<z
            if panduan(x3)
            b=x3;
            z=y3;
            end
        end
        a1=b;
    end
end
if x==3
    if y==1
        [x1,y1]=shang(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x4,y4]=you(a);
        if y4<z;
            if panduan(x4)
            b=x4;
            z=y4;
            end
        end
        a1=b;
    end
    if y==2
        [x1,y1]=shang(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x3,y3]=zuo(a);
        if y3<z
            if panduan(x3)
            b=x3;
            z=y3;
            end
        end
        [x4,y4]=you(a);
        if y4<z;
            if panduan(x4)
            b=x4;
            z=y4;
            end
        end
        a1=b;
    end
    if y==3
        [x1,y1]=shang(a);
        if y1<z
            if panduan(x1)
            b=x1;
            z=y1;
            end
        end
        [x3,y3]=zuo(a);
        if y3<z
            if panduan(x3)
            b=x3;
            z=y3;
            end
        end
        a1=b;
    end
end
E(I)={a1};
发布了86 篇原创文章 · 获赞 83 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41856733/article/details/103002786