图的邻接矩阵表示和拓扑排序

实现了:图的相邻矩阵的转换,深度和广度遍历,拓扑排序

// 图的相邻矩阵表示方法
#include <iostream>
#include <queue>
using namespace std;

#define N 5 // 定义图的顶点数


//***********   Graph.h   ************//
//图的基类

#define UNVISITED 0
#define VISITED 1
const int INFINITE = 0x7fffffff;  // 有符号数

//Edge类
class Edge
{
public:
    int weight;     // weight是边的权
    int from;       // from是边的始点
    int to;         // to是边的终点
    Edge()   	    // 构造函数
    {
        from = -1;
        to = -1;
        weight = 0;
    }
    Edge(int f,int t,int w)     // 构造函数
    {
        from=f;
        to=t;
        weight=w;
    }
    bool operator < (const Edge &arg)
    {
        return (this->weight < arg.weight);
    };
    bool operator == (const Edge &arg)
    {
        return (this->weight == arg.weight);
    };
    bool operator > (const Edge &arg)
    {
        return (this->weight > arg.weight);
    };
    bool operator <= (const Edge &arg)
    {
        return (this->weight <= arg.weight);
    };
    bool operator >= (const Edge &arg)
    {
        return (this->weight >= arg.weight);
    };
};

//图基类
class Graph
{
public:
    int numVertex;              //图的顶点的个数
    int numEdge;				//图的边的数目
    int *Mark;					/*Mark指针指向保存有图的顶点的标志位的数组,标志位用来标记某顶点是否被访问过*/
    int *Indegree;				//Indegree指针指向保存有图的顶点的入度的数组
    Graph(int numVert)   		//构造函数
    {
        numVertex = numVert;        //确定图的顶点的个数
        numEdge = 0;				//确定图的边的数目
        Indegree = new int[numVertex];  /*为保存图的顶点的入度申请数组,Indegree为数组指针*/
        Mark = new int[numVertex];	    /*为图的顶点的标志位申请数组,Mark为数组指针*/

        /*确定图的顶点的标志位和入度,即所有顶点的标志位初始化为未被访问过,入度初始化为0*/
        for (int i = 0; i < numVertex; i ++)
        {
            Mark[i] = UNVISITED;
            Indegree[i] = 0;
        }
    }

    ~Graph()  				//析构函数
    {
        delete [] Mark;
        delete [] Indegree;
    }

    virtual Edge FirstEdge(int oneVertex)  	// 返回与顶点oneVertex相关联的第一条边
    {
        Edge myEdge;
        myEdge.from = oneVertex;
        myEdge.to = -1;
        return myEdge;
    }

    virtual Edge NextEdge(Edge preEdge)        // 返回与边PreEdge有相同关联顶点的下一条边
    {
        return preEdge;
    }

    int VerticesNum()  		        //返回图的顶点个数
    {
        return numVertex;
    }

    int EdgesNum()  			    //返回图的边数
    {
        return numEdge;
    }

    int FromVertex(Edge oneEdge)    // 返回oneEdge的始点
    {
        return oneEdge.from;
    }

    int ToVertex(Edge oneEdge)  	// 返回oneEdge的终点
    {
        return oneEdge.to;
    }

    int Weight(Edge oneEdge)  		// 返回oneEdge的权值
    {
        return oneEdge.weight;
    }

    bool IsEdge(Edge oneEdge)   	//如果oneEdge是边则返回TRUE,否则返回FALSE
    {
        if (oneEdge.weight > 0 && oneEdge.weight < INFINITE && oneEdge.to >= 0)
            return true;
        else
            return false;
    }

    virtual void setEdge(int from, int to, int weight) = 0;
    virtual void delEdge(int from, int to) = 0;
};


// 图的相邻矩阵表示法
class Graphm:public Graph
{
private:
    int **matrix;				//指向相邻矩阵的指针
public:
    void IniGraphm(Graphm *Graphm, int A[N][N]); // 初始化
    void DFS(Graph &G, int v);			// 深度优先搜索
    void BFS(Graph &G, int v);			// 广度优先搜索
    void Visit(Graph &G, int v);		// 访问

public:
    Graphm(int numVert):Graph(numVert)   //构造函数
    {
        int i, j;			//i, j作为for循环中的计数器
        matrix = (int **)new int*[numVertex]; /*申请matrix数组,该数组有numVertex个元素,每个元素是整型指针类型*/

        for (i = 0; i < numVertex; i ++)      /*matrix数组的每个元素,都指向一个具有numVertex个元素的数组*/
            matrix[i] = new int[numVertex];

        for (i = 0; i < numVertex; i++)       /*相邻矩阵的所有元素都初始化为0,如果矩阵元素matrix[i][j]不为0,则表明顶点i与顶点j之间有一条边,边的权即为matrix[i][j]的值*/
            for (j = 0; j < numVertex; j ++)
                matrix[i][j] = 0;
    }

    ~Graphm()  							//析构函数
    {
        for (int i = 0; i < numVertex; i ++)
            delete [] matrix[i];			//释放每个matrix[i]申请的空间
        delete [] matrix;				    //释放matrix指针指向的空间
    }

    Edge FirstEdge(int oneVertex)   	    //返回顶点oneVertex的第一条边
    {
        Edge myEdge;						//边myEdge将作为函数的返回值
        myEdge.from = oneVertex;			//将顶点oneVertex作为边myEdge的始点
        //  myEdge.to = -1;
        for (int i = 0; i < numVertex; i ++)
        {
            /* 下面寻找第一个使得matrix[oneVertex][i]
                不为0的i值,那么边(oneVertex,i)或者
            	弧<oneVertex,i>即为顶点oneVertex
            	的第一条边,将顶点i作为边myEdge的终点边myEdge
            	的权为矩阵元素matrix[oneVertex][i]的值*/
            if (matrix[oneVertex][i] != 0)
            {
                myEdge.to = i;
                myEdge.weight = matrix[oneVertex][i];
                break;
            }
        }
        return myEdge;/*如果找到了顶点oneVertex的第一条边,则返回的myEdge确实是一条边;
		              如果没有找到顶点oneVertex的第一条边,则myEdge的成员变量to为-1,
		              根据IsEdge函数判断可知myEdge不是一条边*/
    }

    Edge NextEdge(Edge preEdge)    //返回与边PreEdge有相同关联顶点的下一条边
    {
        Edge myEdge;
        myEdge.from=preEdge.from; /*将边myEdge的始点置为与上一条边preEdge的始点相同*/
        if(preEdge.to<numVertex)
        {
            //如果preEdge.to+1>=numVertex,那么就不存在下一条边了
            for(int i=preEdge.to+1; i<numVertex; i++)
            {
                /*寻找下一个使得//matrix[preEdge.from][i]不为0的i值,那么
                (preEdge.from,i)或者<preEdge.from,i>即为顶点preEdge.from的下一条边*/
                if(matrix[preEdge.from][i]!=0)
                {
                    myEdge.to=i;
                    myEdge.weight=matrix[preEdge.from][i];
                    break;
                }
            }
        }
        return myEdge; /*如果找到了顶点preEdge.from的下一条边,则返回的myEdge确实是一条边;
					   如果没有找到顶点preEdge.from的下一条边,则myEdge的成员变量to为-1,
						根据IsEdge函数判断可知myEdge不是一条边*/
    }

    void setEdge(int from, int to, int weight)   	//为图设定一条边
    {
        if (matrix[from][to] <= 0)
        {
            /*如果matrix[from][to]<=0,则边(from,to) 或者<from,to>
            将是新增的一条边,否则该边已经存在(现在只是对该边进行修改)*/
            numEdge ++;
            Indegree[to] ++;
        }
        matrix[from][to] = weight;
    }

    void delEdge(int from,int to)        //删除图的一条边
    {
        if(matrix[from][to]>0)
        {
            /*如果matrix[from][to]>0,则边(from,to)或者<from,to>确实存在,
            否则该边实际上并不存在(从而不必对图的边数和顶点to的入度进行修改)*/
            numEdge--;
            Indegree[to]--;
        }
        matrix[from][to]=0;
    }
};

// 函数功能:初始化图
void Graphm::IniGraphm(Graphm *Graphm, int A[N][N])
{
    for (int i = 0; i < N; i ++)
    {
        for (int j = 0; j < N; j ++)
        {
            if (A[i][j] > 0)
                Graphm->setEdge(i, j, A[i][j]);
        }
    }
}

//函数功能:深度优先搜索算法实现
void Graphm::DFS(Graph& G, int v)       //深度优先搜索算法实现
{
    G.Mark[v] = VISITED;       //访问顶点v,并标记其标志位
    Visit(G,v);
    //访问V邻接到的未被访问过的顶点,并递归地按照深度优先的方式进行周游
    for(Edge e=G.FirstEdge(v); G.IsEdge(e); e=G.NextEdge(e))
        if(G.Mark[G.ToVertex(e)]== UNVISITED)
            DFS(G, G.ToVertex(e));
}

// 函数功能:广度优先搜索
void Graphm::BFS(Graph& G, int v)   // 广度优先搜索算法的实现
{
    using std::queue;
    queue<int> Q;                   // 初始化广度优先周游要用到的队列
    Visit(G,v);                     // 问顶点v,并标记其标志位
    G.Mark[v] = VISITED;
    Q.push(v);                      // v入队
    while (!Q.empty())              // 如果队列仍然有元素
    {
        int u = Q.front ();         // 队列顶部元素
        Q.pop();                    // 队列顶部元素出队
        // 该顶点邻接到的每一个未访问顶点都入队
        for (Edge e = G.FirstEdge(u); G.IsEdge(e); e = G.NextEdge(e))
            if (G.Mark[G.ToVertex(e)] == UNVISITED)
            {
                Visit(G, G.ToVertex(e));
                G.Mark[G.ToVertex(e)] = VISITED;
                Q.push(G.ToVertex(e));  // 入队
            }
    }
}

// 函数功能:显示顶点
void Graphm::Visit(Graph &G, int v)
{
    cout << 'V' << v <<" ";
}

//[算法7.7] 队列实现的图拓扑排序
void TopsortbyQueue(Graphm& G)         //队列方式实现的拓扑排序
{
    for(int i=0; i<G.VerticesNum(); i++)  //初始化Mark数组
        G.Mark[i]=UNVISITED;
    using std::queue;
    queue<int> Q;                     //初始化队列
    for(int i=0; i<G.VerticesNum(); i++)
        if(G.Indegree[i]==0)
            Q.push(i);                //图中入度为0的顶点入队
    while(!Q.empty())                 //如果队列中还有图的顶点
    {
        int V=Q.front();
        Q.pop();                     //一个顶点出队
        G.Visit(G,V);
        G.Mark[V]=VISITED;
        for(Edge e= G.FirstEdge(V); G.IsEdge(e); e=G.NextEdge(e))
        {
            G.Indegree[G.ToVertex(e)]--;  //所有与之相邻的顶点入度-1
            if(G.Indegree[G.ToVertex(e)]==0)
                Q.push(G.ToVertex(e));   //入度为0的顶点入队
        }
    }
    for(int i=0; i<G.VerticesNum(); i++)
        if(G.Mark[i]==UNVISITED)
        {
            cout<<" There is circle in the graph!";        //图有环
            break;
        }
}

int A[N][N] =
{
    //        V0 V1 V2 V3 V4
    /*V0*/    0, 0, 1, 1, 0,
    /*V1*/    0, 0, 0, 1, 1,
    /*V2*/    1, 0, 0, 1, 1,
    /*V3*/    1, 1, 1, 0, 0,
    /*V4*/    0, 1, 1, 0, 0,
};      //图7.2中G1表示的无向图


int main()
{
    Graphm aGraphm(N);              // 建立图
    aGraphm.IniGraphm(&aGraphm, A); // 初始化图
    cout << "DFS: ";
    aGraphm.DFS(aGraphm, 0);
    cout << endl;

    for (int i = 0; i < aGraphm.VerticesNum(); i ++) //把Mark改回UNVISITED
        aGraphm.Mark[i] = UNVISITED;

    cout << "BFS: ";
    aGraphm.BFS(aGraphm, 0);
    cout << endl;

 //   cout << "Top sort by Queue is : " << endl;
 //   TopsortbyQueue(aGraphm);
 //   cout << endl;

    return 0;
}

    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/xunmengpiaoyun/article/details/17841785
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞