圖演算法-介面及實現

來源:互聯網
上載者:User

許多計算應用程式不僅包含項集合,而且包含這些項對之間的連通集合。這些連通關係直接產生大量問題:跟隨這些連通 ,能夠從一個項到達另一個項嗎?從已知項,可以到達其他多少個項?從此項到彼項的最佳路徑是哪一條?

我們使用一種稱作圖(graph)的抽象對象來給這種情形建模。下面給出本文使用的研究圖演算法的基本ADT介面:

typedef struct{
 int v;
 int w;
} Edge;
Edge EDGE(int, int);

struct graph{
 int V;
 int E;
 int **adj;
};

typedef struct graph* Graph;
Graph GRAPHinit(int);
void  GRAPHinsert(Graph, Edge);
void  GRAPHremove(Graph, Edge);
int   GRAPHedges(Edge[], Graph G);
Graph GRAPHcopy(Graph);
void  GRAPHdestroy(Graph);

void  GRAPHshow(Graph G);
Graph GRAPHrand(int, int);
int ** MATRIXint(int, int, int);

接下來是他們的實現:

Edge EDGE(int v, int w)
{
 Edge edge;
 edge.v = v;
 edge.w = w;
 return edge;
}

Graph GRAPHinit(int V)
{
 Graph G = (Graph)malloc(sizeof *G);
 G->V = V;
 G->E = 0;
 G->adj = MATRIXint(V, V, 0);
 return G;
}

void GRAPHinsert(Graph G, Edge e)
{
 int v = e.v, w = e.w;
 if(G->adj[v][w] == 0)
  G->E++;
 G->adj[v][w] = 1;
 G->adj[w][v] = 1;
}

void GRAPHremove(Graph G, Edge e)
{
 int v = e.v, w = e.w;
 if(G->adj[v][w] == 1)
  G->E--;
 G->adj[v][w] = 0;
 G->adj[w][v] = 0;
}

/**
 * get the edges of the Graph
 */
int GRAPHedges(Edge a[], Graph G)
{
 int v, w, E = 0;
 for(v = 0; v < G->V; v++)
  for(w = v; w < G->V; w++)
   if(G->adj[v][w] == 1)
    a[E++] = EDGE(v, w);
 return E;
}

/**
 * create a matrix of integer
 * r - row of the matrix
 * c - column of the matrix
 * val - the value of the matrix
 */
int ** MATRIXint(int r, int c, int val)
{
 int i,j;
 int **t = (int **)malloc(r * sizeof(int *));
 for(i = 0; i<r; i++)
  t[i] = (int *)malloc(c*sizeof(int));
 for(i = 0; i<r; i++)
  for(j = 0; j<c; j++)
   t[i][j] = val;
 return t;
}

Graph GRAPHcopy(Graph G)
{
 int i,j;
 Graph g = (Graph)malloc(sizeof *G);
 g->V = G->V;
 g->E = G->E;
 g->adj = MATRIXint(G->V, G->V, 0);
 for(i = 0; i<G->V; i++)
  for(j = 0; j<G->V; j++)
   g->adj[i][j] = G->adj[i][j];
 return g;
}

/**
 * destroy the graph and free the memory, first free
 * the adj, then free the graph
 */
void GRAPHdestroy(Graph G)
{
 int i;
 for(i = 0; i<G->V; i++)
  free(G->adj[i]);
 free(G);
}

void GRAPHshow(Graph G)
{
 int i,j;
 printf("%d vertices, %d edges/n", G->V, G->E);
 for(i = 0; i < G->V; i++)
 {
  printf("%2d: ", i);
  for(j = 0; j < G->V; j++)
   if(G->adj[i][j] == 1)
    printf(" %2d", j);
  printf("/n");
 }
}

/**
 * generate a random graph which has V vertices and E edges
 */
Graph GRAPHrand(int V, int E)
{
 // create a graph
 Graph g = GRAPHinit(V);
 while(g->E < E)
 {
  Edge e;
  e.v = rand() % V;
  e.w = rand() % V;
  GRAPHinsert(g, e);
 }
 return g;
}

當然這裡面沒有涉及到遍曆圖之類的演算法,不過這是基本的東西嘛。然後我們可以編寫圖形化程式,將圖這種抽象結構以圖形的方式展現出來。下面先寫一個視窗程序,其中g為Graph類型,pt為POINT結構指標,為了在WinMain主函數和WndProc之間傳遞,將它們聲明為全域變數就可以了:
Graph g;
POINT *pt;

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);

/**
 * entry of the program
 */
int APIENTRY WinMain(HINSTANCE hInstance,
      HINSTANCE hPrevInstance,
      LPSTR    lpCmdLine,
      int       nCmdShow)
{
 // do some initialize work.
 g = GRAPHrand(25, 50);
 pt = (POINT *)malloc(sizeof(*pt)*(g->V));

 // create window struct.
 WNDCLASSEX wndclass;
 wndclass.cbClsExtra = 0;
 wndclass.cbSize = sizeof(wndclass);
 wndclass.cbWndExtra = 0;
 wndclass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
 wndclass.hCursor = ::LoadCursor(NULL, IDC_ARROW);
 wndclass.hIcon = ::LoadIcon(NULL, IDI_APPLICATION);
 wndclass.hIconSm = NULL;
 wndclass.hInstance = hInstance;
 wndclass.lpfnWndProc = WndProc;
 wndclass.lpszClassName = "MainFrame";
 wndclass.lpszMenuName = NULL;
 wndclass.style = CS_HREDRAW | CS_VREDRAW;

 // register class
 ::RegisterClassEx(&wndclass);

 // create window
 HWND hwnd = ::CreateWindowEx(0,
         "MainFrame",
         "My Program",
         WS_OVERLAPPEDWINDOW,
         CW_USEDEFAULT, // x
         CW_USEDEFAULT, // y
         CW_USEDEFAULT, // nWidth
         CW_USEDEFAULT, // nHeight
         NULL,
         NULL,
         hInstance,
         NULL);
 
 if(hwnd == NULL)
 {
  ::MessageBox(NULL, "CreateWindowEx failed", "Error", MB_OK);
  return -1;
 }
 // generate a random graph
 RandVertices(g, pt, hwnd);

 // show application window
 ::ShowWindow(hwnd, nCmdShow);
 ::UpdateWindow(hwnd);

 // message loop
 MSG msg;
 while(::GetMessage(&msg, NULL, 0, 0))
 {
  ::TranslateMessage(&msg);
  ::DispatchMessage(&msg);
 }

 return msg.wParam;
}

/**
 * Window Precedure
 */
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
 switch(message)
 {
 case WM_PAINT:  
  {
   HDC hdc;
   PAINTSTRUCT ps;
   hdc = BeginPaint(hwnd, &ps);
   // make the vertices filled
   SelectObject(ps.hdc, GetStockObject(GRAY_BRUSH));
   DrawEdges(g, pt, hwnd, hdc);
   DrawVertices(g, pt, hwnd, ps.hdc);
   EndPaint(hwnd, &ps);
   break;
  }
 case WM_DESTROY:
  ::PostQuitMessage(0);
  break;
 }
 return ::DefWindowProc(hwnd, message, wParam, lParam);
}

RandVertices()為每個頂點隨即安排一個座標,這個程式中DrawEdges(),DrawVertices()是我們圖抽象資料類型與圖形化顯示的橋樑。在此我們用它來串連抽象和具體的東西,它的實現如下:

void DrawEdges(Graph g, POINT pt[], HWND hwnd, HDC hdc)
{
 int i;
 Edge *edge = (Edge *)malloc(sizeof(*edge)*(g->E)); 

 // get the edges
 GRAPHedges(edge, g);

 // draw the edge
 for(i = 0; i < g->E; i++)
 {
  MoveToEx(hdc, pt[edge[i].v].x, pt[edge[i].v].y, NULL);
  LineTo(hdc, pt[edge[i].w].x, pt[edge[i].w].y);
 }
 free(edge);
}

void DrawVertices(Graph g, POINT pt[], HWND hwnd, HDC hdc)
{
 int i;
 // draw the vertices of the graph 
 for(i = 0; i < g->V; i++)
  Ellipse(hdc, pt[i].x-3, pt[i].y-3, pt[i].x+3, pt[i].y+3);
}

/**
 * set the position of the vertices in the client
 * remark - the size of p[] must equal to the number of the vertices in
 *          graph g
 */
void RandVertices(Graph g, POINT pt[], HWND hwnd)
{
 int i;
 int cxClient, cyClient;
 RECT rt;

 ::GetClientRect(hwnd, &rt);
 // get the width and height of the client
 cxClient = rt.right - rt.left;
 cyClient = rt.bottom - rt.top;

 // randomly set x and y for every vertices
 for(i = 0; i < g->V; i++)
 {
  pt[i].x = abs(rand())%cxClient;
  pt[i].y = abs(rand())%cyClient;
 }
}

程式很簡單,但可以進行大量的擴充,你可以對其修改,讓產生的頂點位置由你來安排,選擇繪製出定點,搜尋圖中的迴路,尋找一個定點到另一個定點的路徑等等,然後在顯示到你的介面上,相信會很有意思的,呵呵。

下面是我的一個25個頂點,50條邊的隨機產生圖,相信經過你更好的設計會產生更加複雜的圖,如果能圖形化解決實際的問題,那麼就更能為那些不理解演算法的人講述一個形象的方案了:

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.