图的链式表示

图的链式表示

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

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


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

#define UNVISITED 0
#define VISITED 1
#define 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为数组指针*/

        for (int i = 0; i < numVertex; i ++)   	/*确定图的顶点的标志位和入度,即所有顶点的标志位初始化为未被访问过,入度初始化为0*/
        {
            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;
};

//*************** Link.h **************//
struct listUnit     //邻接表表目中数据部分的结构定义
{
    int vertex;     //边的终点
    int weight;     //边的权
};

template<class Elem>   //链表元素
class Link
{
public:
    Elem element;      //表目的数据
    Link *next;        //表目指针,指向下一个表目
    Link(const Elem& elemval, Link *nextval = NULL)    //构造函数
    {
        element = elemval;
        next = nextval;
    }
    Link(Link *nextval = NULL)    					   //构造函数
    {
        next = nextval;
    }
};

template<class Elem>   //链表
class LList
{
public:
    Link<Elem>* head;  //head指针并不储存任何实际元素,其存在只是为了操作方便
    LList()             //构造函数
    {
        head = new Link<Elem>();
    }
    void removeall()     //释放边表所有表目占据的空间
    {
        Link<Elem> *fence;
        while(head != NULL)    //逐步释放每个表目占据的空间
        {
            fence = head;
            head = head->next;
            delete fence;
        }
    }
    ~LList()  				//析构函数
    {
        removeall();
    }
};


class Graphl: public Graph
{
private:
    LList<listUnit> *graList;  //graList是保存所有边表的数组
public:
    Graphl(int numVert):Graph(numVert)    //构造函数
    {
        graList = new LList<listUnit>[numVertex]; /*为graList数组申请空间,图有
										  numVertex个顶点,则有numVertex个边表*/
    }

    ~Graphl()                           //析构函数
    {
        delete [] graList;			    //释放空间
    }

    Edge FirstEdge(int oneVertex)       //返回顶点oneVertex的第一条边
    {
        Edge myEdge;                    //边myEdge将作为函数的返回值
        myEdge.from = oneVertex;        //将顶点oneVertex作为边myEdge的始点
        /*graList[oneVertex].head保存的是顶点oneVertex的边表,
        temp->next指向顶点oneVertex的第一条边(如果temp->next
        不为null)*/
        Link<listUnit> *temp = graList[oneVertex].head;
        if(temp->next != NULL)           //如果顶点oneVertex的第一条边确实存在
        {
            myEdge.to = temp->next->element.vertex;
            myEdge.weight = temp->next->element.weight;
        }
        /*如果找到了顶点oneVertex的第一条边,则返回的myEdge确实是一条边;如果没有
        找到顶点oneVertex的第一条边,则myEdge的成员变量to为-1,根据IsEdge函数判
        断可知myEdge不是一条边*/
        return myEdge;
    }

    Edge NextEdge(Edge preEdge)     // 返回与边PreEdge有相同关联顶点的下一条边
    {
        Edge myEdge;			 		// myEdge的初始成员变量to为-1
        myEdge.from = preEdge.from;  		// 将边的始点置为与上一条边的相同
        Link<listUnit> *temp = graList[preEdge.from].head;  // temp指向边表头一个
        while (temp->next != NULL && temp->next->element.vertex <= preEdge.to)
            temp = temp->next; 			// 确定边preEdge的位置
        if (temp->next != NULL)  		// 边preEdge的下一条边存在
        {
            myEdge.to = temp->next->element.vertex;
            myEdge.weight = temp->next->element.weight;
        }
        return myEdge;					// 如果没有找到第一条边,myEdge.to=-1
    }

    void setEdge(int from,int to,int weight)     //为图设定一条边
    {
        Link<listUnit> *temp = graList[from].head;  /*graList[from].head保存的是顶点from的
													边表,temp->next指向顶点from的第一条边
													(如果temp->next不为null)*/
        while(temp->next != NULL && temp->next->element.vertex < to)
            temp = temp->next;   /*确定边(from,to)或<from,to>在边表中的位置,如果不存在,
									则边(from,to)或<from,to>为新加的一条边*/
        if(temp->next == NULL)
        {
            /*边(from,to)或<from,to>在边表中不存在且在边表中其后
            已无其它边,则在边表中加入这条边*/
            temp->next = new Link<listUnit>;
            temp->next->element.vertex = to;
            temp->next->element.weight = weight;
            numEdge++;
            Indegree[to]++;
            return;
        }
        if(temp->next->element.vertex == to)
        {
            /*边(from,to)或<from,to>在边表中已存在,
            故只需要改变边的权值*/
            temp->next->element.weight = weight;
            return;
        }
        if(temp->next->element.vertex>to)
        {
            /*边(from,to)或<from,to>在边表中不存在,但在边表中
            其后存在其它边,则在边表中插入这条边*/
            Link<listUnit> *other = temp->next;
            temp->next = new Link<listUnit>;
            temp->next->element.vertex = to;
            temp->next->element.weight = weight;
            temp->next->next = other;
            numEdge++;
            Indegree[to]++;
            return;
        }
    }

    void delEdge(int from, int to)             //删掉图的一条边
    {
        Link<listUnit> *temp = graList[from].head;  /*graList[from].head保存的是顶点from的边表,temp->next指向顶点from的第一条边(如果temp->next不为null)*/
        while(temp->next != NULL && temp->next->element.vertex<to)
            temp = temp->next;	/*确定边(from,to)或<from,to>在边表中的位置(如果该边存在)*/
        if(temp->next == NULL)
            return;        //边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
        if(temp->next->element.vertex>to)
            return;        //边(from,to)或<from,to>在边表中不存在,则不需要做任何操作
        if(temp->next->element.vertex == to)
        {
            /*边(from,to)或<from,to>在边表中存在且确
            									   定了该边在边表中的位置,则从边表中将其删掉*/
            Link<listUnit> *other = temp->next->next;
            delete temp->next;
            temp->next = other;
            numEdge--;
            Indegree[to]--;
            return;
        }
    }

    void IniGraphl(Graphl *Graphl, int A[N][N]);
    void DFS(Graph& G, int v);
    void BFS(Graph& G, int v);
    void Visit(Graph &G, int v);
};

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


//函数功能:深度优先搜索算法实现
void Graphl::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 Graphl::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 Graphl::Visit(Graph &G, int v)
{
    cout << 'V' << v <<" ";
}

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()
{
    Graphl aGraphl(N);              // 建立图
    aGraphl.IniGraphl(&aGraphl, A); // 初始化图

    cout << "DFS: ";
    aGraphl.DFS(aGraphl, 0);
    cout << endl;

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

    cout << "BFS: ";
    aGraphl.BFS(aGraphl, 0);
    cout << endl;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值