1. 程式人生 > >《資料結構》C++程式碼 鄰接表與鄰接矩陣

《資料結構》C++程式碼 鄰接表與鄰接矩陣

         上一篇“BFS與DFS”寫完,突然意識到這個可能偏離了“資料結構”的主題,所以回來介紹一下圖的儲存:鄰接表和鄰接矩陣。

         存圖有兩種方式,鄰接矩陣嚴格說就是一個bool型的二維陣列,map[i][j]表示i到j有沒有單向邊,鄰接表則是對1~N中每個點都拉出一個連結串列來,連結串列E[i]中存的每個點j都表示i到j有一條單向邊。          這兩種方式各有利弊,在稀疏圖中,鄰接表更好,省時間而且省空間;在稠密圖中,鄰接矩陣更好,不浪費時間的同時省去了指標域的空間。

而實際寫程式碼時,對於鄰接矩陣,我們可能會考慮用int型的鄰接矩陣來同時表達邊的權值,這取決於具體情況;對於鄰接表,我們在對每個點拉出一個連結串列時,可以實際分配一個一維陣列作為表頭,以簡化刪除邊時的程式碼,同時方便存每個點的資訊,也可以像本文程式碼中直接用指標來作為表頭,省些空間。

         本文僅僅給出相對基本的程式碼,邊上的資訊僅有一個權值,想必這已經夠了。如果資訊增多,大家在同樣的位置新增資訊即可。另外,臨界表在很多情況下是可以用靜態記憶體來代替動態記憶體的,這個方法本文程式碼就不贅述了,方法同“線性表”一文中所述。

         注意!對於鄰接表和鄰接矩陣,我並未試過用類來寫,在此僅僅給出一個很醜的類版程式碼,不是為了供大家參考,而是拋磚引玉,希望有高手能給出更好的類版實現程式碼,不勝感激!

清爽版:

const int maxn = 10000;

// 鄰接矩陣
struct edge
{
    bool p; // p表示此邊有無,也可以通過c取一個題目中不可能取到的值來代替p的作用
    int c;
    edge():p(false) {}
}map[maxn+1][maxn+1];
void Clear()
{
    for(int i=1;i<=maxn;++i)
        for(int j=1;j<=maxn;++j) map[i][j].p=false;
}
void AddEdge(int u,int v,int c)
{
    map[u][v].p=true; map[u][v].c=c;
}
void DelEdge(int u,int v)
{
    map[u][v].p=false;
}

// 鄰接表
struct edge
{
    int v;
    int c;
    edge *next;
    edge(int _v=0,int _c=0): v(_v), c(_c) {}
}*E[maxn+1]; // 全域性定義,初始便都是0;若在區域性定義,則應先清0
void Clear()
{
    edge *p;
    for(int i=1;i<=maxn;++i)
        while(E[i])
        {
            p=E[i]; E[i]=p->next;
            delete p;
        }
}
void AddEdge(int u,int v,int c)
{
    edge *p=new edge(v,c);
    p->next=E[u]; E[u]=p;
}
void DelEdge(int u,int v)
{
    if(E[u]->v==v) { E[u]=E[u]->next; return; }
    for(edge *p=E[u],*q=p->next;q;p=q,q=p->next)
        if(q->v==v)
        {
            p->next=q->next;
            delete q;
            return; // 如果有重邊,則此處不應返回,應待迴圈完再返回
        }
}

類版:

// 鄰接表
struct edge
{
    int v;
    int c;
    edge *next;
    edge(int _v=0,int _c=0): v(_v), c(_c) {}
};

class Map
{
    static const int maxn = 10000;
    edge *E[maxn+1];
public:
    Map() { for(int i=1;i<=maxn;++i) E[i]=0; }
    void clear()
    {
        edge *p;
        for(int i=1;i<=maxn;++i)
            while(E[i])
            {
                p=E[i]; E[i]=p->next;
                delete p;
            }
    }
    void add(int u,int v,int c)
    {
        edge *p=new edge(v,c);
        p->next=E[u]; E[u]=p;
    }
    void del(int u,int v)
    {
        if(E[u]->v==v) { E[u]=E[u]->next; return; }
        for(edge *p=E[u],*q=p->next;q;p=q,q=p->next)
            if(q->v==v)
            {
                p->next=q->next;
                delete q;
                return; // 如果有重邊,則此處不應返回,應待迴圈完再返回
            }
    }
    edge* begin(int u) { return E[u]; }
    edge* next(edge *p) { return p->next; }
}G;