1. 程式人生 > >再談圖的儲存方式(鄰接矩陣,鄰接表,前向星)

再談圖的儲存方式(鄰接矩陣,鄰接表,前向星)

1.鄰接矩陣

1.存圖思想

使用一個矩陣來描述一個圖,對於矩陣的第i行第j列的值,表示編號為i的頂點到編號為j的頂點的權值。

2.程式碼實現

// 最大頂點數
const int V = 1000;

// 鄰接矩陣的定義
// mat[i][j] 表示 頂點'i'到頂點'j'的權值
int mat[V][V];

// 鄰接矩陣的初始化操作
// 假設權值為零表示沒有該邊
memset(mat, 0, sizeof(mat))

// 增加邊
// 新增頂點'i'到頂點'j'的邊,權值為w
mat[i][j] = w;

//遍歷鄰接邊
for(int i=0;i<n;i++)
{
    for(int j=0;j<n;j++)
    {
        if(mat[i][j]!=0)
            //doing something.
    }
}

2.鄰接表

1.存圖思想

鄰接矩陣對於每個頂點使用定長的陣列來儲存以該點出發的邊的情況。第i個數組的第j個值儲存的是從頂點i到頂點j的邊的權值。 
鄰接表則是對於每個頂點使用不定長的連結串列來儲存以該點出發的邊的情況。因此對第i個連結串列的第j個值實際上儲存的是編號為i的頂點出發的第j條邊的情況。

2.程式碼實現

在ACM題目中,動態的資料結構一般是不被推薦的,因為動態開闢記憶體比較消耗時間,且寫起來複雜容易出錯。 
大部分情況我們使用C++STL裡的vector作為連結串列來實現圖的鄰接表。
// 最大頂點數
const int V = 100000;

// vector實現的鄰接表的定義
// 不考慮邊權,儲存型別為int型
vector<int> e[V];
// 若考慮邊權,則定義一個結構,vector也為結構體型別
struct node{int v,int w};//儲存邊的終點和邊的權值
vector<node> e[V];
//也可以用一個數組或vector單獨存邊的資訊,然後在鄰接表vector中記錄每個點鄰接邊的編號

// 鄰接表的初始化操作
for(int i=0;i<n;i++)
{
    e[i].clear();
}


// 增加邊
//不考慮邊權
e[i].push_back(j);
//考慮邊權
e[i].push_back(node(j,w));


//遍歷鄰接邊
for (int j=0; j<(int)e[i].size(); ++j) {
    int k=e[i][j];//第j條邊為[i,k]
    //or
    node &e=e[i][j];//第j條邊為[i,e.v,e.w]
    // do something.
}

3.前向星

1.存圖思想

前向星是一種特殊的邊集陣列,我們把邊集陣列中的每一條邊按照起點從小到大排序,如果起點相同就按照終點從小到大排序, 並記錄下以某個點為起點的所有邊在陣列中的起始位置和儲存長度,那麼前向星就構造好了. 
用len[i]來記錄所有以i為起點的邊在陣列中的儲存長度.//不用len陣列也可以
用head[i]記錄以i為邊集在陣列中的第一個儲存位置.

2.程式碼實現

一般不用不寫了。。。

4.鏈式前向星

1.存圖思想

我們建立邊結構體為:
struct Edge
{
     int next;
     int to;
     int w;
};
其中edge[i].to表示第i條邊的終點,edge[i].next表示與第i條邊同起點的下一條邊的儲存位置,edge[i].w為邊權值. 
另外還有一個數組head[],它是用來表示以i為起點的第一條邊儲存的位置,實際上你會發現這裡的第一條邊儲存的位置其實是在以i為起點的所有邊的最後輸入的那個編號.head[]陣列一般初始化為-1。 

2.程式碼實現

// 最大頂點數
const int V = 1000;
const int E = 10000;

struct Edge
{
    int next;
    int to;
    int w;
};
Edge edge[E];
int head[V];

//初始化
memset(head,0xff,sizeof(head));
memset(edge,0,sizeof(edge));

//增加邊
void add(int u,int v,int w) 
{  
    //cnt為邊計數
    edge[cnt].w = w;  
    edge[cnt].to = v;  
    edge[cnt].next = head[u];  
    head[u] = cnt++;  
} 

//遍歷邊
for(int i=1;i<=n;i++)
{
    for(int k=head[i];k!=-1;k=edge[k].next)
    {
        //doing something.
    }
}
相關資料: