邻接表

Posted 指间ゝ繁华初逝的格调

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了邻接表相关的知识,希望对你有一定的参考价值。

// crikal.cpp : 定义控制台应用程序的入口点。
//

#include "iostream"
#include "vector"
#include "stack"
#include <fstream> 
using namespace std;


#define  MaxNumVertex  20 //最大顶点数
#define  MaxNumEdge 40  //最大边数
#define  infinity 65535//无穷大
typedef int elementtype;       //elementtype 为int 型

//结点类型
struct ArcNode
{
    elementtype data;//顶点信息
    int weight ; //权重
    ArcNode *nextarc ;//指向下一条弧
};

//表头
struct VNode
{
    elementtype data;//顶点信息
    ArcNode *firstarc;//指向第一条弧
};
typedef struct VNode AdjList[MaxNumVertex];
    

class graph{
public:
    graph();
    ~graph();
    elementtype insertvertex(elementtype v); //在图中增加一个顶点
    elementtype insertedge(elementtype v,elementtype u,elementtype weight);//在图中增加一条从v顶点到u顶点的弧
    elementtype firstadj(elementtype v);//求图g中顶点v的第一个邻接点
    elementtype nextadj(elementtype v,elementtype m);//求图中顶点v的m邻接点之后的邻接点
    elementtype firstpre(elementtype v);//求图中顶点v的第一个前驱
    elementtype nextpre(elementtype v,elementtype m);//求图中顶点v的m前驱点之后的前驱点
    elementtype degreein(elementtype v);//求图中顶点v的入度数
    elementtype FindDegreein(elementtype ind[]);//各顶点的入度存放于入度数组中
    elementtype degreeout(elementtype v);//求图中顶点v的入度数
    elementtype FindDegreeout(elementtype oud[]);//各顶点的入度存放于入度数组中
    elementtype EW(elementtype E[]);//最早发生时间的求解
    bool CriticalPath();//关键路径
    elementtype create();//创建图
    int  CurrentVertex;//当前顶点数
    void show();
    elementtype Getedge(elementtype v,elementtype u);//在图中获得v顶点到u顶点的权重

private:
    AdjList vertices;
    elementtype vertex[MaxNumVertex];//顶点表
    elementtype edge[MaxNumVertex][MaxNumVertex];//图中弧的类型
    
};

/*
*初始化
*/
graph::graph()
{
    CurrentVertex = 0; 
}

/*
*在图中增加一个顶点
*/
elementtype graph::insertvertex(elementtype v)
{
    //判断这个顶点是否已经存在
    int i;
    bool flags = true;
    for(i=0;i<CurrentVertex;i++)
    {
        if(vertices[i].data==v)
        {
            flags = false ;
            break;
        }
    }
    if(flags)
    {
        vertices[CurrentVertex].data = v ;
        vertices[CurrentVertex].firstarc= NULL;
        CurrentVertex++;
    }else  cout<<v<<"顶点已经存在!"<<endl;
    return 0;
}

/*
*在图中增加一条从v顶点到u顶点的弧
*/
elementtype graph::insertedge(elementtype v,elementtype u,elementtype weight)
{
    int i ;
    ArcNode *s = new ArcNode;
    s->data = u;
    s->weight = weight;
    for( i = 0 ; i < CurrentVertex ; i ++ )
    {
        if(vertices[i].data==v)//找到顶点v对应的表头
        {
            ArcNode *p = new ArcNode;
            ArcNode *q = new ArcNode;
            p = vertices[i].firstarc ;
            bool flags = true;
            if(p==NULL)
            {
                //cout<<"Yes\n";
                s->nextarc = p;
                vertices[i].firstarc = s ;
                //    cout<<vertices[i].data<<","<<vertices[i].firstarc->data<<","<<vertices[i].firstarc->weight<<endl;
            }else
            {
                while(p!=NULL)
                {
                    if(p->data!=u)
                    {
                        q = p;
                        p = p->nextarc;
                    }else{
                        flags = false;
                        break;
                    }
                }
                if(flags)
                {
                    s->nextarc = q->nextarc;
                    q->nextarc = s;
               }else cout<<v<<"->"<<u<<"这条弧弧已经存在!"<<endl;
            }
        }
    }
    return 0;
}


/*
*求图中顶点v的第一个邻接点
*/
elementtype graph::firstadj(elementtype v)
{
    int i;
    elementtype u = 0;
    for(i=0;i<CurrentVertex;i++)
    {
        if(vertices[i].data==v)//找到顶点v对应的表头
        {
            ArcNode *p = new ArcNode;
            p = vertices[i].firstarc ;
            if(p)
            {
                u = p->data;
            }else
            {
                break;
            }
        }
    }
    return u;
}

/*
*求图中顶点v的m邻接点以后的邻接点
*/
elementtype graph::nextadj(elementtype v,elementtype m)
{
    int i;
    elementtype u = 0;
    for(i=0;i<CurrentVertex;i++)
    {
        if(vertices[i].data==v)//找到顶点v对应的表头
        {
            ArcNode *p = new ArcNode;
            p = vertices[i].firstarc ;
            while(p)
            {
                if(p->data!=m)
                {
                    p = p ->nextarc ;
                }else break;
            }
            if(p&&p->data==m&&p->nextarc) u = p->nextarc->data ;
            break;
        }
    }
    return u;
}

/*
*求图中顶点v的第一个前驱
*/
elementtype graph::firstpre(elementtype v)
{
    int i;
    elementtype u = 0;
    bool flags = false;
    for(i=0;i<CurrentVertex;i++)
    {    
        ArcNode *p = new ArcNode;
        p = vertices[i].firstarc ;
        while(p)
        {
            //cout<<p->data;
            if(p->data==v)
            {
                u = vertices[i].data;
                flags = true;
                break;
            }
            p = p ->nextarc;
        }
        if(flags)break;

    }
    return u;
}

/*
*求图中顶点v的m前驱点之后的前驱点
*/
elementtype graph::nextpre(elementtype v,elementtype m)
{
    int i,j;
    elementtype u = 0;
    bool flags = false;
    for(i=0;i<CurrentVertex;i++)
    {    
        if(vertices[i].data==m)
        {
            ArcNode *p = new ArcNode;
            for(j=i+1;j<CurrentVertex;j++)
            {
                p = vertices[j].firstarc ;
                while(p)
                {
                    if(p->data==v)
                    {
                        u = vertices[j].data;
                        flags = true;
                        break;
                    }
                    p = p ->nextarc;
                }
                if(flags)break;
            }
            break;
        }

    }
    return u;
}
/*
*求图中顶点v的入度数
*/
elementtype graph::degreein(elementtype v)
{
    int i,num = 0;
    for(i=0;i<CurrentVertex;i++)
    {    
        ArcNode *p = new ArcNode;
        p = vertices[i].firstarc ;
        while(p)
        {
            if(p->data==v)
            {
                num++;
                break;
            }
            p = p ->nextarc;
        }
    }
    return num;
}

/*
*每个顶点的入度
*/
elementtype graph::FindDegreein(elementtype ind[])
{
    int i;
    for(i=0;i<CurrentVertex;i++)
    {
        ind[vertices[i].data] = degreein(vertices[i].data);
    }
    return 0;
}

/*
*求图中顶点v的出度数
*/
elementtype graph::degreeout(elementtype v)
{
   int i,num = 0;
    for(i=0;i<CurrentVertex;i++)
    {    
        if(vertices[i].data==v)
        {
            ArcNode *p = new ArcNode;
            p = vertices[i].firstarc ;
            while(p)
            {
                num++;
                p = p ->nextarc;
            }
        break;
        }
    }
    return num;
}

/*
*每个顶点的出度
*/
elementtype graph::FindDegreeout(elementtype outd[])
{
    int i;
    for(i=0;i<CurrentVertex;i++)
    {
        outd[vertices[i].data] = degreeout(vertices[i].data);
    }
    return 0;
}

/*
*在图中获得v顶点到u顶点的权重
*/
elementtype graph::Getedge(elementtype v,elementtype u)
{
    int i;
    int weight = 0;
    for(i=0;i<CurrentVertex;i++)
    {
        if(vertices[i].data==v)
        {
            ArcNode *p = new ArcNode;
            p = vertices[i].firstarc ;
            while(p)
            {
                if(p->data==u)
                {
                    weight =p->weight;
                    break;
                }
                p = p ->nextarc;
            }
            break;
        }
    }
    return weight;
}
void graph::show()
{
    int i;
    elementtype m;
    cout<<"test"<<endl;
    for( i = 0 ; i < CurrentVertex ; i ++ )
    {
        ArcNode *p = new ArcNode;
        p = vertices[i].firstarc ;
        cout<<"表头:"<<vertices[i].data<<endl;
        while(p!=NULL)
        {
            cout<<p->data<<","<<p->weight<<endl;    
            p = p->nextarc;    
                
        }    
    }
    cout<<"第一个邻接点:"<<endl;
    for( i = 0 ; i < CurrentVertex ; i ++ )cout<<vertices[i].data<<","<<firstadj(vertices[i].data)<<endl;
    cout<<endl;
    cout<<"第2个邻接点:"<<endl;
    for( i = 0 ; i < CurrentVertex ; i ++ )
    {
            cout<<vertices[i].data<<":";
            m = firstadj(vertices[i].data) ;
            while(m)
            {
    
                m = nextadj(vertices[i].data,m);
                cout<<m<<",";
            }
            cout<<endl;
    }
    cout<<endl;
    
    for( i = 0 ; i < CurrentVertex ; i ++ )cout<<"第一个前驱点:"<<vertices[i].data<<","<<firstpre(vertices[i].data)<<endl;
    //cout<<"第一个前驱点:"<<vertices[CurrentVertex-1].data<<endl;
    //cout<<firstpre(vertices[CurrentVertex-1].data)<<endl;


    for( i = 0 ; i < CurrentVertex ; i ++ )
    {
            
           cout<<"第2个前驱:"<<vertices[i].data<<":";
            m = firstpre(vertices[i].data) ;
            while(m)
            {
    
                m = nextpre(vertices[i].data,m);
                cout<<m<<",";
            }
            cout<<endl;
    }
    
    cout<<endl;

    for( i = 0 ; i < CurrentVertex ; i ++ )cout<<"入度数目:"<<vertices[i].data<<","<<degreein(vertices[i].data)<<endl;
     elementtype ind[MaxNumVertex];//求各顶点的入度存放于入度数组ind中
    FindDegreein(ind);//
    for( i = 0 ; i < CurrentVertex ; i ++ )cout<<"入度数目:"<<ind[vertices[i].data]<<endl;
    for( i = 0 ; i < CurrentVertex ; i ++ )cout<<"出度数目:"<<vertices[i].data<<","<<degreeout(vertices[i].data)<<endl;
    elementtype outd[MaxNumVertex];//求各顶点的出度存放于出度数组outd中

    FindDegreeout(outd);//求各个结点的出度
    for( i = 0 ; i < CurrentVertex ; i ++ )cout<<"出度数目:"<<vertices[i].data<<","<<outd[vertices[i].data]<<endl;

    cout<<Getedge(vertices[CurrentVertex-2].data,vertices[CurrentVertex-1].data)<<endl;
}

/*
*最早发生时间的求解
*/
elementtype graph::EW(elementtype E[])
{
    int i;
    stack<elementtype> s;//定义并初始索要用到的栈
    elementtype x,w,ind[MaxNumVertex];//求各顶点的入度存放于入度数组ind中
    FindDegreein(ind);

    for(i=0;i<CurrentVertex;i++)//各个结点最早发生时间的初始化
    {
        E[vertices[i].data] = -1;
    }
    for(i=0;i<CurrentVertex;i++)//将入度为0的顶点入栈
    {
        if(degreein(vertices[i].data)==0)
        {
            s.push(vertices[i].data);
            E[vertices[i].data] = 0;//第一个入度为0的结点的最早发生时间为0
        }
    }
    int count =0;//用于统计已经完成的结点数目
    while(!s.empty())
    {
        x = s.top();
        count++;//计数
        s.pop();
        w = firstadj(x);//开始对v的各个后继顶点的入度-1
        while(w!=0)
        {
            if(E[w]<(E[x]+Getedge(x,w)))
            {
                E[w] = E[x]+Getedge(x,w);//更新w的最早发生时间
            }
            if(!(--ind[w]))//若w的入度-1后为0,则入栈
            {
                s.push(w);
            }
            w = nextadj(x,w);
        }
    }

    
    for(i=0;i<CurrentVertex;i++)//各个结点最早发生时间的初始化
    {
        cout<<E[vertices[i].data]<<endl;
    }

    if(count<CurrentVertex)return false;//产生有回路的标志
    else return true;
    return 0;
}

/*
*关键路径
*/
bool graph::CriticalPath()
{
    int i;
    stack<int> s;//定义并初始索要用到的栈
    elementtype x,w,ind[MaxNumVertex];//求各顶点的入度存放于入度数组ind中
    elementtype outd[MaxNumVertex];//求各顶点的出度存放于出度数组outd中
    elementtype E[MaxNumVertex];
    elementtype L[MaxNumVertex];
    FindDegreein(ind);//求各个结点的入度
    FindDegreeout(outd);//求各个结点的出度
    EW(E);//求各个结点的最早发生时间
    
    for(i=0;i<CurrentVertex;i++)
    {
        L[vertices[i].data] = infinity;//各个结点最迟发生时间的初始化
    }
    for(i=0;i<CurrentVertex;i++)//将出度为0的顶点入栈
    {
        if(degreeout(vertices[i].data)==0)
        {
            s.push(vertices[i].data);
            L[vertices[i].data] = E[vertices[i].data];//第一个出度为0的结点的最迟发生时间
        }
    }
    int count =0;//用于统计已经完成的结点数目
    while(!s.empty())
    {
        x = s.top();
        count++;//计数
        s.pop();
        w = firstpre(x);//开始对v的各个前驱顶点的出度-1
        while(w!=0)
        {
            if(L[w]>(L[x]-Getedge(w,x)))
            {
                L[w] = L[x]-Getedge(w,x);//更新w结点的最迟发生时间
            }
    
            if(!(--outd[w]))//若w的出度-1后为0,则入栈
            {
                s.push(w);
            }
            w = nextpre(x,w);
        }

    }

    cout<<"E[i],L[i]:"<<endl;
    for(i=0;i<CurrentVertex;i++)//输出各个节点的最早发生时间和最迟发生时间
    {
        cout<<"E["<<i<<"]="<<E[vertices[i].data]<<",L["<<i<<"]="<<L[vertices[i].data]<<endl;
    }

    vector<elementtype>equal;//记录E[I]=L[I]
    for(i=0;i<CurrentVertex;i++)
    {
        if(E[vertices[i].data]==L[vertices[i].data])
        {
            equal.push_back(vertices[i].data);
        }
    }

    elementtype start,end;
    for(i=0;i<CurrentVertex;i++)//寻找起始结点
    {
        if(degreein(vertices[i].data)==0)
        {
            start = vertices[i].data;
            break;
        }
    }
    FindDegreeout(outd);//求各个结点的出度
    for(i=CurrentVertex-1;i>=0;i--)//寻找终止结点
    {
        if(degreeout(vertices[i].data)==0)
        {
            end = vertices[i].data;
            break;
        }
    }

    cout<<"CriticalPath is:";
    while(start!=end)
    {
        for(i=0;i<equal.size();i++)//输出关键路径
        {
            if(Getedge(start,equal[i])!=0)
            {
                cout<<start<<"->";
                start = equal[i];
                if(start==end)
                {
                    cout<<start<<endl;
                }
                break;
            }
        }
    }
    return 0;
}

/*
*创建图
*/
elementtype graph::create()
{
    int i,VertextNum,ArcNum,v,u,weight;
    ifstream infile("file.txt",ios::in);
    if(!infile)
    {
        cerr<<"open error!"<<endl;
        exit(1);
    }
    infile>>VertextNum>>ArcNum;
    for( i = 0 ; i < VertextNum ; i ++ )
    {
        infile>>v;
        insertvertex(v);
    }
    for( i = 0 ; i < ArcNum ; i ++ )
    {
        infile>>v>>u>>weight;
        insertedge(v,u,weight);
    }
    infile.close();
    cout<<"graph create finish!"<<endl<<endl;
    return 0;
}
graph::~graph()
{
}

int main()
{
    graph g;
    g.create();
    g.show();
    g.CriticalPath();
    return 0;
}

 

以上是关于邻接表的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵

LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵

LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵

LeetCode207.课程表 | BFS DFS 邻接表 邻接矩阵

(王道408考研数据结构)第六章图-第二节1:图的存储结构(邻接矩阵邻接表十字链表和邻接多重表)

图的存储代码实现