對“圖的存儲結構”的理解

圖的存儲結構

1 鄰接矩陣
兩個數組來表示圖
1)一個【一維數組】存儲圖的【頂點】信息
2)一個【二維數組】存儲圖的【邊】的信息
a) 無向圖
無向圖的鄰接矩陣是一個 對稱矩陣 並且對角線上元素數值爲 0
因爲無向圖只要兩個頂點v1,v2之間有邊,那麼不管是v1 -> v2 還是 v2 -> v1都是有邊 
又因爲,在圖結構中,目前只研究簡單圖結構(無向圖兩個頂點之間只有一條邊
並且頂點沒有到自身的邊)所以鄰接矩陣對角線上的元素爲 0
兩個頂點v1,v2之間有邊 -> 鄰接矩陣中的(v1,v2) = 1; 否則 (v1,v2)= 0

無向圖中的度:
頂點所對應的行 或 列 中非0元素的個數,就是該頂點的度

b) 有向圖
有向圖的鄰接矩陣不是一個對稱矩陣,但是矩陣主對角線上的值 仍然爲 0,原因和無向圖中的一樣

兩個頂點的邊是由順序的 (v1,v2)有邊,!= (v2,v1)就有邊,正因爲這個原因
有向圖的鄰接矩陣不是對稱矩陣

鄰接矩陣中的值,比如(v1,v2)的值,就是v1,v2之間的權值

有向圖中的度分爲,出度,入度,在鄰接矩陣中,入度,出度是這樣計算的:
入度:頂點所對應的【列】中非0元素的個數
出度:頂點所對應的【行】中非0元素的個數
3)創建鄰接矩陣
a) 創建鄰接矩陣存儲結構
typedef char VertexType;
typedef int EdgeType;
#define Max 100 //最大頂點數
#define INFINITY 65535 //如果兩個頂點之間沒有權重,就爲 無窮大

typedef struct 
{
VertexType vexs[Max]; //存儲頂點信息的一維數組
EdgeType arc[Max][Max]; //二維數組組成的鄰接矩陣,可看作邊表
int numEdge,numVertex; //邊數  頂點數
}MGraph;

b) 構造圖,給頂點表和鄰接矩陣輸入數據的過程
void CreatMGraph(MGraph *G)
{
//01 輸入邊數,頂點數
int i,j;
int numEdge,numVertex;
cout << "輸入邊數,頂點數: " ;
cin >> numEdge >> numVertex;

//02 輸入頂點信息,建立頂點表
cout << "請輸入頂點信息: " << endl;
for(i = 0; i < numVertex; i++)
{
cin >> G->vexs[i];
}

//03 初始化鄰接矩陣
for(i = 0; i < numEdge; i++)
{
for(j = 0; j < numEdge; j++)
{
G->arc[i][j] = INFINITY;
}
}

//04 輸入邊信息
for(int k = 0; k < numVertex; k++)
{
cout << "請輸入邊(v1,v2)兩個頂點的下標i,j,以及邊權重w" <<endl;
cin >> i >> j >> w;
G->arc[i][j] = w; //邊的權重爲w
G->arc[j][i] = G->[i][j]; //無向圖,矩陣對稱
}
}
4)鄰接矩陣的缺點:
當圖中的表邊數較少時,鄰接矩陣仍然需要開闢 numVertex*numVertex個空間,這是對內存空間的浪費

2 鄰接表
用一個一維數組或單鏈表記錄圖中頂點的信息
(data firstedge)data 頂點信息  firstedge第一個鄰接點的指針
用一個線性鏈表存儲每個頂點的所有鄰接點
(agjvex weight next)agjvex 鄰接點在一維數組(頂點表)中的下標 weight 權重   next  下一個結點的指針

鄰接表由三部分結構體組成:
typedef char VertexType
typedef int EdgeType

1)記錄鄰接邊信息的結構體 EdgeNode
typedef struct EdgeNode
{
int agjvex; //鄰接點域,存儲該點對應的下標
EdgeType weight; //存儲權重,非網圖可以不要
EdgeNode *next; //鏈域,指向下一個鏈接點
}EdgeNode;

2)記錄頂點信息的結構體 VertexNode
typedef struct VertexNode 
{
int data; //存儲頂點數據
EdgeNode *firstedge;//邊表頭指針,指向與該點組成邊的另一個點對應的下標
}VertexNode,AdjList[Max]; //AdjList[Max] 存儲頂點信息的一維數組
多個VertexNode類型的元素組成一維數組,存儲頂點信息

3)記錄當前圖中的頂點個數,邊的個數  GraphAdjList
typedef struct GraphAdjList 
{
AdjList adjList; 
int numEdge,numVertex; //當前圖 的頂點個數,邊數
}GraphAdjList;

4)存儲鄰接邊信息 (鄰接邊是 EdgeNode 類型的) GraphAdjList *G
a) 輸入頂點個數numVertex,邊的個數numEdge
循環輸入頂點信息,建立頂點表,頂點信息存儲在AdjList[i].data中
將G->adjList[i].firstedge = null

b) 建立邊表
每循環一次,就向內存申請一次的空間e EdgeNode類型,存放鄰接邊信息,沒有某種結構類型來存儲,比如數組

輸入(Vi,Vj)鄰接邊 的 序號i,j    
e->adjvex = j;     //頂點i的鄰接序號
e->next = G->adjList[i].firstedge; //使用的是單鏈表中的頭插法 將當前頂點的 firstedge 給 e指針指向
G->adjList[i].firstedge = e; //將當前頂點的 firstedge 指向 e

同樣,對於下標爲j的頂點,它的邊表的建立如下:
e->adjvex = i;
e->next = G->adjList[j].firstedge;
G->adjList[j].firstedge = e;

3 十字鏈表
1)將鄰接表和逆鄰接表結合起來
2)頂點表結構:
data firstin firstout
data :頂點數據
firstin :頂點的入邊的第一個結點
firstout :表示出邊表頭指針,指向該頂點的出邊表中的第一個結點
3)邊表結構:
tailvex headvex headlink tailink
tailvex : 弧【起】點在頂點表中的下標
headvex : 弧【終】點在頂點表中的下標
headlink :指入邊表指針域,指向【終點相同】的下一條邊
tailink : 指出邊表指針域,指向【起點相同】的下一條邊
4)代碼和鄰接表的類似:
typedef char VertexType;
typedef int EdgeType;
#define Max 65535

//01 頂點表結構體 VertexNode
typedef struct VertexNode
{
VertexType data;
EdgeNode *firstin;
EdgeNode * firstout;
}VertexNode,AdjList[Max];

//02 邊表結構體 EdgeNode
typedef struct EdgeNode
{
int tailvex,headvex;
struct EdgeNode *headlink;
struct EdgeNode *tailink;
}EdgeNode;

//03 頂點數,邊數
typedef struct GraphAdjList
{
AdjList adjList;
int numEdge,numVertex;
}GraphAdjList;

//04 建立十字鏈接表結構
void CreatOrthogonal(GraphAdjList *G)
{
int i,j;
//1 輸入頂點個數numVertex,邊的個數numEdge
cout << "輸入邊數,頂點數: ";
cin >> numEdge >> numVertex;
cout << endl;

//2 輸入頂點信息,建立頂點表
cout << "輸入頂點信息,建立頂點表:" << endl;
for(i = 0; i < numVertex; i++)
{
cin >> G->adjList[i].data;
G->adjList[i].firstin = null; //出入邊表爲空
G->adjList[i].firstout = null;
}

//3 構建十字鏈表結構

}

4 鄰接多重表
ivex illink jvex jlink

illink : 指向依附頂點ivex的下一條邊
jlink : 指向依附頂點jvex的下一條邊
ivex jvex  :與某條邊依附的兩個頂點在頂點表中的下標
 
5 邊集數組

begin end weight

部分代碼摘抄自《大話數據結構》


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章