圖的儲存結構——鄰接矩陣與鄰接表
1 概述#
簡單的說,圖由表示資料元素的集合V和表示資料之間關係的集合E組成,記為G=<V,E>。圖又分為有向圖與無向圖。下面是圖的一些基本元素:
- 邊(edge):頂點的序偶。
- 頂點(vertex):資料元素。
- 權重(weight):用來表示一個頂點到另一個頂點的距離、代價、耗費等。
- 度(degree):與該頂點相關聯的邊的數目,入度、出度等等。
圖的基本型別常使用的有相鄰矩陣與鄰接表。下面將從兩方面介紹圖的儲存結構與基本操作。
2 圖的相鄰矩陣儲存型別#
圖的相鄰矩陣或鄰接矩陣表示定點之間的鄰接關係,即表示頂點之間有邊或沒有邊的情況。如下圖則是無向圖G1和有向圖G2的鄰接矩陣。
- 相鄰矩陣型別定義
對於有向圖,相鄰矩陣不一定對稱。因為如果相鄰矩陣第i行第j列的元素為1,則表示有一條從頂點vi到頂點vj的弧,而此時不一定存在由頂點vj到頂點vi的弧。
/*圖的相鄰矩陣儲存型別定義*/
#define MaxVertexNum 100 /*最大頂點數設為100*/
typedef enum{FALSE,TRUE} Boolean;
Boolean mark[MaxVertexNum];
typedef char VertexType; /*頂點型別設為字元型*/
typedef int EdgeType; /*邊的權值設為整型*/
typedef struct {
VertexType vexs[MaxVertexNum]; /*頂點表*/
EdgeType edges[MaxVertexNum][MaxVertexNum]; /*鄰接矩陣,即邊表*/
int numVertex,numEdge; /*頂點數和邊數*/
}Mgragh,*MGragh; /*Maragh 是以鄰接矩陣儲存的圖型別*/
- 圖建立
首先定義相鄰矩陣的尺寸,即定點數和邊數。
輸入每條邊資訊,vi為初始點,vj為終止點。將鄰接表中的edges[i][j]設定為1,代表起點為i,終點為j,存在一條邊。
void CreateMGraph(MGragh G){/*建立有向圖G 的鄰接矩陣儲存*/
int i,j,k,w;
char ch;
cout<<"請輸入頂點數和邊數";
cin>>i>>j;
G->numVertex=i;
G->numEdge=j;
cout<<"請輸入頂點資訊:"<<endl;
for (i=0;i<G->numVertex;i++) {cout<<"第"<<i<<"個點:";cin>>G->vexs[i];} /*輸入頂點資訊,建立頂點表*/
for (i=0;i<G->numVertex;i++)
for (j=0;j<G->numVertex;j++)
G->edges[i][j]=0; /*初始化鄰接矩陣*/
cout<<"請輸入每條邊對應的兩個頂點的序號:\n";
for (k=0;k<G->numEdge;k++){
cout<<"v<i,j>:";
cin>>i>>j; /*輸入e 條邊,建立鄰接矩陣*/
G->edges[i][j]=1;
}
}
- 判斷邊類
FirstEdge即返回以v為頂點的第一條邊。它的想法是:返回以頂點v的編號的相鄰矩陣行,從j=0開始遍歷,直到搜尋到矩陣元素為1時,表示i到j有一條邊,於是返回此條邊。
NextEdge即返回以v為頂點的下一條邊。當輸入邊edge時,將返回以edge.from的編號相同的矩陣行,從j=edge.to+1開始遍歷,直到搜尋到矩陣元素為1時,表示i到j有一條邊,返回此邊。
Edge FirstEdge(MGragh G,int oneVertex){
Edge myEdge;
myEdge.from=oneVertex;
for(int i=0;i<G->numVertex;i++){
if(G->edges[oneVertex][i]!=0){
myEdge.to=i;
myEdge.weight=G->edges[oneVertex][i];
break;
}
}
return myEdge;
}
Edge NextEdge(MGragh G,Edge preEdge){
Edge myEdge;
myEdge.from =preEdge.from ;
if(preEdge.to <G->numVertex){
for(int i=preEdge.to+1;i<G->numVertex;i++){
if(G->edges[preEdge.from][i]!=0){
myEdge.to =i;
myEdge.weight =G->edges[preEdge.from ][i];
break;
}
}
}
return myEdge;
}
bool isEdge(MGragh G, Edge myEdge){
int test=0;
for(int i=0;i<G->numVertex;i++){
if(myEdge.to>=0&&G->edges[myEdge.from][myEdge.to]==1)return true;
}
return false;
}
- 兩種周遊演算法
以有向圖G2為例:
深度優先搜尋的周遊演算法如下:假設從v0點出發,首先將v0的標誌位設定為TRUE,然後從v0的第一條邊出發,尋找第一條邊的終點v2。因為v2為被訪問過,因此將v2標誌位設定為TRUE。從v2出發,尋找v2的第一條邊終點為v3。因為v3為被訪問過,因此設v3的標誌位為TRUE。從v3出發,尋找v3的第一條邊終點為v0,標誌位為TRUE說明已被訪問過。返回上一個頂點v2,尋找v2的nextEdge,無。返回v0,尋找v0的nextEdge,為v1,標識v1為TRUE。遍歷完畢。
廣度優先演算法的周遊如下:假設從v0出發。首先將v0的標誌位設定為TRUE,將v0入隊。因為佇列不為空,所以取出front,設定為u,同時pop掉front。尋找v0的第一條邊的終點v2。輸出v2,並將其push入佇列;尋找v0的第二條邊的終點v1,,輸出v1,並將其push入佇列;尋找v0的第三條邊的終點,無。返回取出front,將v2設定為u,pop掉它。尋找v2的第一條邊v3,輸出v3並將其push如佇列;尋找v2的第二條邊,無。返回取出front,將v1設定為u,pop掉它。尋找v1的第一條邊,無。返回取出front,將v3設定為u,pop掉它,尋找v3的第一條邊v0,因為以被訪問,因此跳過;尋找v3的第二條邊,無。演算法結束。
//深度優先周遊
void DFS(MGragh G, int v){
mark[v]=TRUE;
cout<<G->vexs[v];
for(Edge e=FirstEdge(G,v);isEdge(G,e);e=NextEdge(G,e)){
if(mark[e.to]==FALSE) DFS(G,e.to);
}
}
void DFSM(MGragh G,int v){
for(int i=0;i<G->numVertex;i++){
mark[i]=FALSE;
}
DFS(G,0);
}
//廣度優先周遊
void BFS(MGragh G, int v){
for(int i=0;i<G->numVertex;i++){
mark[i]=FALSE;
}
using std::queue;
queue<int>Q;
cout<<G->vexs[v];
mark[v]=TRUE;
Q.push(v);
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(Edge e=FirstEdge(G,u);isEdge(G,e);e=NextEdge(G,e))
if(mark[e.to]==FALSE){
cout<<G->vexs[e.to];
mark[e.to]=TRUE;
Q.push(e.to);
}
}
}
3 圖的鄰接表儲存型別#
當圖中的邊數較少時,相鄰矩陣就會出現大量的0元素,儲存這些0元素將消耗大量的儲存空間。
鄰接表表示法是一種鏈式儲存結構,由一個順序儲存的頂點表和n個連結串列儲存的邊表組成。頂點表目有兩個域:頂點資料域和指向此頂點邊表指標域。邊表把依附於同一個頂點vi的邊(即相鄰矩陣中同一行的非0元素)組織成一個單連結串列。邊表中的每一個表目都代表一條邊,由兩個主要的域組成:與頂點vi鄰接的另一個頂點的序號、指向邊表中下一個邊表的目的指標。
頂點結點和邊結點的結構如下:
與鄰接矩陣儲存型別相似,鄰接表的基本函式依然包括FirstEdge,NextEdge和isEdge。這裡不再重複,下面只給出廣度周遊和深度周遊演算法。
- 鄰接表型別定義
using namespace std;
#define MAX_VERTEXT_NUM 20
typedef enum{FALSE,TRUE} Boolean;
Boolean mark[MAX_VERTEXT_NUM];
typedef struct edge{ /*邊定義*/
int from,to,weight;
}Edge,*Edged;
typedef struct ArcNode{ /*邊結點定義*/
int adjvex;
struct ArcNode *nextArc;
int weight;
}ArcNode;
typedef struct VNode{ /*頂點定義*/
char data;
ArcNode *firstArc;
}VNode, AdjList[MAX_VERTEXT_NUM];
typedef struct Indegree{ /*每個點的入度*/
int indegree;
}Indegree,indegree[MAX_VERTEXT_NUM];
typedef struct{ /*圖定義*/
AdjList verTices;
int vexNum;
int arcNum;
int kind;
indegree Indegree;
}ALGraph;
- 圖的鄰接表儲存型別建立
首先輸入頂點和邊的個數,同時申請頂點個數的結點空間。
每次輸入邊的鄰接關係時i-j時,首先申請一個邊結點空間給,結點的adjvex為j,nextarc為頭結點firstarc的nextarc,頭結點的firstarc變為此j結點arcnode。
void CreateGraph(ALGraph *G)
{
int i,j,k,weight;
ArcNode *arcNode;
printf_s("請輸入頂點數和邊數:");
cin>>G->vexNum;
cin>>G->arcNum;
//建立頂點表
printf_s("建立頂點表\n");
for (i = 0; i < G->vexNum; i++)
{
printf_s("請輸入第%d個頂點:", i);
cin>>G->verTices[i].data;
arcNode = (ArcNode *)malloc(sizeof(ArcNode));
arcNode->adjvex=i;
arcNode->nextArc=NULL;
G->verTices[i].firstArc=arcNode;
G->Indegree[i].indegree=0;
}
//建立邊表
printf_s("建立邊表\n");
for (k = 0; k < G->arcNum; k++)
{
printf_s("請輸入(vi-vj)的頂點對序號");
cin>>i;
cin>>j;
arcNode = (ArcNode *)malloc(sizeof(ArcNode));
arcNode->adjvex = j;
arcNode->nextArc = G->verTices[i].firstArc->nextArc;//插入表頭
G->verTices[i].firstArc ->nextArc= arcNode;
G->Indegree[j].indegree++;
}
}
- 兩種周遊演算法
深度優先周遊:對於鄰接表儲存型別,它採用遞迴演算法,從起始點v0沿著鄰接表一次訪問,直到next指標為NULL,則返回上一層,進入上一層頂點v1所在的連結串列繼續逐個訪問。
廣度周遊與相鄰矩陣法類似,這裡不做闡述。演算法如下:
//深度優先周遊
void DFSM(ALGraph *G,int i){
ArcNode *p;
cout<<G->verTices[i].data;
mark[i]=TRUE;
p=G->verTices[i].firstArc;
while(p){
if(mark[p->adjvex]==FALSE)
DFSM(G,p->adjvex);
p=p->nextArc;
}
}
void DFS(ALGraph *G){
for ( int i=0; i<G->vexNum;i++)
mark[i]=FALSE;
for( int i=0; i<G->vexNum;i++)
if(!mark[i])
DFSM(G,i);
}
//廣度優先周遊
void BFS(ALGraph *G,int x){
ArcNode *p;
int w;
using std::queue;
queue<int> Q;
for ( int i=0; i<G->vexNum;i++) {mark[i]=FALSE;}
cout<<G->verTices[x].data;
mark[x]=TRUE;
Q.push(x);
while(!Q.empty()){
int v=Q.front();
Q.pop();
p=G->verTices[v].firstArc;
while(p){
int w=p->adjvex;
if(mark[w]==FALSE){
mark[w]=TRUE;
cout<<G->verTices[w].data;
Q.push(w);}
p=p->nextArc;
}
}
}
- 拓撲排序
有向圖的邊可以看做定點之間制約關係的描述。在工程實踐中,有些工程的進行經常受到一定條件的約束,例如一個工程專案通常由若干子工程組成,某些子工程完成之後另一些子工程才能開始。
一個無環的有向圖稱為有向無環圖,有向無環圖常用來描述一個過程或一個系統的進行過程。對於有向無環圖G=<V,E>,如果頂點序列滿足:存在頂點vi到vj的一條路徑,那麼在序列中頂點vi必在頂點vj之前,頂點集合V的這種線型序列稱作一個拓撲序列。
進行有向圖的拓撲序列方法如下:
- 從有向圖中選出一個沒有前驅(入度為0)的頂點並輸出。
- 刪除圖中該頂點和所有以它為起點的弧。
不斷重複上述兩個步驟,會出現兩種情形:要麼有向圖中頂點全部被輸出,要麼當前圖中不存在沒有前驅的頂點。當圖中的頂點全部輸出時,就完成了有向無環圖的拓撲排序;當圖中還有頂點沒有輸出時,說明有向圖中含有環。
它的工作思想如下:
//拓撲排序
void TopsortbyQueue(ALGraph*G){
for(int i=0; i< G->vexNum;i++)
mark[i]=FALSE;
using std::queue;
queue<int> Q;
cout<<"拓撲序列為:"<<endl;
for(int i=0; i< G->vexNum;i++){
if(G->Indegree[i].indegree==0)
Q.push(i);}
while(!Q.empty()){
int v=Q.front();
Q.pop();
cout<<v;
mark[v]=TRUE;
for(Edge e=FirstEdge(G,v);isEdge(G,e);e=NextEdge(G,e)){
G->Indegree[e.to].indegree--;
if(G->Indegree[e.to].indegree ==0)
Q.push(e.to);
}
}
for(int i=0;i< G->vexNum;i++)
if(mark[i]==FALSE){
cout<<endl;
cout<<"還有頂點未訪問,此圖有環。"<<endl;
break;
}
}
4 總結#
明顯感覺到寫得多了對於語言的運用更熟練了,也更有了設計演算法需要的邏輯思想。這個寫的還算比較順隨著思維和語言能力提升,希望能在acm校選賽比賽上有好的發揮過兩天來更新結果!
5 附錄#
鄰接矩陣:
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
using namespace std;
#define MaxVertexNum 100 /*最大頂點數設為100*/
typedef enum{FALSE,TRUE} Boolean;
Boolean mark[MaxVertexNum];
typedef char VertexType; /*頂點型別設為字元型*/
typedef int EdgeType; /*邊的權值設為整型*/
typedef struct {
VertexType vexs[MaxVertexNum]; /*頂點表*/
EdgeType edges[MaxVertexNum][MaxVertexNum]; /*鄰接矩陣,即邊表*/
int numVertex,numEdge; /*頂點數和邊數*/
}Mgragh,*MGragh; /*Maragh 是以鄰接矩陣儲存的圖型別*/
typedef struct edge{
int from,to,weight;
}Edge,*Edged;
void CreateMGraph(MGragh G){/*建立有向圖G 的鄰接矩陣儲存*/
int i,j,k,w;
char ch;
cout<<"請輸入頂點數和邊數";
cin>>i>>j;
G->numVertex=i;
G->numEdge=j;
cout<<"請輸入頂點資訊:"<<endl;
for (i=0;i<G->numVertex;i++) {cout<<"第"<<i<<"個點:";cin>>G->vexs[i];} /*輸入頂點資訊,建立頂點表*/
for (i=0;i<G->numVertex;i++)
for (j=0;j<G->numVertex;j++)
G->edges[i][j]=0; /*初始化鄰接矩陣*/
cout<<"請輸入每條邊對應的兩個頂點的序號:\n";
for (k=0;k<G->numEdge;k++){
cout<<"v<i,j>:";
cin>>i>>j; /*輸入e 條邊,建立鄰接矩陣*/
G->edges[i][j]=1;
}
}
void displaygraph(MGragh G){
int i,j;
for(i=0;i<G->numVertex;i++){
for(j=0;j<G->numVertex;j++){
cout<<G->edges[i][j]<<" ";}
cout<<endl;
}
}
Edge FirstEdge(MGragh G,int oneVertex){
Edge myEdge;
myEdge.from=oneVertex;
for(int i=0;i<G->numVertex;i++){
if(G->edges[oneVertex][i]!=0){
myEdge.to=i;
myEdge.weight=G->edges[oneVertex][i];
break;
}
}
return myEdge;
}
Edge NextEdge(MGragh G,Edge preEdge){
Edge myEdge;
myEdge.from =preEdge.from ;
if(preEdge.to <G->numVertex){
for(int i=preEdge.to+1;i<G->numVertex;i++){
if(G->edges[preEdge.from][i]!=0){
myEdge.to =i;
myEdge.weight =G->edges[preEdge.from ][i];
break;
}
}
}
return myEdge;
}
bool isEdge(MGragh G, Edge myEdge){
int test=0;
for(int i=0;i<G->numVertex;i++){
if(myEdge.to>=0&&G->edges[myEdge.from][myEdge.to]==1)return true;
}
return false;
}
//深度優先周遊
void DFS(MGragh G, int v){
mark[v]=TRUE;
cout<<G->vexs[v];
for(Edge e=FirstEdge(G,v);isEdge(G,e);e=NextEdge(G,e)){
if(mark[e.to]==FALSE) DFS(G,e.to);
}
}
void DFSM(MGragh G,int v){
for(int i=0;i<G->numVertex;i++){
mark[i]=FALSE;
}
DFS(G,0);
}
//廣度優先周遊
void BFS(MGragh G, int v){
for(int i=0;i<G->numVertex;i++){
mark[i]=FALSE;
}
using std::queue;
queue<int>Q;
cout<<G->vexs[v];
mark[v]=TRUE;
Q.push(v);
while(!Q.empty()){
int u=Q.front();
Q.pop();
for(Edge e=FirstEdge(G,u);isEdge(G,e);e=NextEdge(G,e))
if(mark[e.to]==FALSE){
cout<<G->vexs[e.to];
mark[e.to]=TRUE;
Q.push(e.to);
}
}
}
int main(){
Mgragh *Graph = (Mgragh *)malloc(sizeof(Mgragh));
CreateMGraph(Graph);
displaygraph(Graph);
cout<<endl;
BFS(Graph,0);
cout<<endl;
DFSM(Graph,0);
system("pause");
return 0;
}
鄰接表
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<queue>
using namespace std;
#define MAX_VERTEXT_NUM 20
typedef enum{FALSE,TRUE} Boolean;
Boolean mark[MAX_VERTEXT_NUM];
typedef struct edge{
int from,to,weight;
}Edge,*Edged;
typedef struct ArcNode{
int adjvex;
struct ArcNode *nextArc;
int weight;
}ArcNode;
typedef struct VNode{
char data;
ArcNode *firstArc;
}VNode, AdjList[MAX_VERTEXT_NUM];
typedef struct Indegree{
int indegree;
}Indegree,indegree[MAX_VERTEXT_NUM];
typedef struct{
AdjList verTices;
int vexNum;
int arcNum;
int kind;
indegree Indegree;
}ALGraph;
typedef struct Dist{
int index;
int length;
int pre;
}Dist,*Dijk;
edge FirstEdge(ALGraph *G,int oneVertex){
Edge myEdge;
myEdge.from=oneVertex;
ArcNode *temp=G->verTices[oneVertex].firstArc;
if(temp->nextArc!=NULL){
myEdge.to=temp->nextArc->adjvex;
myEdge.weight=temp->nextArc->weight;
}
return myEdge;
}
edge NextEdge(ALGraph *G,Edge preEdge){
Edge myEdge;
myEdge.from =preEdge.from;
ArcNode *temp=G->verTices[preEdge.from].firstArc;
while(temp->nextArc!=NULL&&temp->adjvex<=preEdge.to)
temp=temp->nextArc;
if(temp->nextArc!=NULL){
myEdge.to=temp->nextArc->adjvex;
myEdge.weight=temp->nextArc->weight;
}
return myEdge;
}
bool isEdge(ALGraph *G, Edge myEdge){
int n=0;
ArcNode *p;
p=G->verTices[myEdge.from].firstArc;
while(p){
if(p->adjvex==myEdge.to){
n=0;
}else{
n=1;
}
p=p->nextArc;
}
if(n==0){return true;}
else{
return false;
}
}
void CreateGraph(ALGraph *G)
{
int i,j,k,weight;
ArcNode *arcNode;
printf_s("請輸入頂點數和邊數:");
cin>>G->vexNum;
cin>>G->arcNum;
//建立頂點表
printf_s("建立頂點表\n");
for (i = 0; i < G->vexNum; i++)
{
printf_s("請輸入第%d個頂點:", i);
cin>>G->verTices[i].data;
arcNode = (ArcNode *)malloc(sizeof(ArcNode));
arcNode->adjvex=i;
arcNode->nextArc=NULL;
G->verTices[i].firstArc=arcNode;
G->Indegree[i].indegree=0;
}
//建立邊表
printf_s("建立邊表\n");
for (k = 0; k < G->arcNum; k++)
{
printf_s("請輸入(vi-vj)的頂點對序號");
cin>>i;
cin>>j;
arcNode = (ArcNode *)malloc(sizeof(ArcNode));
arcNode->adjvex = j;
arcNode->nextArc = G->verTices[i].firstArc->nextArc;//插入表頭
G->verTices[i].firstArc ->nextArc= arcNode;
G->Indegree[j].indegree++;
}
}
//顯示圖的鄰接表
void DisplayGraph(ALGraph *G)
{
int i;
for (i = 0; i < G->vexNum; i++)
{
cout<<G->Indegree[i].indegree;
ArcNode *P= G->verTices[i].firstArc;
printf_s("%d->", i);
while (P != NULL)
{
printf_s("%d->", P->adjvex);
P = P->nextArc;
}
printf_s("\n");
}
}
//深度優先周遊
void DFSM(ALGraph *G,int i){
ArcNode *p;
cout<<G->verTices[i].data;
mark[i]=TRUE;
p=G->verTices[i].firstArc;
while(p){
if(mark[p->adjvex]==FALSE)
DFSM(G,p->adjvex);
p=p->nextArc;
}
}
void DFS(ALGraph *G){
for ( int i=0; i<G->vexNum;i++)
mark[i]=FALSE;
for( int i=0; i<G->vexNum;i++)
if(!mark[i])
DFSM(G,i);
}
//廣度優先周遊
void BFS(ALGraph *G,int x){
ArcNode *p;
int w;
using std::queue;
queue<int> Q;
for ( int i=0; i<G->vexNum;i++) {mark[i]=FALSE;}
cout<<G->verTices[x].data;
mark[x]=TRUE;
Q.push(x);
while(!Q.empty()){
int v=Q.front();
Q.pop();
p=G->verTices[v].firstArc;
while(p){
int w=p->adjvex;
if(mark[w]==FALSE){
mark[w]=TRUE;
cout<<G->verTices[w].data;
Q.push(w);}
p=p->nextArc;
}
}
}
//拓撲排序
void TopsortbyQueue(ALGraph*G){
for(int i=0; i< G->vexNum;i++)
mark[i]=FALSE;
using std::queue;
queue<int> Q;
cout<<"拓撲序列為:"<<endl;
for(int i=0; i< G->vexNum;i++){
if(G->Indegree[i].indegree==0)
Q.push(i);}
while(!Q.empty()){
int v=Q.front();
Q.pop();
cout<<v;
mark[v]=TRUE;
for(Edge e=FirstEdge(G,v);isEdge(G,e);e=NextEdge(G,e)){
G->Indegree[e.to].indegree--;
if(G->Indegree[e.to].indegree ==0)
Q.push(e.to);
}
}
for(int i=0;i< G->vexNum;i++)
if(mark[i]==FALSE){
cout<<endl;
cout<<"還有頂點未訪問,此圖有環。"<<endl;
break;
}
}
int main(){
int x;
int num;
string edge;
ALGraph *Graph = (ALGraph *)malloc(sizeof(ALGraph));
CreateGraph(Graph);
DisplayGraph(Graph);
DFS(Graph);
BFS(Graph,0);
TopsortbyQueue(Graph);
system("pause");
}
相關文章
- C#實現圖的鄰接矩陣和鄰接表結構C#矩陣
- 第6章 圖的學習總結(鄰接矩陣&鄰接表)矩陣
- 14、圖-鄰接矩陣矩陣
- _DataStructure_C_Impl:圖的鄰接矩陣儲存ASTStruct矩陣
- 鄰接矩陣、度矩陣矩陣
- 【PTA】鄰接矩陣儲存圖的深度優先遍歷矩陣
- BFS求無權圖的單源最短路徑-鄰接矩陣儲存矩陣
- 鄰接表
- 圖的基本儲存的基本方式二—鄰接表(連結串列)
- 軟考筆記-有向圖的鄰接矩陣筆記矩陣
- 從零開始學golang之圖-鄰接矩陣Golang矩陣
- 圖的深度遍歷(C語言)鄰接矩陣表示C語言矩陣
- (C語言、資料結構)鄰接矩陣的初始化、邊的插入和輸出,以及鄰接矩陣的撤銷和邊的搜尋C語言資料結構矩陣
- BFS-圖的廣度優先搜尋--鄰接矩陣矩陣
- 樹形結構資料儲存方案(一):鄰接列表模式模式
- 【Python】Python中的圖的鄰接矩陣轉化為字典格式Python矩陣
- POJ 2778-DNA Sequence(AC自動機+構建鄰接矩陣+矩陣快速冪)矩陣
- 從原始邊列表到鄰接矩陣Python實現圖資料處理的完整指南矩陣Python
- 資料結構與演算法——圖的鄰接表表示法類的C++實現資料結構演算法C++
- 資料結構作業——用鄰接表表示無向網資料結構
- 圖的鄰接表演算法---(附完整程式碼)演算法
- 資料結構筆記(一)——C語言實現鄰接矩陣儲存的無向圖,判斷是否為連通圖,並且實現最小生成樹Prim演算法資料結構筆記C語言矩陣演算法
- 坐在馬桶上看演算法(9):巧妙的鄰接表演算法
- InnoDB儲存引擎——重新整理鄰接頁、啟動、關閉和恢復儲存引擎
- 分層資料 Hierarchical Data 探索 (2.鄰接表模型)模型
- dijkstra迪傑斯特拉演算法(鄰接表法)演算法
- Innodb關鍵特性之重新整理鄰接頁
- 在MySQL中管理分層資料---鄰接表模型和巢狀集模型MySql模型巢狀
- POJ 3159-Candies(差分約束系統-SPFA+鄰接表)
- 分層資料 Hierarchical Data 探索 (2.鄰接表模型) 無限極分類模型
- Python 圖_系列之基於鄰接炬陣實現廣度、深度優先路徑搜尋演算法Python演算法
- 圖的儲存結構
- 圖(Graph)——圖的儲存結構
- php圖的儲存結構PHP
- 【資料結構——圖和圖的儲存結構】資料結構
- 圖(1)--圖的相關術語與圖的儲存結構
- 結構型模式:橋接模式模式橋接
- 結構型模式----橋接模式模式橋接