注:本文已遷移至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)鄰接矩陣簡介
-- 邏輯結構分爲兩部分: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)無向圖的鄰接矩陣圖例
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>, 用頭插法生成邊鏈
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; } }
-------------------------------------------------------------
【注】博文由本文通過實踐進一步整理,若有問題,還望指出,本人會及時糾正!謝謝^^
--------------------------------------------------------------