第十二週 項目3 -圖遍歷算法實現

/*  
Copyright (c)2015,煙臺大學計算機與控制工程學院  
 All rights reserved.  
 文件名稱:項目3.cbp  
 作    者:臧新曉 
 完成日期:2016年11月12日  
 版 本 號:v1.0  
 問題描述:實現圖遍歷算法,分別輸出如下圖結構的深度優先(DFS)遍歷序列和廣度優先遍歷(BFS)序列。  
 輸入描述:無  
 程序輸出:測試數據  
1、頭文件graph.h中定義相關的數據結構並聲明用於完成基本運算的函數。對應基本運算的函數包括:   
    void ArrayToMat(int *Arr, int n, MGraph &g); //用普通數組構造圖的鄰接矩陣  
    void ArrayToList(int *Arr, int n, ALGraph *&); //用普通數組構造圖的鄰接表  
    void MatToList(MGraph g,ALGraph *&G);//將鄰接矩陣g轉換成鄰接表G  
    void ListToMat(ALGraph *G,MGraph &g);//將鄰接表G轉換成鄰接矩陣g  
    void DispMat(MGraph g);//輸出鄰接矩陣g  
    void DispAdj(ALGraph *G);//輸出鄰接表G      
2、在graph.cpp中實現這些函數  
3、用main.cpp中的main函數中完成測試。     
* 輸入描述: 無   
* 程序輸出: 測試數據   
*/  


graph.h的代碼:

#ifndef GRAPH_H_INCLUDED    
#define GRAPH_H_INCLUDED    
#include <stdio.h>    
#include <malloc.h>    
#define MAXV 100                //最大頂點個數    
#define INF 32767       //INF表示∞    
typedef int InfoType;    
//以下定義鄰接矩陣類型    
typedef struct    
{    
    int no;                     //頂點編號    
    InfoType info;              //頂點其他信息,在此存放帶權圖權值    
} VertexType;                   //頂點類型    
typedef struct                  //圖的定義    
{    
    int edges[MAXV][MAXV];      //鄰接矩陣    
    int n,e;                    //頂點數,弧數    
    VertexType vexs[MAXV];      //存放頂點信息    
} MGraph;                       //圖的鄰接矩陣類型    
//以下定義鄰接表類型    
typedef struct ANode            //弧的結點結構類型    
{    
    int adjvex;                 //該弧的終點位置    
    struct ANode *nextarc;      //指向下一條弧的指針    
    InfoType info;              //該弧的相關信息,這裏用於存放權值    
} ArcNode;    
typedef int Vertex;    
typedef struct Vnode            //鄰接表頭結點的類型    
{    
    Vertex data;                //頂點信息    
    int count;                  //存放頂點入度,只在拓撲排序中用    
    ArcNode *firstarc;          //指向第一條弧    
} VNode;    
typedef VNode AdjList[MAXV];    //AdjList是鄰接表類型    
typedef struct    
{    
    AdjList adjlist;            //鄰接表    
    int n,e;                    //圖中頂點數n和邊數e    
} ALGraph;                      //圖的鄰接表類型    
//功能:由一個反映圖中頂點鄰接關係的二維數組,構造出用鄰接矩陣存儲的圖    
//參數:Arr - 數組名,由於形式參數爲二維數組時必須給出每行的元素個數,在此將參數Arr聲明爲一維數組名(指向int的指針)    
//      n - 矩陣的階數    
//      g - 要構造出來的鄰接矩陣數據結構    
void ArrayToMat(int *Arr, int n, MGraph &g); //用普通數組構造圖的鄰接矩陣    
void ArrayToList(int *Arr, int n, ALGraph *&); //用普通數組構造圖的鄰接表    
void MatToList(MGraph g,ALGraph *&G);//將鄰接矩陣g轉換成鄰接表G    
void ListToMat(ALGraph *G,MGraph &g);//將鄰接表G轉換成鄰接矩陣g    
void DispMat(MGraph g);//輸出鄰接矩陣g    
void DispAdj(ALGraph *G);//輸出鄰接表G    
#endif // GRAPH_H_INCLUDED  
//圖基本運算函數    
#include "graph.h"    
//功能:由一個反映圖中頂點鄰接關係的二維數組,構造出用鄰接矩陣存儲的圖    
//參數:Arr - 數組名,由於形式參數爲二維數組時必須給出每行的元素個數,在此將參數Arr聲明爲一維數組名(指向int的指針)    
//      n - 矩陣的階數    
//      g - 要構造出來的鄰接矩陣數據結構    
void ArrayToMat(int *Arr, int n, MGraph &g)    
{    
    int i,j,count=0;  //count用於統計邊數,即矩陣中非0元素個數    
    g.n=n;    
    for (i=0; i<g.n; i++)    
        for (j=0; j<g.n; j++)    
        {    
            g.edges[i][j]=Arr[i*n+j]; //將Arr看作n×n的二維數組,Arr[i*n+j]即是Arr[i][j],計算存儲位置的功夫在此應用    
            if(g.edges[i][j]!=0)    
                count++;    
        }    
    g.e=count;    
}    
void ArrayToList(int *Arr, int n, ALGraph *&G)    
{    
    int i,j,count=0;  //count用於統計邊數,即矩陣中非0元素個數    
    ArcNode *p;    
    G=(ALGraph *)malloc(sizeof(ALGraph));    
    G->n=n;    
    for (i=0; i<n; i++)                 //給鄰接表中所有頭節點的指針域置初值    
        G->adjlist[i].firstarc=NULL;    
    for (i=0; i<n; i++)                 //檢查鄰接矩陣中每個元素    
        for (j=n-1; j>=0; j--)    
            if (Arr[i*n+j]!=0)      //存在一條邊,將Arr看作n×n的二維數組,Arr[i*n+j]即是Arr[i][j]    
            {    
                p=(ArcNode *)malloc(sizeof(ArcNode));   //創建一個節點*p    
                p->adjvex=j;    
                p->info=Arr[i*n+j];    
                p->nextarc=G->adjlist[i].firstarc;      //採用頭插法插入*p    
                G->adjlist[i].firstarc=p;    
            }    
    G->e=count;    
}    
void MatToList(MGraph g, ALGraph *&G)    
//將鄰接矩陣g轉換成鄰接表G    
{    
    int i,j;    
    ArcNode *p;    
    G=(ALGraph *)malloc(sizeof(ALGraph));    
    for (i=0; i<g.n; i++)                   //給鄰接表中所有頭節點的指針域置初值    
        G->adjlist[i].firstarc=NULL;    
    for (i=0; i<g.n; i++)                   //檢查鄰接矩陣中每個元素    
        for (j=g.n-1; j>=0; j--)    
            if (g.edges[i][j]!=0)       //存在一條邊    
            {    
                p=(ArcNode *)malloc(sizeof(ArcNode));   //創建一個節點*p    
                p->adjvex=j;    
                p->info=g.edges[i][j];    
                p->nextarc=G->adjlist[i].firstarc;      //採用頭插法插入*p    
                G->adjlist[i].firstarc=p;    
            }    
    G->n=g.n;    
    G->e=g.e;    
}    
void ListToMat(ALGraph *G,MGraph &g)    
//將鄰接表G轉換成鄰接矩陣g    
{    
    int i,j;    
    ArcNode *p;    
    for (i=0; i<g.n; i++)   //先初始化鄰接矩陣    
        for (j=0; j<g.n; j++)    
            g.edges[i][j]=0;    
    for (i=0; i<G->n; i++)  //根據鄰接表,爲鄰接矩陣賦值    
    {    
        p=G->adjlist[i].firstarc;    
        while (p!=NULL)    
        {    
            g.edges[i][p->adjvex]=p->info;    
            p=p->nextarc;    
        }    
    }    
    g.n=G->n;    
    g.e=G->e;    
}    
void DispMat(MGraph g)    
//輸出鄰接矩陣g    
{    
    int i,j;    
    for (i=0; i<g.n; i++)    
    {    
        for (j=0; j<g.n; j++)    
            if (g.edges[i][j]==INF)    
                printf("%3s","∞");    
            else    
                printf("%3d",g.edges[i][j]);    
        printf("\n");    
    }    
}    
void DispAdj(ALGraph *G)    
//輸出鄰接表G    
{    
    int i;    
    ArcNode *p;    
    for (i=0; i<G->n; i++)    
    {    
        p=G->adjlist[i].firstarc;    
        printf("%3d: ",i);    
        while (p!=NULL)    
        {    
            printf("-->%d/%d ",p->adjvex,p->info);    
            p=p->nextarc;    
        }    
        printf("\n");    
    }    
}  
深度優先遍歷——DFS  
  
  
#include "graph.h"    
  
  
int visited[MAXV];    
void DFS(ALGraph *G, int v)    
{    
    ArcNode *p;    
    int w;    
    visited[v]=1;    
    printf("%d ", v);    
    p=G->adjlist[v].firstarc;    
    while (p!=NULL)    
    {    
        w=p->adjvex;    
        if (visited[w]==0)    
            DFS(G,w);    
        p=p->nextarc;    
    }    
}    
  
  
int main()    
{    
    int i;    
    ALGraph *G;    
    int A[5][5]=    
    {    
        {0,1,0,1,0},    
        {1,0,1,0,0},    
        {0,1,0,1,1},    
        {1,0,1,0,1},    
        {0,0,1,1,0}    
    };    
    ArrayToList(A[0], 5, G);    
  
  
    for(i=0; i<MAXV; i++) visited[i]=0;    
    printf(" 由2開始深度遍歷:");    
    DFS(G, 2);    
    printf("\n");    
  
  
    for(i=0; i<MAXV; i++) visited[i]=0;    
    printf(" 由0開始深度遍歷:");    
    DFS(G, 0);    
    printf("\n");    
    return 0;    
}  

運行結果:


廣度優先遍歷——BFS

#include "graph.h"    
void BFS(ALGraph *G, int v)    
{    
    ArcNode *p;    
    int w,i;    
    int queue[MAXV],front=0,rear=0; //定義循環隊列    
    int visited[MAXV];     //定義存放節點的訪問標誌的數組    
    for (i=0; i<G->n; i++) visited[i]=0; //訪問標誌數組初始化    
    printf("%2d",v);            //輸出被訪問頂點的編號    
    visited[v]=1;                       //置已訪問標記    
    rear=(rear+1)%MAXV;    
    queue[rear]=v;              //v進隊    
    while (front!=rear)         //若隊列不空時循環    
    {    
        front=(front+1)%MAXV;    
        w=queue[front];             //出隊並賦給w    
        p=G->adjlist[w].firstarc;   //找w的第一個的鄰接點    
        while (p!=NULL)    
        {    
            if (visited[p->adjvex]==0)    
            {    
                printf("%2d",p->adjvex); //訪問之    
                visited[p->adjvex]=1;    
                rear=(rear+1)%MAXV; //該頂點進隊    
                queue[rear]=p->adjvex;    
            }    
            p=p->nextarc;       //找下一個鄰接頂點    
        }    
    }    
    printf("\n");    
}    
int main()    
{    
    ALGraph *G;    
    int A[5][5]=    
    {    
        {0,1,0,1,0},    
        {1,0,1,0,0},    
        {0,1,0,1,1},    
        {1,0,1,0,1},    
        {0,0,1,1,0}    
    };    
    ArrayToList(A[0], 5, G);    
  
  
    printf(" 由2開始廣度遍歷:");    
    BFS(G, 2);    
  
  
    printf(" 由0開始廣度遍歷:");    
    BFS(G, 0);    
    return 0;    
}  
運行結果:


知識點總結:
    圖算法庫的應用。
學習心得:
   這兩種算法要理解透徹,可以通過畫圖的方法實現遍歷。



發佈了80 篇原創文章 · 獲贊 11 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章