詳解資料結構——圖之鄰接矩陣表示法
一、圖的建立
圖是表達“多對多”的關係的一種資料結構。
它由非空的有限頂點集合和有限邊集合組成。
1. 頂點集合常常由陣列表示。
陣列下標表示頂點位置。
陣列內容包含頂點資料,並且要新增判定是否被訪問過的標誌標量,為其餘操作提供引數。
其資料型別定義如下:
struct Vertex { T data; bool isVisited; }
2. 邊集合的儲存常用鄰接矩陣或者鄰接表。
邊數值(權值)表示頂點之間有某種關係,0表示兩個頂點之間沒有邊,也即沒有關係。
鄰接矩陣是一個二維陣列,matrix[頂點數][頂點數]。也可定義為一個省一半空間的一維陣列 n(n+1)/2,不利於理解,不作說明。
最簡單的圖用來呈現頂點之間的關係。頂點型別可以只包含一個用來判斷是否被訪問過的標誌變數。用bool或者int陣列表示頂點。
<pre name="code" class="cpp">//graph.h
#ifndef GRAGH_H#define GRAGH_H
class Graph {
public:
Graph(const int &capacity);
~Graph();
void insertEdge(const int &indexA, const int &indexB, const int &weight = 1);
//成員變數只需要三個。
private:
int capacity; //圖的頂點個數。
bool *pVertex; //儲存圖的頂點。
int *pMatrix; //儲存圖的邊。
}
#endif
實現檔案:
//graph.cpp #include "graph.h" /* 通過初始化列表建立一張圖。 並對pVertex、pMatrix進行值初始化。 pVertex的每個元素值初始化為false,pMatrix的每個元素值初始化為0. */ inline Graph::Graph(const int &capacity): capacity(capacity), pVertex(new bool[capacity]()), pMatrix(new int[capacity * capacity]()) {} <span style="color:#808000;">inline</span><pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style="color:#800080;">Graph</span><span style="color:#000000;">::~</span><span style="color:#800080;">Graph</span><span style="color:#000000;">()</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">{</span>
delete[]pVertex;
delete[]pMatrix;
}
inline
voidGraph::insertEdge(constint &indexA,const int&indexB,const intweight){
//插入一條從A點指向B點的邊。
pMatrix[indexA*capacity+indexB]=weight;
//無向圖需要插入一條從B指向A的邊。
pMatrix[indexB*capacity+indexA]=weight;
}
1. pVertex下標表示頂點位置。
2. pVertex值表示頂點是否被訪問過,初始化為false。
3. pMatrix值表示頂點之間的關係,初始化為0。
4. 新增邊的資訊,就形成了一張圖。
二、圖的遍歷
有了圖之後,我們就要對它進行一些操作。
首先是遍歷:
1. 深度優先搜尋Depth First Search,類似於樹的先序遍歷。
2. 廣度優先搜尋Breadth First Search,類似於樹的層序遍歷。
為此,在graph.h標頭檔案中新增四個函式:
//graph.h
public:
<span style="color:#808000;"> void</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">DFS</span><span style="color:#000000;">(</span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span>index<span style="color:#000000;">);</span><pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style="color:#c0c0c0;"> </span><span style="color:#808000;">void</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">BFS</span><span style="color:#000000;">(</span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span>index<span style="color:#000000;">);</span>
voidresetVertex(); private:
constint&getEdgeWeight(constint&indexA,constint&indexB);
其中的resetVertex是用來在下一個遍歷之前,重置所有的頂點為未訪問過的狀態。
若是用int陣列表示,則可傳入一個值,用來判定頂點的訪問狀態,也就不需要resetVertex。
而getEdgeWeight函式是返回從A點到B點的邊的權值,代表了兩個頂點的關係。
其實現如下:
//graph.cpp
#include <iostream>
#include <queue> //包含標頭檔案,為BFS提供佇列容器。
<span style="color:#808000;">inline</span><pre style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#000000;">&</span><span style="color:#c0c0c0;"> </span><span style="color:#800080;">Graph</span><span style="color:#000000;">::</span><span style="color:#000000;">getEdgeWeight</span><span style="color:#000000;">(</span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span><span style="color:#000000;">indexA</span><span style="color:#000000;">,</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">const</span><span style="color:#c0c0c0;"> </span><span style="color:#808000;">int</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">&</span><span style="color:#000000;">indexB</span><span style="color:#000000;">)</span><span style="color:#c0c0c0;"> </span><span style="color:#000000;">{</span>
returnpMatrix[indexA*capacity+indexB];
}
//打印出從index開始,進行深度優先的索引次序。
voidGraph::DFS(constint&index){
std::cout<<index<<"";
pVertex[index]=true;
for(inti(0);i<capacity;++i){
if(getEdgeWeight(index,i)>0&&!pVertex[i])
DFS(i);
}
}
/打印出從index開始,進行廣度優先的索引次序。
voidGraph::BFS(constint&index){
std::queue<int>que;
que.push(index);
pVertex[index]=true;
while(!que.empty()){
intsubcript(que.front());
que.pop();
std::cout<<subcript<<"";
for(inti(0);i<capacity;++i){
if(getEdgeWeight(subcript,i)>0&&!pVertex[i]){
que.push(i);
pVertex[i]=true;
}
}
}
}
//重置頂點為未訪問過。
voidGraph::resetVertex(){
for(inti(0);i<capacity;++i)
pVertex[i]=false;
}
三、最短路徑Shortest Path
圖的重要應用之一,最短路徑。
。。。怎麼感覺寫部落格好累啊,寫了一個多小時,才寫了這麼點兒。
後面的最短路徑和最小生成樹感覺這樣寫下去得四五個小時。
有空再寫完。