數據結構與算法--圖的存儲方式
1. 圖的定義
- 定義:圖是由頂點的有窮非空結合和頂點之間的集合組成,數據元素(頂點)之間具有任意關係,圖中任意兩個數據元素之間都可能相關
- 各種圖:
無向圖(頂點到頂點之間的邊沒有方向,則稱這條邊爲無向邊)
有向圖(若從頂點 到頂點 的邊有方向,則稱這條邊爲有向邊,也稱爲弧)
頂點A
到頂點D
的邊就是弧,用<A, D>
表示弧,注意不能寫成<D, A>
上圖可以表示爲G= (V2,{E2})
,其中頂點集合V2={A,E,C,D}
, 弧集合E2={<A,D>,<A,E>,<A,C>,<E,D>}
。
無向完全圖
有向完全圖
有些圖的邊
或弧
具有與它相關的數字,這種與圖的邊或弧相關的數叫做權
。這些權可以表示從一個頂點到另一個頂點的距離或耗費。
這種帶權
的圖通常稱爲網
。如下圖就是一張帶權的圖,即標識中國四大城市的直線距離的網,此圖中的權就是兩地的距離。
廣度優先搜索算法:數據結構是隊列。通過將頂點存入隊列中,最先入隊列的頂點先被探索。
深度優先搜索算法:數據結構是棧。通過將頂點存入棧中,沿着路徑探索頂點,存在新的相鄰頂點就去訪問
2. 圖的存儲
2.1. 圖的存儲介紹
圖用 鄰接矩陣存儲方式 來存儲
-
一個
一維數組
存儲圖中頂點信息
, -
一個
二維數組(稱爲鄰接矩陣
)存儲圖中的邊或弧
的信息。
設圖G
有n
個頂點,則鄰接矩陣是一個nxn
的方陣,定義爲:
如下無向圖:
如下有向圖
我們知道,每條邊上帶有權值
的圖
叫做網
,那麼在存儲的時候,可以採用權值代替矩陣中的0、1
,權值不存在的元素之間用∞
表示,如下圖,左圖是一個有向網圖,右圖就是它的鄰接矩陣。
2.2. 鄰接矩陣
定義一個數組,存儲頂點,定義一個鄰接矩陣(二維數組)
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAXVEX 100 // 最大頂點數
#define INFINITYC 0
typedef int Status;
typedef char VertexType; // 頂點類型
typedef int EdgeType; // 邊的權值的類型
// 定義圖的結構
typedef struct {
VertexType vers[MAXVEX]; // 頂點表
EdgeType arc[MAXVEX][MAXVEX];// 鄰接矩陣
int numNodes; // 頂點數
int numEdges; // 邊數
}MGraph;
圖的存儲方法:
void CreateMGraph(MGraph *G){
int i, j, k, m;
// 1.輸入頂點數
printf("輸入頂點數:");
scanf("%d", &G->numNodes);
// 2.輸入邊數
printf("輸入邊數:");
scanf("%d", &G->numEdges);
printf("頂點數:%d,邊數:%d\n",G->numNodes,G->numEdges);
// 3.輸入頂點表
printf("輸入頂點:");
for (i = 0; i <= G->numNodes; i++) {
scanf("%c", &G->vers[i]);
}
// 4.初始化鄰接矩陣
for (i = 0; i < G->numNodes; i++) {
for (j = 0; j < G->numNodes; j++) {
G->arc[i][j] = INFINITY;
}
}
// 5.輸入邊信息
for (k = 0; k < G->numEdges; k++) {
printf("輸入邊(vi,vj)上的下標i,下標j,權w(逗號分隔)\n");
scanf("%d,%d,%d", &i, &j, &m);
G->arc[i][j] = m;
//如果無向圖,矩陣對稱;
//G->arc[j][i] = G->arc[i][j];
}
// 6.打印
for (int i = 0; i < G->numNodes; i++) {
printf("\n");
for (int j = 0; j < G->numNodes; j++) {
printf("%d ",G->arc[i][j]);
}
}
printf("\n");
}
2.3. 鄰接表
#define M 100 //頂點最大個數
#define TRUE 1
#define FALSE 0
typedef char Element;
// 定義鄰接表節點
typedef struct Node {
int adj_vex_index; // 弧頭下標
Element data; // 權重
struct Node *next; // 邊指針
}EdgeNode;
// 定義頂點表結構
typedef struct vNode {
Element data; // 權重
EdgeNode * firstedge; // 頂點的下一個
}VertexNode,Adjlist[M];
// 定義圖結構
typedef struct Graph{
Adjlist adjlist; // 頂點表
int arc_num; // 邊數
int node_num; // 頂點數
int is_directed; // 是否是有向圖
}Graph, *GraphLink;
圖的存儲(鄰接表)
void creatGraph(GraphLink *g){
int i, j, k;
EdgeNode *p;
// 輸入邊數,頂點數,是否有向
printf("輸入頂點數目,邊數和有向?:\n");
scanf("%d %d %d", &(*g)->node_num, &(*g)->arc_num, &(*g)->is_directed);
// 輸入頂點信息
for (i = 0; i < (*g)->node_num; i++) {
getchar();
scanf("%c", &(*g)->adjlist[i].data);
(*g)->adjlist[i].firstedge = NULL;
}
printf("輸入邊信息:\n");
for (k = 0; k < (*g)->arc_num; k++) {
getchar();
scanf("%d %d", &i, &j);
// 創建新節點
p = (EdgeNode *)malloc(sizeof(EdgeNode));
// 弧頭的下標
p->adj_vex_index = j;
// 頭插法
p->next = (*g)->adjlist[i].firstedge;
// 將頂點數組[i].firstedge 設置爲p
(*g)->adjlist[i].firstedge = p;
// 判斷是否是有向
if (!(*g)->is_directed) {
// 創建新節點
p = (EdgeNode *)malloc(sizeof(EdgeNode));
// 弧頭的下標
p->adj_vex_index = i;
// 頭插法
p->next = (*g)->adjlist[j].firstedge;
// 將頂點數組[i].firstedge 設置爲p
(*g)->adjlist[j].firstedge = p;
}
}
}
void putGraph(GraphLink g){
int i;
printf("鄰接表中存儲信息:\n");
//遍歷一遍頂點座標,每個再進去走一次
for (i = 0; i < g->node_num; i++) {
EdgeNode * p = g->adjlist[i].firstedge;
while (p) {
printf("%c->%c ", g->adjlist[i].data, g->adjlist[p->adj_vex_index].data);
p = p->next;
}
printf("\n");
}
}