以前在線性表中,咱們能夠看到,數據元素之間是被串起來的,僅有線性關係,每一個數據元素只有一個直接前驅和一個直接後繼;在樹形結構中,數據元素之間有着明顯的層次關係,而且每一層上的數據元素可能和下一層中多個元素相關,但只能和上一層中一個元素相關。現實狀況下,人與人之間的關係就不單單是這樣的,就不是簡單的一對一或者一對多,而是多對多的狀況。node
圖是由頂點的有窮非空集合和頂點之間邊的集合組成。一般表示爲:G(V,E)。其中G表示一個圖,V是圖G中的頂點集合,E是圖G中邊的集合
那麼如何存儲圖呢?數組
由定義咱們能夠知道,圖是由兩部分組成,頂點和邊,頂點和邊的鏈接,肯定了圖的邏輯關係,因此圖的存儲,其中它的頂點須要存儲,邊與邊的鏈接信息也要存儲。bash
頂點的信息,可使用一維數組進行存儲 markdown
邊的信息,存在這多對多的邏輯關係,那麼可使用二維數據進行存儲數據結構
鄰接矩陣的存儲,其實就是順序存儲的方式
圖上的度指的是:存在關係的頂點數函數
鄰接矩陣存儲實現思路spa
鄰接矩陣存儲圖的數據結構設計
#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXVEX 100 /* 最大頂點數,應由用戶定義 */ #define INFINITYC 0 typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */ typedef char VertexType; /* 頂點類型應由用戶定義 */ typedef int EdgeType; /* 邊上的權值類型應由用戶定義 */ typedef struct { VertexType vexs[MAXVEX]; /* 頂點表 */ EdgeType arc[MAXVEX][MAXVEX];/* 鄰接矩陣,可看做邊表 */ int numNodes, numEdges; /* 圖中當前的頂點數和邊數 */ }MGraph; 複製代碼
存儲部分指針
void CreateMGraph(MGraph *G){ int i,j,k,w; printf("輸入頂點數和邊數\n"); scanf("%d,%d",&G->numNodes,&G->numEdges); printf("頂點數:%d,邊數:%d\n",G->numNodes,G->numEdges); // 輸入頂點信息,組成頂點表 for (i = 0; i<=G->numNodes; i++) { scanf("%c",&G->vexs[i]); } // 初始化鄰接矩陣 for (i = 0; i<=G->numNodes; i++) { for (j = 0; j<=G->numNodes; j++) { G->arc[i][j] = INFINITYC; // 初始化0 } } // 輸入邊表數據 for (k = 0; k<G->numEdges; k++) { printf("輸入邊(vi,vj)上的下標i,下標j,權w\n"); scanf("%d,%d,%d",&i,&j,&w); G->arc[i][j] = w; //若是是無向圖的話 矩陣對陣 G->arc[j][i] = w; } // 打印鄰接矩陣 printf("矩陣結果\n"); 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"); } /** 輸入頂點數和邊數 4,5 頂點數:4,邊數:5 abcd 輸入邊(vi,vj)上的下標i,下標j,權w 0,1,1 輸入邊(vi,vj)上的下標i,下標j,權w 0,2,1 輸入邊(vi,vj)上的下標i,下標j,權w 0,3,1 輸入邊(vi,vj)上的下標i,下標j,權w 1,2,1 輸入邊(vi,vj)上的下標i,下標j,權w 2,3,1 矩陣結果 0 1 1 1 1 0 1 0 1 1 0 1 1 0 1 0 */複製代碼
一樣的,鄰接矩陣(順序存儲)的方式,可能會產生一些空白的空間,會形成空間的浪費,那麼,咱們嘗試使用鏈式的存儲。code
鄰接表中首先有一個一維數組(如圖中綠色部分),上圖綠色的部分存儲的是圖的頂點信息,在這個一維數組中的某一個頂點數據,指向了一個鏈表。一維數組中的數據,相似鏈表中的表頭。鏈表中的數據都是與其有着頂點的鏈接邏輯關係的。
假如邊有權重,那麼鄰接表的節點能夠添加一個權重。
鄰接表存儲的數據結構設計
#define M 100 #define true 1 #define false 0 typedef char Element; typedef int BOOL; //鄰接表的節點 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; //節點個數 BOOL is_directed; //是否是有向圖 }Graph, *GraphLink; 複製代碼
存儲部分
void creatGraph(GraphLink *g){ int i,j,k; EdgeNode *p; //1. 頂點,邊,是否有向 printf("輸入頂點數目,邊數和有向?:\n"); scanf("%d %d %d", &(*g)->node_num, &(*g)->arc_num, &(*g)->is_directed); //2.頂點表 printf("輸入頂點信息:\n"); for (i = 0; i < (*g)->node_num; i++) { getchar(); scanf("%c", &(*g)->adjlist[i].data); (*g)->adjlist[i].firstedge = NULL; } //3.錄入數據 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; //③頭插法插進去,插的時候要找到弧尾,那就是頂點數組的下標i p->next = (*g)->adjlist[i].firstedge; //④將頂點數組[i].firstedge 設置爲p (*g)->adjlist[i].firstedge = p; //j->i if(!(*g)->is_directed) { // j -----> i //①新建一個節點 p = (EdgeNode *)malloc(sizeof(EdgeNode)); //②弧頭的下標i p->adj_vex_index = i; //③頭插法插進去,插的時候要找到弧尾,那就是頂點數組的下標i p->next = (*g)->adjlist[j].firstedge; //④將頂點數組[i].firstedge 設置爲p (*g)->adjlist[j].firstedge = p; } } } 複製代碼