1. 程式人生 > >圖的遍歷與輸出 (鄰接矩陣和鄰接表)

圖的遍歷與輸出 (鄰接矩陣和鄰接表)

#include <iostream>
#include <cstdio>
#include "graph.h"
using namespace std;


int main()
{
    freopen("data.in" , "r" , stdin);

//    cout << "\n ** 生成鄰接矩陣圖,並進行DFS遍歷輸出: "<< endl;
//    MGraph mg  ;
//    createMGraph(mg);
//    DFSTraverse(mg) ;

    cout << "\n ** 生成鄰接表圖,並進行DFS遍歷輸出: "<< endl;
    ALGraph alg ;
    createAdjList(alg);

    DFSTraverse(alg) ;

    cout << "\n ** BFS遍歷輸出: "<< endl;
    BFSTraverse(alg);

    cout << "\n ** From NO.1 To No.4: " <<endl;
    if( !GetOnePath(alg, 1, 4))
        cout << " NO Path " << endl;

    cout << endl;
    return 0 ;
}



#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED

#define N 20


typedef enum{UDG = 0,DG = 1} GraphKind ; // 圖型別:UDG無向圖,DG有向圖
typedef  char T ;
/***************************鄰接矩陣 ****************************/

typedef struct{
    T   vexs[N];      // 頂點向量
    int arcs[N][N];   // 鄰接矩陣
    int vexnum, arcnum; //頂點數,邊數
    GraphKind kind ;    // 圖型別
}MGraph ;


/**********************鄰接表****************************/
/** 弧結點型別 */
typedef struct ArcNode
{
	int      adjvex;
	ArcNode  *nextArc;
}ArcNode ;

/** 頭結點VNode,頭結點向量AdjList型別*/
typedef struct VNode
{
	T         data ;
	ArcNode * firstarc ;
}AdjList[N] ;

//VNode,
/** 鄰接圖型別*/
typedef struct {
	AdjList vertices;  //頭結點向量
	int vexnum, arcnum;
	GraphKind kind;    // UDG無向圖 ; DG有向圖
}ALGraph;

/**************************基本操作 *******************************/
void createAdjList( ALGraph &g);
void createMGraph( MGraph &g);

void DFS( ALGraph g , int v );
void DFS( MGraph g , int v );

void DFSTraverse( MGraph g );
void DFSTraverse( ALGraph g );

bool GetOnePath( ALGraph g , int v ,int d );

/**輸出鄰接表圖中第v個頂點*/
inline void PrintNode(ALGraph g, int v);


void BFSTraverse(ALGraph g);


#endif // GRAPH_H_INCLUDED

/**
  createGraph.cpp
  讀入資料,分別建立圖的兩種儲存"鄰接矩陣"和"鄰接表"
  操作簡單但繁瑣,能用它們建立圖相應儲存結構,非重點
*/

#include "iostream"
#include "graph.h"
using namespace std ;

/* 建立圖的 鄰接表結構g */
void createAdjList( ALGraph &g)
{
    int i ;

    cin >>(int&)g.kind;
    cin >> g.vexnum ; // 輸入頂點數
    cin >> g.arcnum ; // 輸入弧數

    /* 輸入結點資料,建立頭結點向量*/
    for ( i = 1 ; i <= g.vexnum ; i++ )
    {
        cin >> g.vertices[i].data ;
        g.vertices[i].firstarc = NULL ;
    }

    /*輸入弧(頭,尾),建立鄰接表*/
    for ( i= 0 ; i < g.arcnum ; i++ )
    {
        int head , tail ;
        cin >> head >> tail ;

        //生成邊結點
        ArcNode * p = new ArcNode ;
        p->adjvex = tail ;

        //頭插
        p->nextArc = g.vertices[head].firstarc ;
        g.vertices[head].firstarc = p ;

        if ( g.kind == UDG )  //無向圖,還需在尾結點的邊連結串列中插入結點
        {
            ArcNode * p = new ArcNode ;
            p->adjvex = head ;
            p->nextArc = g.vertices[tail].firstarc ;
            g.vertices[tail].firstarc = p ;
        }
    }
}

/* 建立圖的 鄰接矩陣結構g */
void createMGraph( MGraph &g)
{
    int i , j;

    cin >> (int&)g.kind;
    cin >> g.vexnum; // 輸入頂點數
    cin >> g.arcnum; // 輸入弧數

    /* 輸入結點資料,建立頂點向量*/
    for ( i = 1 ; i <= g.vexnum ; i++ )
    {
        cin >> g.vexs[i];
    }

    /*輸入弧(頭,尾),建立鄰接表*/
    for (i = 1 ; i <= g.vexnum ; i++)
        for (j = 1 ; j <= g.vexnum ; j++)
           g.arcs[i][j] = 0 ;

    for ( i= 1 ; i <= g.arcnum ; i++ )
    {
        int head , tail ;
        cin >> head >> tail ;
        g.arcs[head][tail] = 1 ;

        if ( g.kind == UDG ) // 無向圖為對稱陣
        {
             g.arcs[tail][head] = 1 ;
        }
    }
}

/**
 traverse.cpp
 鄰接矩陣圖和鄰接表圖的 深度優先搜尋(遍歷)
 鄰接表圖廣度優先搜尋(遍歷)
 鄰接表圖的指定起點和終點的路徑搜尋
 (有路則向前探索,無路則回溯.即為迷宮問題)*/

#include "iostream"
#include "graph.h"
#include <queue>

using namespace std ;

bool VISITED[N]; //訪問標誌向量

/**訪問標誌陣列全部初始化為“未訪問” */
inline void InitVisited( )
{
    for(int i=0; i<N; i++)
        VISITED[i] = false;
}

/**從某頂點出發,深度優先搜尋“鄰接矩陣”儲存的圖
 *@g 鄰接矩陣
 *@v 出發頂點編號 */
void DFS( MGraph g , int v )
{
    VISITED[v] = true ;
    cout << g.vexs[v] << "  " ;

    for ( int w = 1 ; w <= g.vexnum ; w++ )
    {
        if ( g.arcs[v][w] && !VISITED[w] )
            DFS( g , w ) ;
    }
}


/** 深度優先搜尋遍歷,"鄰接矩陣”圖
 * @g 鄰接矩陣 */
void DFSTraverse( MGraph g )
{
    int v ;

    InitVisited();//標誌陣列初始化為false

    for ( v = 1 ; v <= g.vexnum ; v++)
        if ( !VISITED[v] ) DFS(g,v) ;
}


/************* 以下為鄰接表圖的操作**************

/**輸出鄰接表圖中第v個頂點*/
inline void PrintNode(ALGraph g, int v)
{
    cout << g.vertices[v].data << " " ;
}


/**從某頂點出發,深度搜索”鄰接表“儲存的圖
 * @g 鄰接表
 * @v 出發頂點編號*/
void DFS( ALGraph g , int v )
{
    ArcNode * p ;

    VISITED[v] = true ;
    PrintNode(g,v) ;  //輸出第v個頂點
    for ( p = g.vertices[v].firstarc ; p ; p = p->nextArc )
    {
        int w  = p->adjvex ;
        if ( !VISITED[w] )
            DFS( g , w ) ;
    }
}


/** 深度優先搜尋遍歷,"鄰接表”表示的圖
 * @g 鄰接表*/
void DFSTraverse( ALGraph g )
{
    int v ;

    InitVisited();//標誌陣列初始化為false

    for ( v = 1 ; v <= g.vexnum ; v++)
        if ( !VISITED[v] )
            DFS(g,v);
}


/**BFS 廣度優先遍歷圖 (需使用佇列,這裡使用STL的queue)
 *@g 鄰接表圖
 */
void BFSTraverse(ALGraph g)
{
    int v,w;
    queue<int> q;

    InitVisited();//標誌陣列初始化為false

    for(v=1; v<=g.vexnum; v++)
    {
        if( !VISITED[v])
        {
            VISITED[v] = true;
            PrintNode(g,v) ;  //輸出第v個頂點
            q.push(v);
            while(q.size()!=0)
            {
                w = q.front();
                q.pop();
                for(ArcNode *p=g.vertices[w].firstarc; p; p=p->nextArc)
                {
                    w = p->adjvex;
                    if(!VISITED[w])
                    {
                        VISITED[w] = true;
                        PrintNode(g,w) ;  //輸出第w個頂點
                        q.push(w);
                    }
                }//for
            }//while
        }
    }
}


int PATH[100] ;// 儲存路徑
/** 基於DFS,輸出從v號到d號頂點的一條路徑 (即為迷宮問題)
 * @g 鄰接表儲存的圖
 * @v 起點編號
 * @d 終點編號
 * @len 從len開始儲存,即起點距當前頂點的距離
 * @return 存在v到s路徑true,否則false */
bool GetOnePath( ALGraph g, int s, int d, int len )
{
    ArcNode * p ;

    //到達終點,則輸出路徑並返回
    if ( d == s )
    {
        PATH[len] = s ;
        for (int i = 1 ; i <= len ; i++)
            PrintNode(g,PATH[i]) ;
        return true;
    }
    //訪問(記入路徑)並標記
    VISITED[s] = true ;
    PATH[len] = s ;

    for ( p = g.vertices[s].firstarc ; p ; p = p->nextArc )
    {
        // 從v的各個尚未訪問的鄰接點w出發 搜尋d
        int nextNode  = p->adjvex ;
        if ( !VISITED[nextNode] )
            if( GetOnePath(g, nextNode, d, len+1) )
                return true ;
    }
    return false; //從起點s的各鄰接點出發(各方向)均無路可達,則無路
}

/** 尋路徑的包裝函式*/
bool GetOnePath( ALGraph g, int s, int d )
{
     InitVisited();
     return GetOnePath(g,s,d,1);
}



0 8 9
A B C D E F G H
1 2
1 3
2 4
2 5
3 6
3 7
4 8
5 8
6 7



1 4  4
A B C D
1 2
1 3
3 4
4 1