精华内容
下载资源
问答
  • 图的一些基本知识:图,邻居,度矩阵,邻接矩阵 https://blog.csdn.net/luzaijiaoxia0618/article/details/104718146/ 关联矩阵,拉普拉斯矩阵 https://blog.csdn.net/luzaijiaoxia0618/article/details/104720948 ...

    图的一些基本知识:图,邻居,度矩阵,邻接矩阵
    https://blog.csdn.net/luzaijiaoxia0618/article/details/104718146/
    关联矩阵,拉普拉斯矩阵
    https://blog.csdn.net/luzaijiaoxia0618/article/details/104720948

    图有节点V和边E,边可以是有向的和无向的两种。两个节点之间通过边形成邻居关系。跟某一节点相关联的边的数量形成该节点的度。
    ——————————————————————
    无向图分析
    在这里插入图片描述
    上图中节点为V(v1,v2,v3,v4,v5).
    节点间边的关系形成邻接矩阵A
    V1的邻居关系:v1v1, v1v2, v1v3, v1v4, v1v5
    V2的邻居关系:v2v1, v2v2, v2v3, v2v4, v2v5
    V3的邻居关系:v3v1, v3v2, v3v3, v3v4, v3v5
    V4的邻居关系:v4v1, v4v2, v4v3, v4v4, v4v5
    V5的邻居关系:v5v1, v5v2, v5v3, v5v4, v5v5

    上图节点之间关系没有方向,可以双向表示,邻接矩阵的元素表示如下
    0,1,0,0,0
    1,0,1,0,1
    0,1,0,1,1
    0,0,1,0,1
    0,1,1,1,0
    和每个节点相关联的边的数量叫做度,在矩阵中放在对角位置上。邻接矩阵每一行有几个1,就表示该节点上的度为几。度矩阵D的元素可以表示如下
    1,0,0,0,0,
    0,3,0,0,0,
    0,0,3,0,0
    0,0,0,2,0
    0,0,0,0,3

    拉普拉斯矩阵 = 度矩阵 - 邻接矩阵,表示如下:
    1, -1, 0, 0, 0
    -1, 3,-1, 0,-1
    0, -1, 3,-1,-1
    1, 1,-1, 2,-1
    1, -1,-1,-1, 3
    拉普拉斯矩阵每一行的和均为0
    拉普拉斯矩阵是半正定矩阵;
    特征值中0出现的次数就是图连通区域的个数;
    最小特征值是0,对应的特征向量为全1列向量,因为拉普拉斯矩阵每一行的和均为0
    (待解)
    ——————————————————————
    有向图分析

    在这里插入图片描述
    上图中节点为V(v0,v1,v2,v3,v4,v5).
    节点间边的关系形成邻接矩阵A
    V0的邻居关系:v0v0, v0v1, v0v2, v0v3, v0v4
    V1的邻居关系:v1v0, v1v1, v1v2, v1v3, v1v4
    V2的邻居关系:v2v0, v2v1, v2v2, v2v3, v2v4
    V3的邻居关系:v3v0, v3v1, v3v2, v3v3, v3v4
    V4的邻居关系:v4v0, v4v1, v4v2, v4v3, v4v4
    上图节点之间关系有向邻接矩阵的元素表示如下
    0,1,0,0,0
    1,0,0,0,1
    0,1,0,1,0
    1,0,0,0,0
    0,0,0,1,0
    和每个节点相关联的边的数量叫做度,在矩阵中放在对角位置上。邻接矩阵每一行有几个1,就表示该节点上的度为几。度矩阵D的元素可以表示如下
    1,0,0,0,0,
    0,2,0,0,0,
    0,0,2,0,0
    0,0,0,1,0
    0,0,0,0,1


    关联矩阵
    节点N和边数量M形成的矩阵。
    有向图的关联矩阵,两个节点之间有边,一共形成M条边。多某节点而言,若节点在边的起点,则矩阵元素值为1,若节点在边的终点,则矩阵值为-1,若某条边和该节点没有关系,则矩阵元素为0.
    在这里插入图片描述
    上图中,四个节点V1,V2,V3,V4,三条边e1,e2,e3,其中
    v1是e1,e2的起点,和e3无关联。矩阵元素为(1,1,0)
    v2是e2的终点,和e1、e3无关联。矩阵元素为(0,-1,0)
    v3是e1,e3的终点,和e2无关联。矩阵元素为(-1,0,-1)
    v4是e3的起点,和e1,e2无关联。矩阵元素为(0,0,1)
    四个节点和三条边形成的矩阵如下

    节点/边 e1 e2 e3
    v1 1, 1, 0
    v2 0, -1, 0
    v3 -1, 0, -1,
    v4 0, 0, 1
    可以看出,每一条边和某一个节点是起点关系1,势必和另一个节点是终点关系-1。因此,每一条边作为一个列,每列元素之和为0
    矩阵中任一行可以从其他 n-1 行中导出,即只有 n-1 行是独立的(待解)
    ——————————————————————————
    无向图的关联矩阵
    在这里插入图片描述
    节点/边 e1 e2 e3 e4 e5 e6 e7
    v1 1, 0, 0, 0, 1, 0, 1
    v2 1, 1, 0, 0, 0, 0, 0
    v3 0 , 1, 1, 0, 0, 1, 1
    v4 0, 0, 1, 1, 0, 0, 0
    v5 0, 0, 0, 1, 1, 1, 0
    列元素作为边的表示,有且只有两个1;
    行元素作为节点的表示,元素之和表示该节点的边的数量度;
    某一行所有元素为0,则表示该节点不与其他节点有关联,是孤立点。
    重边所对应的列元素完全相同(待解)
    —————————————————————————

    展开全文
  • 邻接链表存储无向图有向图

    千次阅读 2017-04-08 09:48:44
    邻接矩阵存储很好理解,但是,有时候太浪费空间了,特别是对于顶点数多,但是关联关系少的图。 举个极端的例子。 下图中,5个顶点都是孤立的,然而为了存储边的信息,要分配一个5X5的矩阵。本来一条边都没有,没...
    上一篇文章我们说到用邻接矩阵存储有向图和无向图,这种方法的有点是很直观的知道点与点之间的关系,查找的复杂度是为O(1)。但是这种存储方式同时存在着占用较多存储空间的问题,
    

    邻接矩阵存储很好理解,但是,有时候太浪费空间了,特别是对于顶点数多,但是关联关系少的图。

    举个极端的例子。

    下图中,5个顶点都是孤立的,然而为了存储边的信息,要分配一个5X5的矩阵。本来一条边都没有,没必要用存储空间来存储边,但还要分配额外的空间。

                

    用邻接表则可以避免这种浪费。邻接表用动态表结构存储边,更加灵活:有一个边就分配一个空间去存储,没有就不分配。

    我们仍然用邻接矩阵中那个图的例子来说明邻接表的构建思想。

    邻接表只需要一个数组,但是这个数组有点复杂,需要解剖一下。如下图。

     

     

     可以发现,用邻接表存储时,图中的每一个节点 不仅要存储本顶点的数据data,还要存储一个表,这个表存储了此顶点的所有临接点的索引。2点确定一线,那么就能存储此节点相关的所有的边了。

    下面我们用到C++库中的vector来实现indexlist。

    代码如下:

    #include<stdio.h>
    #include<vector>
    
    #define MAX_VERTEX 4
    using std::vector;        //使用C++标准库中的vector来作为list,它实质就是一个顺序表 
    
    
    typedef char DataType;
    
    typedef struct node
    {
        DataType data;            //顶点数据 
        vector<int> indexList;    //存储顶点邻接点索引的 表 
    
    }Node;
    
    
    typedef Node* UListGraph;
    
    
    /********************************/
    void UListGraph_init(UListGraph*pGraph);
    void UListGraph_create(UListGraph graph);
    void UListGraph_show(UListGraph graph);
    void UListGraph_destroy(UListGraph*pGraph);
    
    int main(void)
    {
    
        UListGraph g;
    
        UListGraph_init(&g);
        UListGraph_create(g);
        UListGraph_show(g);
    
        UListGraph_destroy(&g);
    
    
    
        return 0;
    }
    
    
    void UListGraph_init(UListGraph*pGraph)
    {
    
        (*pGraph) = new Node[MAX_VERTEX];
    
    
    }
    
    
    void UListGraph_create(UListGraph  graph)
    {
    
        
        
        for (int i = 0; i < MAX_VERTEX; ++i)  //填充顶点数组
        {
            printf("输入第%d个顶点值\n",i+1);
            
            scanf(" %c",  &(graph[i].data)); 
    
        }
    
        for(int i=0;i<MAX_VERTEX;++i)
            for(int j=i+1;j<MAX_VERTEX;++j)
            {
                printf("如果元素%c和%c之间有边,请输入1,否则输入0",graph[i].data,graph[j].data);
    
                int opt;
                scanf("%d",&opt);
    
                if(opt==1)
                {
                    graph[i].indexList.push_back(j);
                    graph[j].indexList.push_back(i);
                }
    
    
            }
    
    
    
    }
    
    
    
    void UListGraph_show(UListGraph graph)
    {
        
        printf("顶点元素如下:\n\n"); 
        for(int i=0;i<MAX_VERTEX;i++)
        {
            printf("%c\t",graph[i].data);
        }
        printf("\n\n");
    
    
    
        for(int i=0;i<MAX_VERTEX;i++)
        {
            printf("元素%c的邻接点 :",graph[i].data);
    
            Node tnode = graph[i];
    
            for(int k=0;k<tnode.indexList.size();++k)
            {
                printf("%c\t",graph[tnode.indexList[k]].data);
            }
    
            putchar('\n');
        }
    
    
    }
    
    
    void UListGraph_destroy(UListGraph*pGraph)
    {
        delete (*pGraph);
        *pGraph = NULL;        
           
    
    }
    2、有向网用邻接链表存储

    邻接表对于无向图来说很适用,但是对于有向图来说就不适用了,因为邻接表中,每一个节点的IndexList只能存储一种状态的弧,出弧或者入弧(逆邻接表),那怎么将一个顶点的出入弧都存储起来呢?

    那就是将邻接表和逆邻接表都用起来,也就是一个节点需要存储:①data,②inArcList,入弧记录表,③outArcList,出弧记录表


    实现代码如下:

    #include<stdio.h>
    #include<vector>
    
    using std::vector;
    
    #define MAX_VERTEX 4 
    
    typedef char DataType;
    
    
    typedef struct arc{ 
    
        int headVertex;         //此条弧的头尾结点的index
        int tailVertex;         //此条弧的头尾结点的index
    
        //WeightType weight;    //此弧的附加信息,比如权重,这里是有向图,不是网,所以不需要weight
    
    }Arc;
    
    typedef struct node{
    
        DataType data;   //顶点数据域
    
        vector<Arc> outArc;     //此顶点的所有 出度 弧 表
        vector<Arc> inArc;      //此顶点的所有 入度 弧 表 
    
    }Node;
    
    
    typedef Node* Graph;
    
    void Graph_init(Graph* pG);
    void Graph_create(Graph g);
    void Graph_show(Graph g);
    void Graph_destroy(Graph*pg);
    
    
    int main(void)
    {
    
    
        Graph g;
    
        Graph_init(&g);
        Graph_create(g);
        Graph_show(g);
    
        return 0;
    }
    
    
    
    void Graph_init(Graph* pG)
    {
    
        (*pG) = new Node[MAX_VERTEX];
        if(*pG == NULL)
        {
            //exit(-1);
        }
    
    }
    
    void Graph_create(Graph g)
    {
    
        int opt;
        
        for (int i = 0; i < MAX_VERTEX; ++i)  //填充顶点数组
        {
            printf("输入第%d个顶点值\n",i+1);
            
            scanf(" %c",  &(g[i].data)); 
    
        }
    
        for(int j=0;j<MAX_VERTEX;++j)
            for(int i=j+1;i<MAX_VERTEX;++i)
            {
    
    
                printf("若元素%c有指向%c的弧,则输入1,否则输入0\t",g[j].data,g[i].data);
               
                scanf("%d",&opt);
    
                if(opt==1)
                {
                    Arc* parc = new Arc;
                    parc->headVertex = i;
                    parc->tailVertex = j;
                    
                    g[j].outArc.push_back(*parc);
                    g[i].inArc.push_back(*parc);
    
                }
    
                
                printf("若元素%c有指向%c的弧,则输入1,否则输入0\t",g[i].data,g[j].data);
               
                scanf("%d",&opt);
    
                if(opt==1)
                {
                    
                    Arc* parc = new Arc;
                    parc->headVertex = j;
                    parc->tailVertex = i;
    
                    g[i].outArc.push_back(*parc);
                    g[j].inArc.push_back(*parc);
                         
    
                }
    
            }
    
    }
    
    void Graph_show(Graph g)
    {
    
    
        for (int j = 0; j <MAX_VERTEX; ++j)
        {
            printf("顶点数据%c\n",g[j].data);
           
            printf("发射:");
    
            
            for(int i=0;i<g[j].outArc.size();++i)
            {
                printf("%c\t",g[g[j].outArc[i].headVertex].data);
            }
    
    
            putchar('\n');
            printf("接收:");
    
            for(int i=0;i<g[j].inArc.size();++i)
            {
                printf("%c\t",g[g[j].inArc[i].tailVertex].data);
            }
    
            printf("\n\n");
    
        }
        
    
    
    }
    
    
    
    void Graph_destroy(Graph*pg)
    {
      delete (*pg);
        *pg = NULL;        
           
    }


    展开全文
  • 在有向图中,与一个节点相关联的边有出边入边之分。相反,边没有方向的图称为无向图。 下面介绍图的两种存储结构 1、邻接矩阵 用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的...

    图的分类

    有/无向图

    如果给图的每条边规定一个方向,那么得到的图称为有向图。在有向图中,与一个节点相关联的边有出边和入边之分。相反,边没有方向的图称为无向图
    下面介绍图的两种存储结构

    1、邻接矩阵

    用一个一维数组存放图中所有顶点数据;用一个二维数组存放顶点间关系(边或弧)的数据,这个二维数组称为邻接矩阵。邻接矩阵又分为有向图邻接矩阵和无向图邻接矩阵

    邻接矩阵的思想图

    代码实现

    	int GetIndex(const V& v)//获取顶点
    	{
    		for (size_t i=0;i<_size;i++)
    		{
    			if(_vertex[i]==v)
    				return i;
    		}
    		throw std::invalid_argument("顶点赋值错误");
    	}
    	void AddEdge(const V& src,const V& dst,const W& w)//增加矩阵中的点
    	{
    		size_t srcIndex=GetIndex(src);
    		size_t dstIndex=GetIndex(dst);
    		_matrix[srcIndex][dstIndex]=w;
    		if(_isDirection==false)
    			_matrix[dstIndex][srcIndex]=w;
    	}

    2、邻接表

    图的邻接矩阵存储方法跟树的孩子链表示法相类似,是一种顺序分配和链式分配相结合的存储结构。如这个表头结点所对应的顶点存在相邻顶点,则把相邻顶点依次存放于表头结点所指向的单向链表中。

    邻接表的思想图


    邻接表的代码实现

    int GetIndex(const V& v)
    	{
    		for (int i=0;i<_vertex.size();i++)
    		{
    			if(_vertex[i]==v)
    				return i;
    		}
    		throw std::invalid_argument("顶点赋值错误");
    	}
    	void _AddEdge(size_t src,size_t dst,const W& w)
    	{
    		// _table[src][dst]._w=w;
    
    		Node* cur=new Node(src,dst,w);
    		cur->Next=_table[src];
    		_table[src]=cur;
    
    	}
    	void AddEdge(const V& src,const V& dst,const W& w)
    	{
    		int srcIndex=GetIndex(src);
    		int dstIndex=GetIndex(dst);
    		if (_isDirection)
    		{
    			_AddEdge(srcIndex,dstIndex,w);
    		}
    		else
    		{
    			_AddEdge(srcIndex,dstIndex,w);
    			_AddEdge(dstIndex,srcIndex,w);
    		}
    	}

    邻接表的深度优先遍历,类似于二叉树的前序遍历

    一个节点知道遍历到无路可走才遍历旁边的节点


    代码实现,这里用vector实现

    void DFS(const V& v)
    	{
    		vector<bool> visted(_vertex.size(),false);
    		cout<<v;
    		_DFS(GetIndex(v),visted);
    		for(size_t i=0;i<_vertex.size();i++)
    		{
    			if(visted[i]==false)
    			{
    				cout<<_vertex[i];
    				visted[i]=true;
    				_DFS(i,visted);
    			}
    		}
    		cout<<"NULL"<<endl;
    	}
    	void _DFS(size_t src,vector<bool>& visted)
    	{
    		
    		visted[src]=true;
    		Node* cur=_table[src];
    		
            cout<<"["<<src<<"]->";
    		while (cur)
    		{
    			
    			if(visted[cur->_dst]==false)
    			{
    				cout<<_vertex[cur->_dst];
    				visted[cur->_dst]=true;
    				_DFS(cur->_dst,visted);
    			}
    			cur=cur->Next;
    		}
    
    	}

    邻接表的广度优先遍历

    一个节点把它周围的节点全部都遍历完,才会进行前进遍历


    代码实现,这里用队列实现,队列有先进先出的特点,符合此算法

    void _BFS(size_t src,vector<bool>& visted)
    	{
    		visted[src]=true;
    		cout<<"["<<src<<"]->";
    		queue<size_t> q;
    		q.push(src);
    		
    		while (!q.empty())
    		{
    			 src=q.front();
    			 q.pop();
    			 Node* cur=_table[src];
    
    			 while (cur)
    			 {
    				 if(visted[cur->_dst]==false)
    				 {
    				cout<<_vertex[cur->_dst]<<"["<<cur->_dst<<"]"<<"-> ";
    				 visted[cur->_dst]=true;
    				 q.push(cur->_dst);
    				 }
    				 cur=cur->Next;
    				 
    			 }
    
    		}
    		cout<<endl;
    	}
    	void BFS(const V& v)
    	{
    		vector<bool> visted(_vertex.size(),false);
    		cout<<v;
    		_BFS(GetIndex(v),visted);
    	}

    附全部代码及其测试
    临街矩阵

    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;
    template<class V,class W>
    class GraphMatrix
    {
    public:
    	GraphMatrix(V* vertex,size_t size,bool isDirection=false ,const int invalid=0 )
    		:_vertex(new V[size])
    		,_size(size)
    		,_isDirection(isDirection)
    	{
    		_matrix=new W*[size];
    		for(size_t i=0;i<size;i++)
    		{
    			_vertex[i]=vertex[i];
    			_matrix[i]=new W[size];
    			for (size_t j=0;j<size;j++)
    			{
    				_matrix[i][j]=invalid;
    			}
    		}
    
    	}
    	~GraphMatrix()
    	{
    		delete[] _vertex;
    		delete[] _matrix;
    		_size=0;
    	}
    	int GetIndex(const V& v)//获取顶点
    	{
    		for (size_t i=0;i<_size;i++)
    		{
    			if(_vertex[i]==v)
    				return i;
    		}
    		throw std::invalid_argument("顶点赋值错误");
    	}
    	void AddEdge(const V& src,const V& dst,const W& w)//增加矩阵中的点
    	{
    		size_t srcIndex=GetIndex(src);
    		size_t dstIndex=GetIndex(dst);
    		_matrix[srcIndex][dstIndex]=w;
    		if(_isDirection==false)
    			_matrix[dstIndex][srcIndex]=w;
    	}
    	void PrintMaxtix()
    	{
    		for(size_t i=0;i<_size;i++)
    		{
    			for(size_t j=0;j<_size;j++)
    			{
    				cout<<_matrix[i][j]<<"     ";
    			}
    			cout<<endl;
    		}
    	}
    protected:
    	V* _vertex;
    	W** _matrix;
    	size_t _size;
    	bool _isDirection;
    };
    void TestGraphMatrix()
    {
    	string v[4]={"西安","宝鸡","咸阳","延安"};
    	GraphMatrix<string,size_t> gm(v,4);//无向图
    	cout<<"无向图邻接矩阵:"<<endl;
    	gm.AddEdge("西安","咸阳",7);
    	gm.AddEdge("西安","宝鸡",200);
    	gm.AddEdge("西安","延安",500);
    	gm.AddEdge("宝鸡","咸阳",100);
    	gm.AddEdge("宝鸡","延安",200);
    	gm.AddEdge("咸阳","延安",100);
    	gm.PrintMaxtix();
    	GraphMatrix<string,size_t> gm1(v,4,true);//有向图
    	cout<<"有向图邻接矩阵:"<<endl;
    	gm1.AddEdge("西安","咸阳",7);
    	gm1.AddEdge("西安","宝鸡",200);
    	gm1.AddEdge("西安","延安",500);
    	gm1.AddEdge("宝鸡","咸阳",100);
    	gm1.AddEdge("宝鸡","延安",200);
    	gm1.AddEdge("咸阳","延安",100);
    	gm1.PrintMaxtix();
    }
    
    邻接表及其遍历

    #include <iostream>
    #include <string>
    #include <vector>
    #include <queue>
    using namespace std;
    template<class V,class W>
    class GraphLink
    {
    	struct Node 
    	{
    		W _w;
    		size_t _src;
    		size_t _dst;
    		Node* Next;
    		Node(int src=0,int dst=0,const W& w=W())
    			:_src(src)
    			,_dst(dst)
    			,_w(w)
    			,Next(NULL)
    		{}
    	};
    public:
    	GraphLink(const V* vertex,int size,bool isDirection=false)
    		:_isDirection(isDirection)
    	{
    		_vertex.resize(size);
    		_table.resize(size);
    		
    		for(size_t i=0;i<size;i++)
    		{
    			_vertex[i]=vertex[i];
    		}
    
    	}
    	int GetIndex(const V& v)
    	{
    		for (int i=0;i<_vertex.size();i++)
    		{
    			if(_vertex[i]==v)
    				return i;
    		}
    		throw std::invalid_argument("顶点赋值错误");
    	}
    	void _AddEdge(size_t src,size_t dst,const W& w)
    	{
    		// _table[src][dst]._w=w;
    
    		Node* cur=new Node(src,dst,w);
    		cur->Next=_table[src];
    		_table[src]=cur;
    
    	}
    	void AddEdge(const V& src,const V& dst,const W& w)
    	{
    		int srcIndex=GetIndex(src);
    		int dstIndex=GetIndex(dst);
    		if (_isDirection)
    		{
    			_AddEdge(srcIndex,dstIndex,w);
    		}
    		else
    		{
    			_AddEdge(srcIndex,dstIndex,w);
    			_AddEdge(dstIndex,srcIndex,w);
    		}
    	}
    	void DFS(const V& v)
    	{
    		vector<bool> visted(_vertex.size(),false);
    		cout<<v;
    		_DFS(GetIndex(v),visted);
    		for(size_t i=0;i<_vertex.size();i++)
    		{
    			if(visted[i]==false)
    			{
    				cout<<_vertex[i];
    				visted[i]=true;
    				_DFS(i,visted);
    			}
    		}
    		cout<<"NULL"<<endl;
    	}
    	void _DFS(size_t src,vector<bool>& visted)
    	{
    		
    		visted[src]=true;
    		Node* cur=_table[src];
    		
            cout<<"["<<src<<"]->";
    		while (cur)
    		{
    			
    			if(visted[cur->_dst]==false)
    			{
    				cout<<_vertex[cur->_dst];
    				visted[cur->_dst]=true;
    				_DFS(cur->_dst,visted);
    			}
    			cur=cur->Next;
    		}
    
    	}
    	void _BFS(size_t src,vector<bool>& visted)
    	{
    		visted[src]=true;
    		cout<<"["<<src<<"]->";
    		queue<size_t> q;
    		q.push(src);
    		
    		while (!q.empty())
    		{
    			 src=q.front();
    			 q.pop();
    			 Node* cur=_table[src];
    
    			 while (cur)
    			 {
    				 if(visted[cur->_dst]==false)
    				 {
    				cout<<_vertex[cur->_dst]<<"["<<cur->_dst<<"]"<<"-> ";
    				 visted[cur->_dst]=true;
    				 q.push(cur->_dst);
    				 }
    				 cur=cur->Next;
    				 
    			 }
    
    		}
    		cout<<endl;
    	}
    	void BFS(const V& v)
    	{
    		vector<bool> visted(_vertex.size(),false);
    		cout<<v;
    		_BFS(GetIndex(v),visted);
    	}
    	void PrintLink()
    	{
    		for (size_t i=0;i<_vertex.size();++i)
    		{
    	     cout<<_vertex[i]<<"["<<i<<"]->";
    		  Node* cur=_table[i];
    		  while (cur)
    		  {
    			  cout<<_vertex[cur->_dst]<<" ["<<cur->_dst<<"]"<<cur->_w<<"->";
    			  cur=cur->Next;
    		  }
    		  cout<<"NULL"<<endl;
    		}
    
    	}
    protected:
    	vector<V> _vertex;
    	vector<Node*> _table;
    	bool _isDirection;
    };
    void TestGraphLink()
    {
    	string v[4]={"西安","宝鸡","咸阳","延安"};
    	GraphLink<string,size_t> gm(v,4);//无向图邻接表
    	cout<<"无向图邻接表:"<<endl;
    	gm.AddEdge("西安","咸阳",7);
    	gm.AddEdge("西安","宝鸡",200);
    	gm.AddEdge("西安","延安",500);
    	gm.AddEdge("宝鸡","咸阳",100);
    	gm.AddEdge("宝鸡","延安",200);
    	gm.AddEdge("咸阳","延安",100);
    	gm.PrintLink();
    	cout<<"无向图DFS遍历:"<<endl;//深度优先遍历
    	gm.DFS("西安");
    	gm.DFS("宝鸡");
    	gm.DFS("咸阳");
    	gm.DFS("延安");
    	cout<<"无向图BFS遍历:"<<endl;//广度优先遍历
    	gm.BFS("西安");
    	gm.BFS("宝鸡");
    	gm.BFS("咸阳");
    	gm.BFS("延安");
    	GraphLink<string,size_t> gm1(v,4,true);//有向图邻接表
    	cout<<"有向图邻接表:"<<endl;
    	gm1.AddEdge("西安","咸阳",7);
    	gm1.AddEdge("西安","宝鸡",200);
    	gm1.AddEdge("西安","延安",500);
    	gm1.AddEdge("宝鸡","咸阳",100);
    	gm1.AddEdge("宝鸡","延安",200);
    	gm1.AddEdge("咸阳","延安",100);
    	gm1.PrintLink();
    	cout<<"有向图DFS遍历:"<<endl;//深度优先遍历
    	gm1.DFS("西安");
    	gm1.DFS("宝鸡");
    	gm1.DFS("咸阳");
    	gm1.DFS("延安");
    	cout<<"有向图BFS遍历:"<<endl;//广度优先遍历
    	gm1.BFS("西安");
    	gm1.BFS("宝鸡");
    	gm1.BFS("咸阳");
    	gm1.BFS("延安");
    }

    测试代码

    #include "Graph.h"
    #include "GraphLink.h"
    #include<stdlib.h>
    int main()
    {
    	TestGraphMatrix();
    	TestGraphLink();
    	system("pause");
    	return 0;
    }
    测试结果





    展开全文
  • 2.将图进行变形,根据顶点和边的关系进行层次划分,使用队列来进行遍历 3.广度优先遍历的关键点是使用一个队列来把当前结点的所有下一级关联点存进去,依次进行 邻接矩阵的广度优先遍历: BFS(G) for i=0;i<G-...
    1.图的深度优先遍历类似前序遍历,图的广度优先类似树的层序遍历
    2.将图进行变形,根据顶点和边的关系进行层次划分,使用队列来进行遍历
    3.广度优先遍历的关键点是使用一个队列来把当前结点的所有下一级关联点存进去,依次进行
    
    邻接矩阵的广度优先遍历:
    BFS(G)
        for i=0;i<G->numVertexes;i++
            visited[i]=false;//检测是否访问过
        for i=0;i<G.numVertexes;i++//遍历顶点
            if visited[i]==true break;//访问过的断掉
            visited[i]=true //当前顶点访问
            InQueue(i)      //当前顶点入队列
            while(!QueueEmpty()) //当前队列不为空
                i=OutQueue() //队列元素出队列
                for j=0;j<G->numVertexes;j++ //遍历顶点
                    if G->arc[i][j]==1 && !visited[j] //当前顶点与其他顶点存在关系并且未被访问
                        visited[j]=true //标记此顶点
                        InQueue(j)      //此顶点入队列,会排在后面等前面一层的全遍历完才会遍历这个
    
    深度优先遍历DFS:
    DFSTravserse G
        for i=0;i<G.xNum;i++
            if !visted[i]
                DFS(G,i)
    DFS G,i
        visted[i]=true
        print G.vexs[i]
        if G.arc[i][j]==1 && !visited[j]
            DFS(G,j)
    
    
    图的物理存储的实现:
    邻接矩阵 邻接链表 十字链表 邻接多重表
    有向图的存储方法:十字链表
    无向图存储的优化:邻接多重表
    
    图的遍历:
    1.从图中某一顶点出发访遍图中其余顶点,且使每个顶点仅被访问一次
    2.需要给访问过的顶点打上标记,设置个数组visited[n],访问过后设置为1
    3.遍历次序:深度优先遍历和广度优先遍历
    深度优先遍历DFS:
    1.类似走迷宫右手定则,走一个做标记,一直往右走,直到重复了,就退回上一个顶点
    2.从某个顶点v出发访问和v有路径相通的顶点,递归调用
    <?php
    class Graph{
            public $vertexs;
            public $arc;
            public $num=5;
    }
    
    $G=new Graph();
    for($i=0;$i<$G->num;$i++){
            $G->vertexs[$i]="V{$i}";
    }
    
    $G->arc[1][0]=9;
    $G->arc[1][2]=3;
    $G->arc[2][0]=2;
    $G->arc[2][3]=5;
    $G->arc[3][4]=1;
    $G->arc[0][4]=6;
    
    //广度优先遍历
    function BFS($G){
            $res=array();
            $queue=array();
            for($i=0;$i<$G->num;$i++){
                    $visited[$i]=false;
            }   
            for($i=0;$i<$G->num;$i++){
                    if($visited[$i]){
                            break;
                    }   
                    $visited[$i]=true;
                    $res[]=$G->vertexs[$i];
                    array_push($queue,$i);
                    while(!empty($queue)){
                            $v=array_pop($queue);
                            for($j=0;$j<$G->num;$j++){
                                    if($G->arc[$v][$j]>0 && !$visited[$j]){
                                            $visited[$j]=true;
                                            $res[]=$G->vertexs[$j];
                                            array_push($queue,$j);
                                    }   
                            }   
                    }   
            }   
            return $res;
    }
    //深度优先遍历
    function DFS($G,$i){
            static $res;
            static $visited;
            if(!$visited[$i]){
                    $visited[$i]=true;
                    $res[]=$G->vertexs[$i];
            }
                    for($j=0;$j<$G->num;$j++){
                            if($G->arc[$i][$j]>0 && !$visited[$j]){
                                    $visited[$j]=true;
                                    $res[]=$G->vertexs[$j];
                                    DFS($G,$j);
                            }
                    }
            return $res;
    }
    
    $b=BFS($G);
    $d=DFS($G,1);
    var_dump($b);
    var_dump($d);

     

    array(5) {
      [0]=>
      string(2) "V0"
      [1]=>
      string(2) "V4"
      [2]=>
      string(2) "V1"
      [3]=>
      string(2) "V2"
      [4]=>
      string(2) "V3"
    }
    array(5) {
      [0]=>
      string(2) "V1"
      [1]=>
      string(2) "V0"
      [2]=>
      string(2) "V4"
      [3]=>
      string(2) "V2"
      [4]=>
      string(2) "V3"
    }

     

    展开全文
  • 拓扑关系

    2020-04-19 19:12:09
    拓扑关系是指满足拓扑几何学原理的各空间数据间的相互关系。即用结点、弧段多边形所表示的实体之间的邻接、关联、包含连通关系...如:点与点的邻接关系、点与面的包含关系、线与面的相离关系、面与面的重合关系等。
  • 如:点与点的邻接关系、点与面的包含关系、线与面的相离关系、面与面的重合关系等。 2、拓扑关系的类型 邻接、关联、包含、连通。 3、意义 拓扑关系验证是查找空间数据中错误空间关系的必要手段,且对数据处理空间...
  • 1、图:用来表示“多对多”的关系 图的要素:顶点、边 一组顶点:通常用V来表示顶点的集合 一组边:通常用E来表示边的集合 ...称为从顶点x到顶点y的一条有向边,而(x,y)称为顶点x顶点y相关联的一条边。...
  • 图 多对多关系 是一种网状数据结构,图是由非空的顶点集合一个描述顶点之间关系的集合...P(u, v) 表示uv之间有特定的关联属性 若<u,v>∈E,则<u,v>表示从顶点u的一条弧,并称u为弧尾或起始点,称
  • 1)关联矩阵(表示了图的结构,即图中各结点的后件关系):表示各个结点的前件与后件关系,矩阵R(i,j)=1,表示结点i是结点j的前件,矩阵R(i,j)=0,表示结点i不是结点j的前件,无向图的关联矩阵是对称矩阵,且对...
  • 一般系统中都会有需求在数据库中存储树形结构。如果系统中用的是非关系型数据库如mongodb,那么没什么好说的。如果系统中用的是关系型...每个节点有id字段,一个关联父节点的字段pid。 对于常用的操作,添加一个叶子
  • focusNodeAdjacency:true,//当鼠标移动到节点上,突出显示节点以及节点的边和邻接节点 draggable: true,//指示节点是否可以拖动 roam: true, data: getNodes(), links: [], label: { normal: { show:...
  • 作者:xinxin   ...如:点与点的邻接关系、点与面的包含关系、线与面的相离关系、面与面的重合关系等。当我们在项目中使用含有拓扑关系的数据时,如果这个数据存在拓扑错误,比如线内有自...
  • 它采用两个数组来表示图:一个是用于存储所有顶点信息的一维数组,另一个是用于存储图中顶点之间关联关系的二维数组,这个关联关系数组也被称为邻接矩阵。 假设图G=(V , E)有n个顶点,即V={v0,v1...
  • 对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。 在图的基本算法中,最初需要接触的就是图的...
  • 图的BFSDFS算法

    2018-12-26 11:25:54
    对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。 在图的基本算法中,最初需要接触的就是图的...
  • 图的遍历:BFSDFS

    2018-09-12 19:56:24
    对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。 在图的基本算法中,最初需要接触的就是图的...
  • 图的基本算法(BFSDFS) ...对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图...
  • 数据结构 第六章 图-1

    2020-02-01 15:13:01
    邻接关系:彼此之间存在关系且邻接的,顶点与顶点之间的关系。对于任何边e=(u,v),称作顶点uv彼此邻接adjacent,互为邻居。而他们都与边e彼此关联incident。 关联关系:定点与相关的边的关系。 入度 (...
  • 对象由顶点(V)表示,而对象之间的关系或者关联则通过图的边(E)来表示。 图可以分为有向图无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。 在图的基本算法中,最初需要接触的就是图的...

空空如也

空空如也

1 2 3 4 5 6
收藏数 107
精华内容 42
关键字:

关联关系和邻接关系