圖的存儲方式:鄰接矩陣和鄰接表【基礎】

注:本文已遷移至CSDN,後續的更新也會在CSDN。html

http://blog.csdn.net/houchaoqun_xmu/article/details/53813630算法

http://blog.csdn.net/houchaoqun_xmu數組

【原】本文主要簡單介紹了數據結構中,圖的存儲方式,包括鄰接矩陣的存儲方式和鄰接表的存儲方式,並使用C++進一步實現。數據結構

-- 說明:本博文屬於基礎篇,適合於初學或者還沒有學且對數據結構感興趣的同窗,核心內容以下ide

  1. 圖的存儲結構理論簡介,以及建立圖的算法;spa

  2. 無向鄰接矩陣的應用,主要介紹了經過文件流讀取城市路徑(旅行商問題)的相關數據,將值賦給圖的數據結構相關的成員;.net

  3. 關於旅行商問題的數聽說明與處理;3d

-- 此外,在本文的基礎上,後續還會有6篇左右的文章基於圖的存儲結構,解決TSP旅行商問題,分別包括以下標題:指針

-------------------------------------------------------------------------------------------------
(1)TSP_旅行商問題- 蠻力法( 深度遍歷優先算法DFS )
(2)TSP_旅行商問題- 動態規劃
(3)TSP_旅行商問題- 模擬退火算法
(4)TSP_旅行商問題- 遺傳算法
(5)TSP_旅行商問題- 粒子羣算法code

-------------------------------------------------------------------------------------------------

1、圖的存儲結構

1. 鄰接矩陣表示法 - 以無向圖爲例:

  1)鄰接矩陣簡介

    -- 邏輯結構分爲兩部分:Vexs[](存儲頂點)和Arcs[][](鄰接矩陣)集合。所以,用一個一維數組存放圖中全部頂點數據;用一個二維數組存放頂點間關係(邊或弧)的數據,這個二維數組稱爲鄰接矩陣。

    -- 鄰接矩陣又分爲有向圖鄰接矩陣和無向圖鄰接矩陣,此處以無向圖爲例。

  2)無向圖鄰接矩陣的特色:

    -- 對無向圖而言,鄰接矩陣必定是對稱的,並且主對角線必定爲零(在此僅討論無向簡單圖),副對角線不必定爲0,有向圖則不必定如此;

    -- 無向圖鄰接矩陣是一個對稱矩陣;

    -- 頂點Vi的度等於第i行非零元個數,或第i列非零元個數;(有向圖沒有此特色)

    

    -- 矩陣非零元總數等於邊數的2倍;

    -- 用鄰接矩陣表示圖,很容易肯定圖中任意兩個頂點是否有邊相連;

   3)完整的數據結構表示以下:

/* 1. 圖 - 鄰接矩陣表示法 */
/* ---------------------------------------------------------------- */
/* 較完善的數據結構 */
#define VRType int
#define InfoType int
#define VertexType char
#define max_n 20
typedef enum{DG, DN, AG, AN} GraphKind;

//  弧結點與矩陣的類型
typedef struct { 
    VRType    adj;          //VRType爲弧的類型。圖--0,1;網--權值
    InfoType  *Info;        //與弧相關的信息的指針,可省略
}ArcCell, AdjMatrix[max_n][max_n];

//  圖的類型
typedef struct{        
    VertexType vexs[max_n];     // 頂點向量
    AdjMatrix  arcs;            // 鄰接矩陣
    int        vexnum, arcnum;  // 頂點數,邊數
    GraphKind  kind;            // 圖類型
}MGraph;     
 
/* ---------------------------------------------------------------- */

  4)【具體問題具體分析】根據」TSP「旅行商問題的需求,將該無向圖的鄰接矩陣簡化以下:

/* 簡化的數據結構 */

#define max_vexNum 26    // 最大城市個數
#define MAX_PATH_LENGTH 9999999
typedef struct{
    int vex_num, arc_num;                   // 頂點數 邊數
    char vexs[max_vexNum];                  // 頂點向量
    double arcs[max_vexNum][max_vexNum];    // 鄰接矩陣
}Graph;

  5)基於鄰接矩陣建立圖 - CreateGraph()

1. 輸入圖的類型Kind,0--有向圖,2--無向圖;
2. 輸入頂點數G.vexnum和邊數G.arcnum;
3. 輸入n個頂點,填入頂點數組G.vexs;
4. 輸入邊的偶對(vi,vj)或<vi,vj>, 填寫鄰接矩陣G.arcs

  6)無向圖的鄰接矩陣圖例

2. 鄰接表表示法 - 將每一個頂點的鄰接點串成一個單鏈表

   1)鄰接表的數據結構

#define  max_n   20                //最大頂點數
typedef struct ArcNode{            //邊結點
     int            adjvex;        //鄰接點的下標
     struct ArcNode    *nextarc;     //後繼鏈指針
}ArcNode;
typedef
struct VNode{     //頂點結點 VertexType data; //頂點數據 ArcNode *firstarc; //邊鏈頭指針 }VNode, AdjList[max_n];
typedef
struct{ AdjList vertices; //鄰接表 int vexnum,arcnum; //頂點數和邊數 GraphType kind;   //圖種類標誌 }ALGraph;

  2)無向圖的鄰接表 - 實例:

  3)基於鄰接表建立圖 - CreateGraph()

1. 輸入圖的類型Kind,0--有向圖,2--無向圖;
2. 輸入頂點數G.vexnum和邊數G.arcnum;
3. 輸入n個頂點,填入頂點數組G.vextices;
4. 輸入邊的偶對(vi,vj)或<vi,vj>, 用頭插法生成邊鏈

2、C++實現圖的鄰接矩陣表示法

1. 數據結構

/* 簡化的數據結構 */

#define max_vexNum 26    // 最大城市個數
#define MAX_PATH_LENGTH 9999999
typedef struct{
    int vex_num, arc_num;                  // 頂點數 邊數
    char vexs[max_vexNum];                 // 頂點向量
    double arcs[max_vexNum][max_vexNum];   // 鄰接矩陣
}Graph;

2. 文件讀取的方式,本程序採用文件流的方式進行數據的讀寫,相關代碼以下:

#include <fstream>

ifstream read_in;
read_in.open("L:\\Coding\\圖的常見操做\\圖的常見操做\\city_10.txt");
if (!read_in.is_open())
{
    cout<<"文件讀取失敗."<<endl;
    return;
}

3. TSP(旅行商問題)的實驗數據:文件名( city_10.txt )

10
A B C D E F G H I J 
0 2538.94 2873.8 2575.27 2318.1 2158.71 2216.58 3174.04 3371.13 3540.24 
2538.94 0 1073.54 111.288 266.835 395.032 410.118 637.942 853.554 1055 
2873.8 1073.54 0 964.495 988.636 1094.32 1382.73 1240.15 1460.25 1687 
2575.27 111.288 964.495 0 262.053 416.707 503.563 624.725 854.916 1068.42 
2318.1 266.835 988.636 262.053 0 163.355 395.14 885 1110.86 1318.19 
2158.71 395.032 1094.32 416.707 163.355 0 338.634 1030.34 1248.58 1447.69 
2216.58 410.118 1382.73 503.563 395.14 338.634 0 984.068 1160.26 1323.7 
3174.04 637.942 1240.15 624.725 885 1030.34 984.068 0 243.417 473.768 
3371.13 853.554 1460.25 854.916 1110.86 1248.58 1160.26 243.417 0 232.112 
3540.24 1055 1687 1068.42 1318.19 1447.69 1323.7 473.768 232.112 0 

4. 建立TSP城市的鄰接矩陣

void CreateGraph(Graph &G){
    ifstream read_in;
    read_in.open("L:\\Coding\\圖的常見操做\\圖的常見操做\\city_10.txt");
    if (!read_in.is_open())
    {
        cout<<"文件讀取失敗."<<endl;
        return;
    }
    
    read_in >> G.vex_num;
    // read_in >> G.arc_num;
    G.arc_num = 0;
    for (int i = 0;i < G.vex_num; i++)
    {
        read_in >> G.vexs[i];
    }
    G.vexs[G.vex_num] = '\0';    // char的結束符.

    for (int i = 0; i < G.vex_num;i++)
    {
        for (int j = 0; j < G.vex_num; j++)
        {
            read_in >> G.arcs[i][j];

            // calculate the arc_num
            if (G.arcs[i][j] > 0)
            {
                G.arc_num++;
            }
        }
    }

    // display
    cout<<"無向圖建立完畢,相關信息以下:"<<endl;
    cout<<"【頂點數】 G.vex_num = "<<G.vex_num<<endl;
    cout<<"【邊數】 G.arc_num = "<<G.arc_num<<endl;
    cout<<"【頂點向量】 vexs[max_vexNum] = ";
    for (int i = 0; i < G.vex_num; i++)
    {
        cout<<G.vexs[i]<<" ";
    }
    cout<<endl<<"【鄰接矩陣】 arcs[max_vexNum][max_vexNum] 以下:"<<endl;
    for (int i = 0; i < G.vex_num;i++)
    {
        for (int j = 0; j < G.vex_num; j++)
        {
            cout << std::right<<setw(10) << G.arcs[i][j]<<" ";
        }
        cout<<endl;
    }
}

5. 實驗結果

 

 

 

 

 

 

 

 

 

 

 

 

6. 旅行商問題數據的說明與處理

  1)旅行商問題的數聽說明:

     -- 目前網上有不少我國城市相關的數據,以座標點的方式表示,而本程序以及後續的程序都是以鄰接矩陣的方式體現,因此如今須要將數據進行轉換。

     -- 【城市數據】  參考網址:http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/tsp/

     -- 【TSP最優解】參考網址:http://comopt.ifi.uni-heidelberg.de/software/TSPLIB95/STSP.html

   2)轉換程序以下:

// 城市數據格式轉化

#define MAX_CITYNUM 150
void CityDataTranslate(){
    ifstream read_in;
    read_in.open("L:\\Coding\\TSP_SA模擬退火算法\\TSP_SA模擬退火算法\\ch150.txt");        // 待轉換數據,數據可從上述連接【城市數據】下載
    if (!read_in.is_open())
    {
        cout<<"文件讀取失敗."<<endl;
        return;
    }

    ofstream fout("L:\\Coding\\TSP_SA模擬退火算法\\TSP_SA模擬退火算法\\city_150.txt");        // 轉換後的數據存入文檔 city_150.txt

    double city_table[MAX_CITYNUM][MAX_CITYNUM];
    int city_No[MAX_CITYNUM];
    double city_x[MAX_CITYNUM];
    double city_y[MAX_CITYNUM];

    int vex_num;
    read_in >> vex_num;
    fout << vex_num << endl;

    for (int i = 0; i < vex_num; i++)
    {
        read_in >> city_No[i] >> city_x[i] >> city_y[i];

        fout << i + 1 <<" ";
    }
    fout<<endl;

    for (int i = 0; i < vex_num; i++)
    {
        city_table[i][i] = 0;
        for (int j = 0; j < vex_num; j++)
        {
            double temp = (city_x[i] - city_x[j])*(city_x[i] - city_x[j]) + (city_y[i] - city_y[j])*(city_y[i] - city_y[j]);
            city_table[i][j] = sqrt(temp);
            fout << city_table[i][j]<<" ";
        }
        fout<<endl;
    }
}

 -------------------------------------------------------------

【注】博文由本文通過實踐進一步整理,若有問題,還望指出,本人會及時糾正!謝謝^^

--------------------------------------------------------------

相關文章
相關標籤/搜索