数据结构课程设计之九宫格.docx
- 文档编号:25493708
- 上传时间:2023-06-09
- 格式:DOCX
- 页数:17
- 大小:18.56KB
数据结构课程设计之九宫格.docx
《数据结构课程设计之九宫格.docx》由会员分享,可在线阅读,更多相关《数据结构课程设计之九宫格.docx(17页珍藏版)》请在冰豆网上搜索。
数据结构课程设计之九宫格
#include
#include
#include
#include
#include"Basic_Operation.h"
#defineU56//up
#defineD57//down
#defineL58//left
#defineR59//right
typedefstructLNode{
intdata;//用一个各位不相等的9位数来表示当前状态,9表示空格
intflag;//0表示由初始状态生成,1表示由末状态生成
intfangxaing;//表示双亲结点生成此结点时空格的移动方向
char*path;//存放路径的数组下标,比实际值小1
structLNode*next,*next1;//next用于队列中,next1用于链表
}LNode,*Linklist;
typedefstruct{
Linklistfront,rear;
}LinkQueue,*Queue;
voidgotoxy(intx,inty)
{
intxx=0x0b;
HANDLEhOutput;
COORDloc;
loc.X=x;
loc.Y=y;
hOutput=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput,loc);
return;
}
voidHideCursor()
{
CONSOLE_CURSOR_INFOcursor_info={1,0};
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&cursor_info);
}
intInitQueue(QueueQ)
{
Q->front=(Linklist)malloc(sizeof(LNode));
Q->rear=Q->front;
return1;
}
intEnQueue(QueueQ,Linklisttem)
{
Q->rear->next=tem;
Q->rear=tem;
return0;
}
intdequeue(QueueQ,Linklist*tem)
{
*tem=Q->front->next;
Q->front=Q->front->next;
return0;
}
intDestroyQueue(QueueQ)
{
Linklisttem,tem1;
if(Q->front==Q->rear)return0;
dequeue(Q,&tem);
while(Q->front!
=Q->rear)
{
tem1=Q->front;
dequeue(Q,&tem);
free(tem1->path);
free(tem1);
}
free(Q->rear->path);
free(Q->rear);
return0;
}
intDestroylist(Linklista)
{
Linklisttem;
while(a->next1!
=0)
{
tem=a;
a=a->next1;
free(tem->path);
free(tem);
}
return1;
}
voids*a,char*b)
{
chartem;
tem=*a;
*a=*b;
*b=tem;
}
intInitLNode(Linklist*M,char*b,intn)
{
inttemp;
(*M)=(Linklist)malloc(sizeof(LNode));
sscanf(b,"%d",&(*M)->data);
(*M)->path=(char*)malloc(2*sizeof(char));
for(temp=0;temp<9;temp++)//找到空格所在位置
if(b[temp]=='9')break;
(*M)->path[0]=temp+48;
(*M)->path[1]=0;
(*M)->flag=n;
(*M)->fangxaing=0;
return0;
}
intcheck(chara[]);//检测初始状态是否有解
intsearch(chara[],char**path);//寻找解。
将路径存入path
voidprint(char*path);//输出路径
voidmove(char*data,char*path);//动态演示
intmain(void)
{
intflag=1;//flag为0时退出
chara[9]={0};
charb[9]={0};
char*path;
chartem;
while(flag)
{
printf("请以字符串形式输入九宫格初始状态,空格用9表示。
例如:
\n");
printf("初始状态┌─┬─┬─┐\n");
printf("\t│1│2│3│\n");
printf("\t├─┼─┼─┤\n");
printf("\t│4│5│6│\n");
printf("\t├─┼─┼─┤\n");
printf("\t│7│8││\n");
printf("\t└─┴─┴─┘\n");
printf("输入\"123456789\"\n");
scanf("%s",a);
getchar();//把回车吃掉
strcpy(b,a);
if(check(b))
{
printf("unsolvable\n");
printf("输入Y测试下一个九宫格,输入其他任意键退出\n");
}
else
{
printf("空格所经路径为\n");
search(a,&path);
print(path);
move(a,path);
gotoxy(30,13);
printf("输入Y测试下一个九宫格,输入其他任意键退出\n");
gotoxy(30,14);
}
tem=getchar();
getchar();//把回车吃掉
if(tem=='y'||tem=='Y')
{
system("cls");
}
else
{
flag=0;
}
}
return0;
}
intcheck1(intn,chara[])
{
inti,m=0;
for(i=0;i if(a[i]>a[n])m++; returnm; } intcheck(chara[]) { inti,tem=0; for(i=0;i<9;i++)//找到空格所在位置 if(a[i]=='9')break; while(i<6) { s[i],&a[i+3]); i=i+3; } while(i<8) { s[i],&a[i+1]); i=i+1; }//将空格置于右下角的位置来推算是否成立。 数学原理如下: /* 假设图中的a是3*3数字拼图标准的结果,则对于图b的状态是不可能变换成a的。 证明起来需要用到高等代数里逆序数的概念, 具体的说是用到了一个简单的定理。 定义: 在一个1,2,...,n的排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。 一个排列中逆序的总数就称为这个排列的逆序数。 逆序数为偶数的排列称为偶排列;逆序数为奇数的排列称为奇排列。 如2431中,21,43,41,31是逆序,逆序数是4,为偶排列。 ——这是北大《高等代数》上的定义。 定理: 交换一个排列中的两个数,则排列的奇偶性发生改变。 (证明见任何一本《高等代数》) 我们将空格看成数字9(数字9对应空位),按正常顺序看a图,9个数字排列是123456789,其逆序数是0,是偶排列; b图是123456879,逆序数是1,是奇排列。 我们知道,我们能够移动空块相邻的块, 这里的移动相当于一种特殊的对换(相邻对换),例如: 对于b图,移动6就相当于9和6互换(9向上移动了), 移动7就相当于9和7互换(9向左移动了)。 现在假设从b图经过一系列的平移变到了a图, 则空格块9必然移动(对换)了偶数次(向左一次必然要再向右一次回来,向上一次必然要向下再回来,最终才能够回到右下角的位置), 根据上面的定理最终变成的排列必然是仍然是奇排列(和b相同), 然而a图是偶排列,因而产生矛盾,因此b图不可能通过平移变成最终的a图。 */ for(i=0;i<9;i++)//求逆置数 { tem=tem+check1(i,a); } returntem%2; } voidnextpath(Linklistparent,Linklistchild,intn) { child->path=(char*)malloc(strlen(parent->path)+2); strcpy(child->path,parent->path); child->path[strlen(parent->path)]=n+48; child->path[strlen(parent->path)+1]=0; } intnext(Linklistparent,Linklist*child,intflag) { chartem[10]={0}; inttemp; sprintf(tem,"%d",parent->data); *child=(Linklist)malloc(sizeof(LNode)); for(temp=0;temp<9;temp++)//找到空格所在位置 if(tem[temp]=='9')break; switch(flag) { caseU: s[temp],&tem[temp-3]);nextpath(parent,*child,temp-3);break; caseD: s[temp],&tem[temp+3]);nextpath(parent,*child,temp+3);break; caseL: s[temp],&tem[temp-1]);nextpath(parent,*child,temp-1);break; caseR: s[temp],&tem[temp+1]);nextpath(parent,*child,temp+1);break; } (*child)->flag=parent->flag; sscanf(tem,"%d",&((*child)->data)); (*child)->fangxaing=flag; return0; } intf(intn) {//哈希函数 intm=0,i,a[8]={40320,5040,720,120,24,6,2,1}; chartem[9]; sprintf(tem,"%d",n); for(i=0;i<8;i++) { m=m+(tem[i]-49+check1(i,tem)-i)*a[i]; } //a=((n/100000000)-1)*40320+(((n%100000000)/10000000)-1)*5040+(((n%10000000)/1000000)-1)*720+(((n%1000000)/100000)-1)*120; //m=a+(((n%100000)/10000)-1)*24+(((n%10000)/1000)-1)*6+(((n%1000)/100)-1)*2+(((n%100)/10)-1); returnm+1; } intinhxb(Linklisttem,Linklista[]) {//哈希函数为所有比表示这个状态的各位不相等的九位数小的各位不相等的九位数的个数,所以不会产生冲突 //将tem放入正确的位置,并利用结点中的next构造一个头结点为hxb[0]的单链表便于之后释放空间 intn,m; n=tem->data; m=f(n); a[m]=tem; tem->next1=a[0]; a[0]=tem; return1; } intbfs(QueueQ,Linklistparent,Linklisthxb[]) {//对结点tem进行宽度优先搜索,并将子状态入队列, intm,x,y;//x,y表示空格在3*3矩阵中的位置, chartemp[9]; Linklistchild; m=f(parent->data); if(hxb[m]! =0) { if(hxb[m]->flag==parent->flag) return1; else return0; } inhxb(parent,hxb);//进入已搜索的列表 sprintf(temp,"%d",parent->data); for(m=0;m<9;m++)//找到空格所在位置 if(temp[m]=='9')break; y=m%3+1;x=m/3+1; if(x<3&&parent->fangxaing! =U) { next(parent,&child,D); EnQueue(Q,child); } if(x>1&&parent->fangxaing! =D) { next(parent,&child,U); EnQueue(Q,child); } if(y<3&&parent->fangxaing! =L) { next(parent,&child,R); EnQueue(Q,child); } if(y>1&&parent->fangxaing! =R) { next(parent,&child,L); EnQueue(Q,child); } return1; } intsearch(chara[],char**path) { LinkQueuem,n;//分别用于从初始状态,以及末状态同步开始的两路搜索 Linklistl1,l2,temp1,temp2; Linklist*hxb;//哈希表 hxb=(Linklist*)calloc(362881,sizeof(Linklist)); hxb[0]=(Linklist)malloc(sizeof(LNode)); hxb[0]->next1=0; intflag1=1,flag2=1,i,j,k;//找到结果时flag=0;i,j,k作为计数量使用 char*b="123456789"; InitLNode(&l1,a,0);//初始化节点l1,l2 InitLNode(&l2,b,1); InitQueue(&m);//初始化队列m,n InitQueue(&n); EnQueue(&m,l1);//l1,l2入队列 EnQueue(&n,l2); while(flag1&&flag2) { dequeue(&n,&temp2); flag2=bfs(&n,temp2,hxb); dequeue(&m,&temp1); flag1=bfs(&m,temp1,hxb); } if(0==flag1) { i=f(temp1->data); (*path)=(char*)malloc(strlen(temp1->path)+strlen(hxb[i]->path)); strcpy((*path),temp1->path); for(j=strlen(temp1->path),k=strlen(hxb[i]->path)-1;k>=0;j++,k--) (*path)[j-1]=hxb[i]->path[k]; } else { i=f(temp2->data); (*path)=(char*)malloc(strlen(temp2->path)+strlen(hxb[i]->path)+1); strcpy((*path),hxb[i]->path); for(j=strlen(hxb[i]->path),k=strlen(temp2->path)-1;k>=0;j++,k--) (*path)[j-1]=temp2->path[k]; } (*path)[j-1]=0; DestroyQueue(&m); DestroyQueue(&n); Destroylist(hxb[0]); return1; } voidmove(char*data,char*path) { intx,y,m,n,tem,a,b;//x,y,m,n用于计算光标位置,a储存当前空格所在,b储存空格将要移动位置 char*temp; temp=data; m=30; n=5; HideCursor();//隐藏光标 for(tem=0;tem<9;tem++)//找到空格所在位置 if(temp[tem]=='9')break; temp[tem]=''; tem=n; gotoxy(m,n++);printf("动态演示: "); gotoxy(m,n++);printf("┌─┬─┬─┐"); gotoxy(m,n++);printf("││││"); gotoxy(m,n++);printf("├─┼─┼─┤"); gotoxy(m,n++);printf("││││"); gotoxy(m,n++);printf("├─┼─┼─┤"); gotoxy(m,n++);printf("││││"); gotoxy(m,n++);printf("└─┴─┴─┘"); n=tem; for(x=1;x<4;x++) for(y=1;y<4;y++) { gotoxy((m-1)+4*y,n+2*x); printf("%c",*temp++); } a=(*path)-48; path++; while((*path)! =0) { Sleep(1500); b=(*path)-48; s[a],&data[b]); a=b; path++; temp=data; for(x=1;x<4;x++) for(y=1;y<4;y++) { gotoxy((m-1)+4*y,n+2*x); printf("%c",*temp++); } } } voidprint(char*path) { intx,y,m,i=0; while((*path)! =0) { if((i%3)==0)printf("\n"); m=(*path)-48; y=m%3+1;x=m/3+1; printf("(%d,%d)",x,y); path++; i++; } printf("\n"); system("Pause"); }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数据结构 课程设计 九宫