图的两种存储方式---邻接矩阵和邻接表

   图:图是一种数据结构,由顶点的有穷非空集合和顶点之间边的集合组成,表示为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)销毁函数。

 

posted @ 2018-05-23 19:56  XNQC  阅读(3545)  评论(0编辑  收藏  举报