1. 程式人生 > >鄰接表&十字連結串列

鄰接表&十字連結串列

鄰接表:

在這裡插入圖片描述 每一行都可以看成一個單鏈表,第一行中,v0-1-3可以得到,v0的出度為v1和v3。

鄰接表完整程式碼:

#include <iostream>
using namespace std;

const int MAX_V = 15;

//邊節點
typedef struct Edge_node {
    char data;
    Edge_node *next;
}Enode,*pEnode;

//表節點
typedef struct List_node {
    char data;
    Edge_node *firstEdge;
}Lnode, *pLnode;


int main()
{
    void AddEdge( char v1, char v2, pLnode list, int V );
    void display( pLnode list, int V );
    void clear( pLnode list, int V);

    int V,E;
    cout << "input vertex number and edge number:\n";//輸入頂點數和邊數
    cin >> V >> E;

    Lnode list[MAX_V];//建立陣列
    for( int i=0; i<V; ++i ){
        list[i].firstEdge = NULL;
    }

    cout << "input vertex:\n";//輸入頂點
    for( int i=0; i<V; ++i )
        cin >> list[i].data;

    cout << "input edges, eg: a b \n";
    char v1,v2;
    for( int i=0; i<E; ++i ){

        cin >> v1 >> v2;
        AddEdge( v1, v2, list, V);
    }

    //輸出
    cout <<"display:\n";
    display( list, V );

    cout << "clear:\n";
    clear( list, V );

    return 0;
}

void AddEdge( char v1, char v2, pLnode list, int V ) {

    for( int i=0; i<V; ++i ){

        if( v1==list[i].data ){
            //生成新的邊節點
            pEnode newEdge = new Enode;
            newEdge->data = v2;
            newEdge->next = NULL;

            newEdge->next = list[i].firstEdge;
            list[i].firstEdge = newEdge;

            break;
        }
    }
}

void display( pLnode list, int V ){

    for( int i=0; i<V; ++i ){
        cout << list[i].data <<": ";
        pEnode p = list[i].firstEdge;
        while( p ){
            cout << p->data << ' ';
            p = p->next;
        }
        cout <<endl;
    }
}

void clear( pLnode list, int V){

    for( int i=0; i<V; ++i ){
        pEnode p = list[i].firstEdge;
        pEnode todel;
        while( NULL!=p ){
            todel = p;
            cout <<"delete is "<< todel->data << ' ';
            p = p->next;
            delete todel;
        }
        cout << endl;
    }

}

但對於有向圖來說,鄰接表是有缺陷的,關心了出度問題,想了解入度就必須要遍歷整個圖才能知道,反之,逆鄰接表解決了入度的情況。 而十字連結串列可以同時解決出度和入度的問題。

十字連結串列

重新定義表節點結構:增加了兩個指標firstIn,firstOut。分別用來指向該頂點的入(出)邊表中第一個結點。

在這裡插入圖片描述 firstin表示入邊表頭指標,指向該頂點的入邊表中第一個結點;

firstout表示出邊表頭指標,指向該頂點的出邊表中第一個結點; tailvex是指弧起點在頂點的下標,

headvex是指弧終點在頂點表中的下標,

headlink是指入邊表指標域,指向終點相同的一下條邊

taillink是指出邊表指標域,指向起點相同的下一條邊。

對比

與鄰接表相比,這裡的 tailLink 指標就相當於鄰接表裡的那個指標,指向出度的下一個節點。而這裡的 headLink 就是新增加的用來記錄入度的指標。 在這裡插入圖片描述 首先,橫著看:每一行都可以看出單鏈表,把從 firstOut 出來的串起來就是出度(類似鄰接表); 豎著看(不太明顯):從 headLink 出來的指標指向串起來,都是入度節點。

那為什麼要重複儲存節點資訊呢?例如圖中的0存了2次,1存了3次等。這是為了方便找入度節點。試想,鄰接表用一個指標一個節點資訊來儲存方便找出度,那麼要是出度入度都方便找,自然要給入度也加上一個指標(headLink)和一個數據域(tailVex)。這樣當找到入度的邊接節點,取出 headLink 就找到入度節點了。

將邊節點結構分割: 入度:headLink + tailVex; 出度:tailLink + headVex;

十字連結串列程式碼:

#include <iostream>
#include <cstring>
using namespace std;

const int MAX_V = 15;
//邊節點
typedef struct Edge_node {
    char tailVex,headVex;           //tailvex是指弧起點在頂點的下標,headvex是指弧終點在頂點表中的下標,
    Edge_node *tailLink, *headLink;//headlink指向弧頭相同的下一條弧。taillink指向弧尾相同的下一條弧.
}Enode,*pEnode;

//表節點
typedef struct List_node {
    char data;
    Edge_node *firstIn, *firstOut;//firstin表示入邊表頭指標,指向該頂點的入邊表中第一個結點.
}Lnode, *pLnode;

int main()
{
    void AddEdge( char v1, char v2, pLnode list, int V );
    void display( pLnode list, int V );
    void clear( pLnode list, int V);

    int V,E;
    cout << "input vertex number and edge number:\n";//輸入頂點數和邊數
    cin >> V >> E;

    Lnode list[MAX_V];//建立陣列
    for( int i=0; i<V; ++i ){
        list[i].firstIn = NULL;
        list[i].firstOut = NULL;
    }

    //輸入頂點
    cout << "input vertex:\n";
    for( int i=0; i<V; ++i )
        cin >> list[i].data;

    //輸入邊
    cout << "input edges, eg: a b \n";
    char v1,v2;
    for( int i=0; i<E; ++i ){

        cin >> v1 >> v2;
        AddEdge( v1, v2, list, V);
    }

    //輸出
    cout <<"display:\n";
    display( list, V );

    cout << "clear:\n";
    clear( list, V );

    return 0;
}

void AddEdge( char v1, char v2, pLnode list, int V ){

    int getIndex( char x , pLnode list , int V );
    int v1_index = getIndex( v1 , list, V );
    int v2_index = getIndex( v2, list ,V );

    pEnode newEdge = new Enode;
    newEdge->tailVex = v1;
    newEdge->headVex = v2;

    //添加出度
    newEdge->tailLink = list[v1_index].firstOut;
    list[v1_index].firstOut = newEdge;

    //新增入度
    newEdge->headLink = list[v2_index].firstIn;
    list[v2_index].firstIn = newEdge;
}
int getIndex( char x, pLnode list, int V ){

    for( int i=0; i<V; ++i ){
        if( x==list[i].data )
            return i;
    }
}

void display( pLnode list, int V ){

    for( int i=0; i<V; ++i ){
        cout << list[i].data <<" out : ";
        pEnode p = list[i].firstOut;
        while( p ){
            cout << p->headVex << ' ';
            p = p->tailLink;
        }
        cout <<endl;

        cout << list[i].data <<" in : ";
        p = list[i].firstIn;
        while( p ){
            cout << p->tailVex << ' ';
            p = p->headLink;
        }
        cout <<endl;
    }

}

void clear( pLnode list, int V){

    for( int i=0; i<V; ++i ){
        pEnode p = list[i].firstOut;
        pEnode todel;
        while( NULL!=p ){
            todel = p;
            cout <<"delete is "<< todel->headVex << ' ';
            p = p->tailLink;
            delete todel;
        }
        cout << endl;
    }
}