圖的兩種存儲方式---鄰接矩陣和鄰接表


   圖:圖是一種數據結構,由頂點的有窮非空集合和頂點之間邊的集合組成,表示為G(V,E),V表示為頂點的集

合,E表示為邊的集合。

   首先肯定是要對圖進行存儲,然后進行一系列的操作,下面對圖的兩種存儲方式鄰接矩陣和鄰接表盡行介紹。

   (一)、鄰接矩陣存儲:

   用兩個數組分別進行存儲數據元素(頂點)的信息和數據元素之間的關系(邊或弧)的信息。

   存儲頂點:用一個連續的空間存儲n個頂點。

   存儲頂點之間的邊:將由n個頂點組成的邊用一個n*n的矩陣來存儲,如果兩個頂點之間有邊,則表示為1,否

則表示為0。

   下面用代碼來實現鄰接矩陣的存儲:

#define SIZE 10

class Graph
{
public:
    Graph()
    {
        MaxVertices = SIZE;
        NumVertices = NumEdges = 0;
        VerticesList = new char[sizeof(char)*MaxVertices];
        Edge = new int*[sizeof(int*)*MaxVertices];
        int i,j;
        for(i = 0;i<MaxVertices;i++)
            Edge[i] = new int[sizeof(int)*MaxVertices];
        for(i = 0;i<MaxVertices;i++)
        {
            for(j = 0;j<MaxVertices;++j)
                Edge[i][j] = 0;
        }
    }
    void ShowGraph()
    {
        int i,j;
        cout<<"  ";
        for(i = 0;i<NumVertices;i++)
            cout<<VerticesList[i]<<" ";
        cout<<endl;
        for(i = 0;i<NumVertices;i++)
        {
            cout<<VerticesList[i]<<" ";
            for(j = 0;j<NumVertices;j++)
                cout<<Edge[i][j] <<" ";
            cout<<endl;
        }
        cout<<endl;
    }
    int GetVertexPos(char v)
    {
        int i;
        for(i = 0;i<NumVertices;i++)
        {
            if(VerticesList[i] == v)
                return i;
        }
        return -1;
    }
    ~Graph()
    {
        Destroy();
    }
    void Insert(char v)
    {
        if(NumVertices < MaxVertices)
        {
            VerticesList[NumVertices] = v;
            NumVertices++;   
        }
    }
    void InsertEdge(char v1,char v2)  
    {
        int i,j;
        int p1 = GetVertexPos(v1);  
        int p2 = GetVertexPos(v2);
        if(p1 == -1 || p2 == -1)
            return ;
        Edge[p1][p2] = Edge[p2][p1] = 1;
        NumEdges++;  
    }
    void RemoveEdge(char v1,char v2)
    {
        int p1 = GetVertexPos(v1);
        int p2 = GetVertexPos(v2);
        if(p1 == -1 || p2== -1)
            return;
        if(Edge[p1][p2] == 0) 
            return;
        Edge[p1][p2] = Edge[p2][p1] = 0;
        NumEdges--;
    }
    void Destroy()
    {
        delete[] VerticesList;
        VerticesList = NULL;
        for(int i = 0;i<NumVertices;i++)
        {
            delete Edge[i];
            Edge[i] = NULL;
        }
        delete[] Edge;
        Edge = NULL;

        MaxVertices = NumVertices = 0;
    }
    void RemoveVertex(char v)
    {
        int i,j;
        int p = GetVertexPos(v);
        int reNum = 0;
        if(p == -1)
            return;
        for(i = p;i<NumVertices-1;i++) 
        {
            VerticesList[i] = VerticesList[i+1];
        }
        
        for(i = 0;i<NumVertices;i++)
        {
            if(Edge[p][i] != 0)
                reNum++;
        }
        for(i = p;i<NumVertices-1;i++)
        {
            for(j = 0;j<NumVertices;j++)
            {
                Edge[i][j] = Edge[i+1][j];
            }
        }
        for(i = p;i<NumVertices;i++)
        {
            for(j = 0;j<NumVertices;j++)
                Edge[j][i] = Edge[j][i+1];
        }

        NumVertices--;
        NumEdges = NumEdges - reNum;
    }
private:
    int MaxVertices;
    int NumVertices;
    int NumEdges;
    char *VerticesList;
    int **Edge;
};

    上面的類中的數據有定義最大的頂點的個數(MaxVertices),當前頂點的個數(NumVertices),當前邊的個數

(NumEdges),保存頂點的數組,保存邊的數組。其中的方法是(1)構造函數:對定義的數據進行初始化。(2)顯

示構造的圖的信息的函數。(3)得到頂點位置信息的函數。(4)析構函數:調用銷毀函數。(5)插入頂點函數。

(6)插入邊的函數。(7)刪除邊的函數。(8)銷毀函數,釋放開辟的內存空間。(9)刪除頂點函數。

  (二)、鄰接表存儲:

   鄰接表是圖的一種鏈式存儲結構。用數組存儲頂點,用鏈表存儲和頂點相關聯的邊,邊值為當前頂點在數組中的下

標。用如下圖可以表示鄰接表的存儲方式:

                 

                  

   下面用代碼來實現鄰接表的存儲:

#define SIZE 10
typedef char T;
struct Edge
{
    Edge(int v):destvalue(v),link(NULL){}
    int destvalue;
    Edge *link;
};
struct Vertex
{
    Vertex():list(NULL){}
    T data;
    Edge *list;
};
class GraphLnk
{
public:
    GraphLnk();
    ~GraphLnk(){}

    void InsertVertex(T v);
    void InsertEdge(T v1,T v2);
    int GetVertexI(T v);
    void ShowGraph();
    void RemoveEdge(T v1,T v2);
    void RemoveVertex(T v);
    void DestroyGraph();
private:
    int MaxVertex;
    int NumVertex;
    int NumEdge;

    Vertex *VertexTable;
};

GraphLnk::GraphLnk()
{
    MaxVertex = SIZE;
    NumVertex = NumEdge = 0;
    VertexTable = new Vertex[MaxVertex];
}
void GraphLnk::InsertVertex(T v)
{
    if(NumVertex >= MaxVertex)
        return;
    VertexTable[NumVertex++].data = v;
}
void GraphLnk::ShowGraph()
{
    int i;
    for(i = 0;i<NumVertex;i++)
    {
        cout<<i<<" "<<VertexTable[i].data<<":->";
        Edge *p = VertexTable[i].list;
        while(p != NULL)
        {
            cout<<p->destvalue<<"->";
            p = p->link;
        }
        cout<<"nul"<<endl;
    }
    cout<<endl;
}
int GraphLnk::GetVertexI(T v)
{
    int i;
    for(i = 0;i<NumVertex;i++)
    {
        if(VertexTable[i].data == v)
            return i;
    }
    return -1;
}
void GraphLnk::InsertEdge(T v1,T v2)
{
    int p1 = GetVertexI(v1);
    int p2 = GetVertexI(v2);
    if(p1 == -1 || p2 == -1)
        return;
    //v1 -> v2
    Edge *ed = new Edge(p2);
    ed->link = VertexTable[p1].list;
    VertexTable[p1].list = ed;
    //v2 -> v1
    ed = new Edge(p1);
    ed->link = VertexTable[p2].list;
    VertexTable[p2].list = ed;

    NumEdge++;
}

void GraphLnk::RemoveEdge(T v1,T v2)
{
    int p1 = GetVertexI(v1);
    int p2 = GetVertexI(v2);
    if(p1 == -1 || p2 == -1)
        return;
    Edge *q = NULL;              //標識要刪除邊鏈表的前一個
    Edge *p;

    p = VertexTable[p1].list;    //從鏈表開頭開始
    //查找v2所在位置
    while(p != NULL && p->destvalue != p2)
    {
        q = p;
        p = p->link;
    }
    if(p == NULL)          //兩個頂點之間沒有邊的存在¨
        return;
        //找到所要刪除的邊
        if(q == NULL)      //所要刪除的為鏈表開頭
        {
            VertexTable[p1].list = p->link;
        }
        else
        {
            q->link = p->link;
        }
        delete p;
        p = NULL;
 
        q = NULL;
        p = VertexTable[p2].list;
        while(p->destvalue != p1)
        {
            q = p;
            p = p->link;
        }
        if(q == NULL)
        {
            VertexTable[p2].list = p->link;
        }
        else
        {
            q->link = p->link;
        }
        delete p;
        p = NULL;
        NumEdge--;
}

void GraphLnk::RemoveVertex(T vertex)
{
    int v  = GetVertexI(vertex);
    if(v == -1)
        return;
    //刪除和結點相關的邊
    Edge*p=VertexTable[v].list;

    Edge *s;
    Edge *t = NULL;
    int k;
    while(p != NULL)
    {
        k = p->destvalue;
        s = VertexTable[k].list;
        while(s != NULL&&s->destvalue != v)
        {
            t = s;
            s = s->link;
        }
        if(s != NULL)
        {
            if(t == NULL)     //第一個結點
            {
                VertexTable[k].list = s->link;
            }
            else
            {
                t->link = s->link;
            }
            delete s;
            s = NULL;
        }
        
        VertexTable[v].list = p->link;

        delete p;
        p = VertexTable[v].list;
    }
    /*刪除結點,用最后一個結點覆蓋要刪除的結點,並把和
    最后一個結點相關聯的邊的下標改正
    */
    NumVertex--;
    VertexTable[v].data = VertexTable[NumVertex].data; 
    VertexTable[v].list = VertexTable[NumVertex].list;

    s = VertexTable[v].list;
    while(s != NULL)
    {
        k = s->destvalue;
        p = VertexTable[k].list;
        while(p != NULL)
        {
            if(p->destvalue == NumVertex)   
            {
                p->destvalue = v;
                break;
            }
            p = p->link;
        }
        s = s->link;
    }
}

void GraphLnk::DestroyGraph()
{
    Edge *p;
    for(int i = 0;i<NumVertex;i++)
    {
        p = VertexTable[i].list;
        while(p != NULL)
        {
            VertexTable[i].list = p->link;
            delete p;
            p = VertexTable[i].list;
        }
    }
    delete []VertexTable;
    MaxVertex = NumEdge = NumVertex = 0;
}

   在代碼實現的過程中,先定義出頂點和邊的數據結構,然后在類中定義了最大頂點數,當前頂點的個數,當前的

邊的個數,頂點類型的數組,還有在類中進行了函數的聲明,包括(1)構造函數。(2)析構函數。(3)插入頂點

函數。(4)插入邊函數。(5)得到頂點位置的函數。(6)顯示構造出的圖的信息函數。(7)刪除邊函數。(8)

刪除頂點函數。(9)銷毀函數。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM