一次数据结构的作业,第一次调用WINDOWS APIS生成了图形界面
来源:互联网 发布:唯品会 有类似淘宝客 编辑:程序博客网 时间:2024/06/05 19:40
一:问题描述
求解任意图任意两个顶点间的最短路径。
二:需求分析
我的程序要能够方便的,以人性化的方式让用户输入要求解的图,所以,一个GUI 是不可少的,然后当用户输入图完毕时,要能同样方便的指定要求解的两个顶点,最好的方式就是让用户直接拿鼠标指定,但考虑到一个点确实不容易那么准确的点中,所以,我设计了只要用户的鼠标点击到已画顶点上下左右30像素内,就自动识别为要将已有点选中,并且要限制用户最多只能选中两个顶点,同样的道理,当用户输入图时,要想让某条线以已有的一个顶点出发,或者要将某条线连到已有的一个顶点上时,也设计了在已画顶点上下左右30像素内自动识别。最后,要提供一个按钮,当用户按下时,程序就根据已知条件求解出结果,并以与已画图所用线条颜色不同,粗细不同的线条将求得的路线标记出来。由于还不大会处理对客户区的输入之接收,所以对各个权值就用所画线的长度来代替了,那么这样以来,所求的结果,确实是名副其实的最短路径了。
三:概要设计
GUI的实现以C/SDK WINDOWS编程的方式解决;图以Ajacency List 来存储;最短路径的求解算法采用 Dijkstra 算法。
四:详细设计
1:定义一个临时数组 A ,当用户在画图时,按下鼠标左键,采集此时鼠标的坐标,存储在临时数组中,当用户完成一条线时,必然以松开左键结束,再次采集此时鼠标的坐标,也存储在临时数组中,如此重复,完成整个图的输入。
2:再定义一个2行2列的临时数组 B ,以存储用户指定要求解的两个顶点,因为左键已被使用,这时定义右键按下为选中某个要求解的顶点,并且在该顶点上画一个较大的点以突出显示,如果用户没有指定点就按了按钮,弹出一个 MESSAGE BOX 提示用户要先指定点,当用户指定了两个点后还要指定,也弹出一个 MESSAGE BOX 提示用户已经选择了两个点。
3:当准备完成后,用户按下了“开始求解”的按钮,于是程序先将A中的相邻点提取出来,构成邻接链表,然后使用 Dijkstra 算法求得最短路径,最后将所得最短路径标记出来。
由于在屏幕上接受用户输入各边的权值比较麻烦,所以本程序就以两顶点之间的实际距离为边的权值,进行求解。这并不影响数据结构的课设意义。
4:Dijkstra 最短路径算法
Dijkstra 算法对每个顶点做标记,令L(v)表示顶点v的标记,在任何时候,有些顶点具有临时标记,有些顶点具有永久标记。w(a,b)表示顶点a,b 之间的权值。令T 代表 具有临时标记的顶点的集合。在进行算法的过程中,将对具有临时标记的顶点改为永久标记,如果L(v) 被标记为永久,则从指定起点到v的最短路径就找到了。开始时,所有的顶点都具有临时标记,在每一次迭代过程中,算法将一个顶点的标记从临时改为永久,这们,当终点得到一个永久标记时,算法就结束了。
输入:一个(连通)在加权图,其中所有的权值为正,顶点a ,顶点 z;
输出:从 a 到 z 的最短路径;
Procedure Dijkstra (w ,a ,z ,L)
L(a)=0;
For 所有顶点 x!=a do
L(x)=无穷大(在程序中可具体指定)
T=所有顶点的集合
While(z属于T) do
Begin
从T 中找出具有最小 L(v)的顶点 v
T=T-{v}
For 所有与v 相邻的顶点,且属于T 的顶点 x
L(x)=min{L(x),L(v)+w(v,x)}
记录前一个可以得到最小路径的顶点
End
End Dijkstra
五:调试分析
编写过程中只出现了一些语法错误,所以不再专门分析。
六:测试结果
本程序对简单的如两点之间直线最短是没问题的,然后做了许多肉眼看上去显然的问题也与程序求解结果相符,由于图形界面运用不太熟练,测试做得并不是太好。但从代码的编写来说,绝对有100%的把握,因为算法确实不复杂。
七:用户手册
1:运行本程序时,只需拿鼠标在客户区域内拖曳即可完成画图。
2:用右键点击已画的点表示选择这个点做为要求解的两点之一。
3:选好点后,点击“开始求解”的按钮,程序将显示所得结果。
八:程序源码
//本程序在windows xp, visual c++6.0 下编译通过,运行正常
#include<windows.h> //windows application must include this
#include<math.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM); int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE prevInstance,PSTR szCmdLine,int iCmdShow){
static TCHAR szAppName[]="Draw Line Program";
HWND hwnd; //handle of the window
MSG msg; //message structure
WNDCLASS wndclass; //window class
wndclass.style=CS_HREDRAW | CS_VREDRAW |CS_DBLCLKS; wndclass.lpfnWndProc=WndProc;
wndclass.cbClsExtra=0; //extra class memory
wndclass.cbWndExtra=0; //extra window memory
wndclass.hInstance=hInstance;
wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
wndclass.hCursor=LoadCursor(NULL,IDC_CROSS);
wndclass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);
wndclass.lpszMenuName=NULL; //no menu
wndclass.lpszClassName=szAppName; //class name
RegisterClass(&wndclass); //register this window
hwnd=CreateWindow(szAppName,"求解图任意两顶点间的最短路径",WS_OVERLAPPED|WS_CAPTION|WS_MINIMIZEBOX|WS_SYSMENU,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,iCmdShow);//let the window can be seen
UpdateWindow(hwnd); //sent the first WM_PAINT message
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg); //about keyboard and so on
DispatchMessage(&msg);
}
return msg.wParam; //return
}
struct lavertex //the real vertex of the graph
{
int ix; //x
int iy; //y
int iweight; //weight
lavertex * next; //to be a linkedlist
int symbol; //symbol for Dijkstra algorithm
int sym;
int befor_vertex;
};
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam){
static int apt[2][2]; //struct to store the temp point
static int tobe_solve[2][2];
static int vertex[1000][2];
static int i=0; //index value
static int j=0; //only for loop
static int k=0; //only for loop
static int x=0; //store the positon of the point which you choosed
static int len=0; //store the length of shortest road just got
static int start=0;
static int end=0; //the end vertex you choosed
static HWND hwndButton;
static int cxChar,cyChar;
static int position;
static int min;
static int js; //for test
static char a; //for test
static char * pa; //for test
HDC hdc; //handle to device
HPEN hPen;
PAINTSTRUCT ps; //paint struct
switch(message){
case WM_CREATE:
cxChar=LOWORD(GetDialogBaseUnits());
cyChar=HIWORD(GetDialogBaseUnits());
hwndButton=CreateWindow(TEXT("BUTTON"),"开始求解->",WS_CHILD |WS_VISIBL|BS_DEFPUSHBUTTON,70*cxChar,28*cyChar ,20*cxChar,7*cyChar/4,hwnd,(HMENU)i,((LPCREATESTRUCT)lParam)->hInstance,NULL);
return 0;
case WM_LBUTTONDOWN: //if the lbutton down
apt[0][0]=(int)LOWORD(lParam);
apt[0][1]=(int)HIWORD(lParam);
for(k=0;i>1 && k<=i-1;k++){
if((apt[0][0]>vertex[k][0]-30)&&(apt[0][0]<vertex[k][0]+30)&& (apt[0][1]>vertex[k][1]-30) && (apt[0][1]<vertex[k][1]+30)){
apt[0][0]=vertex[k][0];
apt[0][1]=vertex[k][1];
}
}
return 0;
case WM_MOUSEMOVE:
if(wParam & MK_LBUTTON){
hdc=GetDC(hwnd);
SelectObject(hdc,GetStockObject(WHITE_PEN));
MoveToEx(hdc,apt[0][0],apt[0][1],NULL);
LineTo(hdc,apt[1][0],apt[1][1]);
InvalidateRect(hwnd,NULL,FALSE);
apt[1][0]=LOWORD(lParam);
apt[1][1]=HIWORD(lParam);
SelectObject(hdc,GetStockObject(BLACK_PEN));
MoveToEx(hdc,apt[0][0],apt[0][1],NULL);
LineTo(hdc,apt[1][0],apt[1][1]);
ReleaseDC(hwnd,hdc);
}
return 0;
case WM_RBUTTONDOWN:
apt[0][0]=(int)LOWORD(lParam);
apt[0][1]=(int)HIWORD(lParam);
return 0;
case WM_RBUTTONUP:
for(k=0;i>1 && k<=i-1;k++){
if((apt[0][0]>vertex[k][0]-30) && (apt[0][0]<vertex[k][0]+30) && (apt[0][1]>vertex[k][1]-30) && (apt[0][1]<vertex[k][1]+30)){
if(x<2){
tobe_solve[x][0]=vertex[k][0];
tobe_solve[x][1]=vertex[k][1];
hdc=GetDC(hwnd);
SelectObject(hdc,GetStockObject(BLACK_BRUSH));
Ellipse(hdc,tobe_solve[x][0]-5,tobe_solve[x][1]-5,tobe_solve[x][0]+5,tobe_solve[x][1]+5);
ReleaseDC(hwnd,hdc);
x++;
}
else{
MessageBox(hwnd,"已经选择了两个点!","Error",MB_ICONERROR);
}
break;
}
}
apt[0][0]=0; //clearing for judge
apt[0][1]=0;
return 0;
case WM_LBUTTONUP:
if((apt[1][0]!=0) && (apt[1][1]!=0) && (apt[1][0]!=apt[0][0]) && (apt[1][1]!=apt[0][1])){
for(k=0;i>1 && k<=i-1;k++){
if((apt[1][0]>vertex[k][0]-30)&&(apt[1][0]<vertex[k][0]+30)&&(apt[1][1]>vertex[k][1]-30)&&(apt[1][1]<vertex[k][1]+30)){
hdc=GetDC(hwnd);
SelectObject(hdc,GetStockObject(WHITE_PEN));
MoveToEx(hdc,apt[0][0],apt[0][1],NULL);
LineTo(hdc,apt[1][0],apt[1][1]);
ReleaseDC(hwnd,hdc);
apt[1][0]=vertex[k][0];
apt[1][1]=vertex[k][1];
}
}
vertex[i][0]=apt[0][0]; //
vertex[i][1]=apt[0][1];
i++;
vertex[i][0]=apt[1][0]; //
vertex[i][1]=apt[1][1];
i++;
apt[0][0]=0; //clearing for judge
apt[0][1]=0;
apt[1][0]=0;
apt[1][1]=0;
InvalidateRect(hwnd,NULL,FALSE);
}
return 0;
case WM_COMMAND:
if(tobe_solve[1][0]==0 && tobe_solve[1][1]==0){
if(tobe_solve[0][0]==0 && tobe_solve[0][1]==0){
MessageBox(hwnd,"先用右键选择两个顶点!","Error",MB_ICONERROR);
return 0;
}
else{
MessageBox(hwnd,"你只选择了一个点,请再选择一个,然后点 开始!","Error",MB_ICONERROR);
return 0;
}
}
static lavertex * graph=new lavertex[i];
for(j=0;j<i;j++){
graph[j].ix=0;
graph[j].iy=0;
graph[j].iweight=0;
graph[j].befor_vertex=-1;
graph[j].next=NULL;
graph[j].sym=-1;
graph[j].symbol=10000000;//a very lardge figure
}
for(j=0,k=0;k<i;k+=2){
if(vertex[k][0]!=0 && vertex[k][1]!=0){
int symbol1=0;//symbol=1 ,if it has been stored
int symbol2=0;
intweight=(int)sqrt(pow((vertex[k+1][0]-vertex[k][0]),2)+pow((vertex[k+1][1]-vertex[k][1]),2));
for(int m=0;m<j;m++){
if(vertex[k][0]==graph[m].ix&&
vertex[k][1]==graph[m].iy) {
lavertex * temp=&graph[m];
while(temp->next){
temp=temp->next;
}
lavertex * temp2=new lavertex;
temp2->ix=vertex[k+1][0];
temp2->iy=vertex[k+1][1];
temp2->iweight=weight;
temp2->next=NULL;
temp->next=temp2;
symbol1=1;
break;
}
}
if(symbol1==0){
graph[j].ix=vertex[k][0]; //add a new vertex in
graph[j].iy=vertex[k][1];
lavertex * temp3=new lavertex;
graph[j].next=temp3;
temp3->ix=vertex[k+1][0];
temp3->iy=vertex[k+1][1];
temp3->iweight=weight;
temp3->next=NULL;
j++;
}
for(m=0;m<j;m++){
if(vertex[k+1][0]==graph[m].ix&&vertex[k+1][1]==graph[m].iy){
lavertex * temp=&graph[m];
while(temp->next){
temp=temp->next;
}
lavertex * temp2=new lavertex;
temp2->ix=vertex[k][0];
temp2->iy=vertex[k][1];
temp2->iweight=weight;
temp2->next=NULL;
temp->next=temp2;
symbol2=1;
break;
}
}
if(symbol2==0){
graph[j].ix=vertex[k+1][0];
//add a new vertex in
graph[j].iy=vertex[k+1][1];
lavertex * temp3=new lavertex;
graph[j].next=temp3;
temp3->ix=vertex[k][0];
temp3->iy=vertex[k][1];
temp3->iweight=weight;
temp3->next=NULL;
j++;
}
}
else break;
}
//Dijksrtra algorithm ,to finding the shortest
//road between two apointed vertexes
for(x=0;x<j;x++) //find the start vertex
{
if(graph[x].ix==tobe_solve[0][0]&&graph[x].iy==tobe_solve[0][1]){
start=x;
graph[start].symbol=0;
break;
}
}
for(x=0;x<j;x++){ //find the end vertex
if(graph[x].ix==tobe_solve[1][0]&&graph[x].iy==tobe_solve[1][1]){
end=x;
break;
}
}
while(graph[end].sym==-1){
min=0;
position=0; //to record the vertex which has the min symbol
for(x=0;x<j;x++){
if(graph[x].sym==-1){
min=graph[x].symbol;
position=x;
}
}
for(x=0;x<j;x++) //find the vertex has the minimun symbol
{
if(graph[x].sym==-1 && graph[x].symbol<min){ min=graph[x].symbol;
position=x;
}
}
static lavertex * temp4=NULL;
temp4=graph[position].next;
while(temp4){ //update the adjacent vertex
for(int m=0;m<j;m++){
if(temp4->ix==graph[m].ix&&temp4->iy==graph[m].iy){
if(graph[m].sym==-1){
if(graph[m].befor_vertex==-1){
graph[m].befor_vertex=position;
}
int a=graph[m].symbol;
intb=((graph[position].symbol)+(temp4->iweight));
if(b<a){
graph[m].symbol=b;
graph[m].befor_vertex=position;
}
}
}
}
temp4=temp4->next;
}
graph[position].sym=0; // a=(char)(graph[position].befor_vertex+48);
}
//we find the shortest road then let's paint the road
hdc=GetDC(hwnd);
hPen=CreatePen(PS_SOLID,2,RGB(255,0,0));
SelectObject(hdc,hPen);
x=end;
while(graph[x].befor_vertex!=start){
MoveToEx(hdc,graph[x].ix,graph[x].iy,NULL);
x=graph[x].befor_vertex;
LineTo(hdc,graph[x].ix,graph[x].iy);
}
MoveToEx(hdc,graph[x].ix,graph[x].iy,NULL);
LineTo(hdc,graph[start].ix,graph[start].iy);
ReleaseDC(hwnd,hdc);
return 0;
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
for(j=0;vertex[j][0]!=0 && vertex[j][1]!=0;j+=2){
MoveToEx(hdc,vertex[j][0],vertex[j][1],NULL);
LineTo(hdc,vertex[j+1][0],vertex[j+1][1]);
}
EndPaint(hwnd,&ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd,message,wParam,lParam);
}///////////////////////////////--END---///////////////////////////////////////////////////////////
- 一次数据结构的作业,第一次调用WINDOWS APIS生成了图形界面
- 我对第一次数据结构作业的理解
- 第一次作业-数据结构
- 第一次作业(数据结构)
- 开始了第一次 就会有最后一次 也许你的第一次就是你的最后一次
- 第一次作业(3.数据结构)
- 我的第一次作业
- 第一次的作业
- 数据结构第一次作业:程序设计技术规则
- C#调用非托管DLL的APIs
- C#调用非托管DLL的APIs
- 第一次出现一次的字符
- 大二 第一次数据结构作业 (数组的排序,删除,查找,插入,合并)(线性表)
- 数据结构的第一次总结
- 我的第一次汇编作业!
- 第一次的SQL小作业
- 第一次的Java编程作业
- 我的VB第一次作业
- SQLServer基本函数
- 亚马逊流域的一只蝴蝶扇动翅膀,会掀起密西西比河流域的一场风暴
- SQL Server日期格式的转换
- 下拉框,绑定数据,无法保持状态(绑定列必须是值类型)
- 操作文本文件
- 一次数据结构的作业,第一次调用WINDOWS APIS生成了图形界面
- 字符串通用代码
- Javascript代码格式化工具
- 用正则表达式完全匹配帐号名
- 程序中调出控制面板等窗口
- 肥皂泡里蕴含的科技和艺术
- ASP.Net+XML打造留言薄
- 根据类名和函数名字符串调用相关函数
- 2005年全国城镇在岗职工年平均工资