一次数据结构的作业,第一次调用WINDOWS APIS生成了图形界面

来源:互联网 发布:唯品会 有类似淘宝客 编辑:程序博客网 时间:2024/06/05 19:40

一:问题描述

求解任意图任意两个顶点间的最短路径。

二:需求分析

我的程序要能够方便的,以人性化的方式让用户输入要求解的图,所以,一个GUI 是不可少的,然后当用户输入图完毕时,要能同样方便的指定要求解的两个顶点,最好的方式就是让用户直接拿鼠标指定,但考虑到一个点确实不容易那么准确的点中,所以,我设计了只要用户的鼠标点击到已画顶点上下左右30像素内,就自动识别为要将已有点选中,并且要限制用户最多只能选中两个顶点,同样的道理,当用户输入图时,要想让某条线以已有的一个顶点出发,或者要将某条线连到已有的一个顶点上时,也设计了在已画顶点上下左右30像素内自动识别。最后,要提供一个按钮,当用户按下时,程序就根据已知条件求解出结果,并以与已画图所用线条颜色不同,粗细不同的线条将求得的路线标记出来。由于还不大会处理对客户区的输入之接收,所以对各个权值就用所画线的长度来代替了,那么这样以来,所求的结果,确实是名副其实的最短路径了。

三:概要设计

GUI的实现以C/SDK WINDOWS编程的方式解决;图以Ajacency List 来存储;最短路径的求解算法采用 Dijkstra 算法。

四:详细设计

1:定义一个临时数组 A ,当用户在画图时,按下鼠标左键,采集此时鼠标的坐标,存储在临时数组中,当用户完成一条线时,必然以松开左键结束,再次采集此时鼠标的坐标,也存储在临时数组中,如此重复,完成整个图的输入。

2:再定义一个22列的临时数组 B ,以存储用户指定要求解的两个顶点,因为左键已被使用,这时定义右键按下为选中某个要求解的顶点,并且在该顶点上画一个较大的点以突出显示,如果用户没有指定点就按了按钮,弹出一个 MESSAGE BOX 提示用户要先指定点,当用户指定了两个点后还要指定,也弹出一个 MESSAGE BOX 提示用户已经选择了两个点。

3:当准备完成后,用户按下了“开始求解”的按钮,于是程序先将A中的相邻点提取出来,构成邻接链表,然后使用 Dijkstra 算法求得最短路径,最后将所得最短路径标记出来。

由于在屏幕上接受用户输入各边的权值比较麻烦,所以本程序就以两顶点之间的实际距离为边的权值,进行求解。这并不影响数据结构的课设意义。

4Dijkstra 最短路径算法

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---///////////////////////////////////////////////////////////