zoukankan      html  css  js  c++  java
  • 图的邻接表表示

    邻接表

    • G[N]为指针数组,对应矩阵每行一个链表,只存非0元素。

    • 邻接表的优点
      - 方便找任一顶点的所有“邻接点”
      - 节约稀疏图的空间
      - 需要N个头指针+ 2E个结点(每个结点至少2个域)
      - 方便计算任一顶点的“度”?
      - 对无向图:是的
      - 对有向图:只能计算“出度”;需要构造“逆邻接表”(存指向自己的边)来方便计算“入度”

    • 邻接表的缺点

       - 不方便检查任意一对顶点间是否存在边
      

    BFS广度优先搜索(Breadth First Search, BFS)

    • 运用队列,将顶点V的每个邻接点进队。(类似于树的层先遍历)

    • 若有N个顶点、E条边,时间复杂度是

      • 用邻接表存储图,有O(N+E)
      • 用邻接矩阵存储图,有O(N^2)

    DFS深度优先搜索索(Depth First Search, DFS)

    • 用递归(类似于树的先序遍历)。

    • ListComponents 图不连通时,列出各连通分量。

    • 若有N个顶点、E条边,时间复杂度是

      • 用邻接表存储图,有O(N+E)
      • 用邻接矩阵存储图,有O(N^2)

    测试代码:

    
    /*!
     * file 图的邻接表表示.cpp
     *
     * author ranjiewen
     * date 2017/04/12 8:57
     *
     * 
     */
    
    #include <iostream> 
    #include <cstdio>
    #include <cstdlib>
    #include <queue>
    
    using namespace std;
    
    /* 图的邻接表表示法 */
    #define  MaxVertexNum 100 /*最大顶点数设为100*/
    #define  INFINITY 65535 /*设为双字节无符号整数的最大值为65535*/
    typedef int Vertex; /*用顶点下标表示顶点,为整型*/
    typedef int WeightType; /*边的权值设为整型*/
    typedef char DataType; /*顶点存储的数据类型设为字符型*/
    
    /*边的定义*/
    typedef struct ENode* PtrToENode;
    struct ENode
    {
    	Vertex V1, V2; //有向边<v1,v2>
    	WeightType Weight;//权重
    };
    typedef PtrToENode Edge;
    
    /*邻接点的定义*/
    typedef struct AdjVNode *PtrToAdjVNode;
    struct AdjVNode
    {
    	Vertex AdjV; //邻接点下标
    	WeightType Weight; //边权重
    	PtrToAdjVNode Next; //指向下一个邻接点的指针
    };
    
    /*顶点表头结点的定义*/
    typedef struct VNode
    {
    	PtrToAdjVNode FirstEdge; //边表头指针
    	DataType Data; //存顶点的数据
    	//注意:很多时候,顶点无数据,此时Data可以不出现
    }AdjList[MaxVertexNum];
    
    /*图结点的定义*/
    typedef struct GNode *PtrToGNode;
    struct GNode
    {
    	int Nv; //顶点树
    	int Ne; //边数
    	AdjList G; //邻接表
    };
    typedef PtrToGNode LGraph;  /* 以邻接表方式存储的图类型 */
    
    LGraph CreateGraph(int VertexNum)
    {
    	/*初始化一个有VertexNum个顶点但没有边的图*/
    	Vertex V, W; /*顶点的下标*/
    	LGraph Graph;
    
    	Graph = (LGraph)malloc(sizeof(struct GNode)); /*建立图*/
    	Graph->Nv = VertexNum;
    	Graph->Ne = 0;
    	//初始化邻接表
    	//注意:这里默认顶点编号从0开始到(Graph->Nv - 1)
    	for (V = 0; V < Graph->Nv;V++)
    	{
    		Graph->G[V].FirstEdge = NULL;
    	}
    	return Graph;
    }
    
    void InsertEdge(LGraph Graph,Edge E)
    {
    	PtrToAdjVNode NewNode;
    
    	//插入边<v1,v2>
    	//为V2建立新的邻接点
    	NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    	NewNode->AdjV = E->V2;
    	NewNode->Weight = E->Weight;
    	//将v2插入v1的表头
    	NewNode->Next = Graph->G[E->V1].FirstEdge;
    	Graph->G[E->V1].FirstEdge = NewNode;
    
    	//若是无向图,还有插入边<v2,v1>
    	//为v1建立新的邻接点
    	NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
    	NewNode->AdjV = E->V1;
    	NewNode->Weight = E->Weight;
    	//将v1插入v2的表头
    	NewNode->Next = Graph->G[E->V2].FirstEdge;
    	Graph->G[E->V2].FirstEdge = NewNode;
    }
    
    LGraph BuildGraph()
    {
    	LGraph Graph;
    	Edge E;
    	Vertex V;
    	int Nv, i;
    
    	scanf("%d", &Nv); /*读入顶点个数*/
    	Graph = CreateGraph(Nv); /* 初始化有Nv个顶点但没有边的图 */
    	
    	scanf("%d", &(Graph->Ne)); /*读入边数*/
    	if (Graph->Ne!=0) //如果有边
     	{
    		E = (Edge)malloc(sizeof(struct ENode)); //建立边结点
    		//读入边,格式为:起点,中点,权重;插入邻接
    		for (i = 0; i < Graph->Ne;i++)
    		{
    			scanf("%d %d %d", &E->V1, &E->V2, &E->Weight);
    			//注意:如果权重不是整型,weight的读入格式要改变
    			InsertEdge(Graph, E);
    		}
    	}
    
    	//如果顶点有数据的话,读入数据
    	for (V = 0; V < Graph->Nv;V++)
    	{
    		//scanf("%c", &(Graph->G[V].Data));
    	}
    	return Graph;
    }
    
    /* 邻接矩阵存储的图 - BFS */
    bool Visited[MaxVertexNum] = { false };
    
    void InitVisited()
    {
    	for (int i = 0; i < MaxVertexNum;i++)
    	{
    		Visited[i] = false;
    	}
    }
    
    void Visit(Vertex v)
    {
    	printf("%d ", v);
    }
    
    //连通下的DFS和BFS
    void DFS(LGraph Graph, Vertex V, void(*Visit)(Vertex))
    {
    	/*以V为出发点对邻接表存储的图Graph进行DFS搜索*/
    	PtrToAdjVNode W;
    	Visit(V); //访问第V个顶点
    	Visited[V] = true;
    	
    	for (W = Graph->G[V].FirstEdge; W;W=W->Next) //对V的每个邻接点访问
    	{
    		if (!Visited[W->AdjV])
    		{
    			DFS(Graph, W->AdjV, Visit);
    		}
    	}
    }
    
    //非连通下的遍历
    Vertex listDFS(LGraph Graph, void(*Visit)(Vertex))
    {
    	Vertex i;
    	for (i = 0; i < Graph->Nv; i++) {
    		if (Visited[i] == false)
    			break;
    	}
    	if (i == Graph->Nv)
    		return 0;
    	DFS(Graph, i, Visit);
    	printf("
    ");
    
    	return listDFS(Graph, Visit);
    }
    
    //图不连通时 列出各连通分量 
    void DFSListComponents(LGraph Graph, void(*Visit)(Vertex))
    {
    	for (Vertex i = 0; i < Graph->Nv; i++) {
    		if (Visited[i] == false) {
    			DFS(Graph, i, Visit);
    			printf("
    ");
    		}
    	}
    }
    
    void BFS(LGraph Graph, Vertex S, void(*Visit)(Vertex))
    {
    	/* 以S为出发点对邻接表存储的图Graph进行BFS搜索 */
    	queue<Vertex> Q;
    	Vertex V;
    
    	Visit(S);
    	Visited[S] = true;
    	Q.push(S);
    
    	while (!Q.empty()) {
    		V = Q.front();
    		Q.pop();
    		for (PtrToAdjVNode tempV = Graph->G[V].FirstEdge; tempV;tempV=tempV->Next) /* 对W的每个邻接点tempV->AdjV */
    			/* 若W是V的邻接点并且未访问过 */
    		if (!Visited[tempV->AdjV] )
    		{
    			/* 访问顶点W */
    			Visit(tempV->AdjV);
    			Visited[tempV->AdjV] = true;
    			Q.push(tempV->AdjV);
    		}
    	}
    }
    
    void BFSListComponents(LGraph Graph, void(*Visit)(Vertex))
    {
    	for (Vertex i = 0; i < Graph->Nv; i++) {
    		if (Visited[i] == false) {
    			BFS(Graph, i, Visit);
    			printf("
    ");
    		}
    	}
    }
    
    int main()
    {
    	LGraph graph;
    	graph = BuildGraph();
    	InitVisited();
    	listDFS(graph, &Visit);
    	InitVisited();
    	DFSListComponents(graph, &Visit);
    	InitVisited();
    	//BFS(graph,0,&Visit);
    	BFSListComponents(graph, &Visit);
    	return 0;
    }
    
    

    结果:

    Reference

    数据结构学习笔记05图 (邻接矩阵 邻接表-->BFS DFS、最短路径)

  • 相关阅读:
    设计模式(二十三)—— 模板方法
    设计模式(二十二)—— 策略模式
    设计模式(二十一)—— 状态模式
    设计模式(二十)—— 观察者模式
    设计模式(十九)—— 备忘录模式
    设计模式(十八)—— 中介者模式
    设计模式(十七)—— 迭代器模式
    设计模式(十六)—— 解释器模式
    设计模式(十五)—— 命令模式
    设计模式(十四)—— 职责链模式
  • 原文地址:https://www.cnblogs.com/ranjiewen/p/6698738.html
Copyright © 2011-2022 走看看