图的概念


1. 图
  图是一种非线性数据结构,由顶点的集合及顶点间的关系(边)组成;G=(V,E),其中顶点集合V是有穷非空集合;E={(x,y) | x,y属于V}或E={<x,y> | x,y属于V}是顶点间关系的有穷集合,也叫做边的集合;其中第一种圆括号表示x到y的一条双向通路,即:(x,y)(y,x)是一条边,这种边与顶点构成的图叫做无向图;第二种尖括号表示x到y的一条单向通路,也就是说:<x,y>是从x到y的一条边与<y,x>并不是同一个,这种边与顶点构成的图叫做有向图。
  
2. 完全图
  在无向图中,如果任意两条顶点之间有且仅有一条边,即:有n个顶点,就有n*(n-1)/2条边,则称此图为无向完全图;
  在有向图中,如果任意两条顶点之间有且仅有方向相反的边,那么称此图为有向完全图;若有n条边,则有n*(n-1)条边。
  
3. 邻接顶点
  在无向图中,如果(x,y)是图中的一条边,则称x与y互为邻接顶点,边(x,y)依附于顶点x和y;
  在有向图中,如果<x,y>是图中的一条边,则称顶点x邻接到y,y邻接自x,边(x,y)与顶点x,y相关联。
  
4. 顶点的度:顶点的度是与顶点相关的边的个数。在无向图中,我们把以顶点v为终点的边的条数称为入度,把以顶点v为起始点的边的个数称为出度,有向图顶点的度等于入度与出度之和。

5. 权:边附带的数据信息
例如:

6. 路径与路径长度
  从顶点x出发有一组边可以使其到达顶点y,则称这一组边为顶点x到顶点y的路径。
  对于不带权的图:路径长度是该路径上边的条数;对于带权的图,路径长度为路径上各个边的权值之和。
  
7. 子图:设图G={V,E}和图G1={V1,E1},若V1属于V且E1属于E,则称G1是G的子图。

8. 连通图与强连通图
  在无向图中,任意两个顶点之间都有一条路径,那么称此图为连通图;n个顶点的连通图至少有n-1条边。
  在有向图中,任意两个顶点v1,v2之间都存在一条从v1到v2,从v2到v1的路径,那么称此图为强连通图。
  
9. 生成树:一个连通图的最小连通子图叫做该图的生成树。生成树不唯一。

图的存储

邻接矩阵

  我们将用一个数组表示顶点的集合,利用矩阵表示顶点间的关系
例如:

可以看到如果是无向图,我们得到的邻接矩阵是对称的。
代码如下:

#include <iostream>
#include <vector>
#include <assert.h>
using namespace std;
template <class V,class W,bool IsDirect = false>//false表示为无向图
class Graph
{
public:
     Graph(const V* arr,size_t size)
          : _v(arr,arr + size)
     {
          _edges.resize(size);
          for (size_t i = 0; i < size; i++)
               _edges[i].resize(size);
     }
     int GetIndex(const V& v)
     {
          for (size_t i = 0; i < _v.size(); i++)
          {
               if (_v[i] == v)
                    return i;
          }
          assert(false);
          return -1;
     }
     void AddEdges(const V v1,const V v2,const W& weight)//存储边
     {
          size_t index1 = GetIndex(v1);
          size_t index2 = GetIndex(v2);
          _edges[index1][index2] = weight;
          if (!IsDirect)//无向图需要两次,有向图只需要一次 false为无向图
               _edges[index2][index1] = weight;
     }
     void Print()//打印矩阵
     {
          for (size_t i = 0; i < _v.size(); i++)
          {
               printf("%c ",_v[i]);
               for (size_t j = 0; j < _v.size(); j++)
               {
                    printf("%2d ",_edges[i][j]);
               }
               cout << endl;
          }
     }
     size_t Dev(const V& v)//计算顶点的度
     {
          size_t index = GetIndex(v);
          size_t count = 0;//false表示无向图,无向图度的计算是遍历一行,
                           //true是有向图,有向图度的计算:出度+入度
          for (size_t i = 0; i < _v.size(); i++)
          {
               if (_edges[index][i] > 0)
                    count++;
               if (IsDirect && _edges[i][index] > 0)
                    count++;
          }
          return count;
     }
private:
     vector<V> _v;
     vector<vector<W>> _edges;
};

  对于带权的图,我们可以将1改成权值;如果没有某条边,可以把0改成无穷大;对角线上自己到自己的边,仍然存为0。
  利用邻接矩阵存储图结构,有可能出现顶点很多,边却很少的情况,此时就会有大量的0元素,造成空间浪费。

邻接表

  利用数组表示顶点的集合,利用好链表表示边的关系。把顶点在数组中的下标存放到链表的数据域中。
  对于无向图,每条边在邻接表中出现两次;要计算某个结点的,只需要将vi对应的链表遍历一遍即可。例如,下图中,A的度为2,D的度为1
  对于有向图,每条边在邻接表中只出现一次;与顶点vi对给你个的邻接表,其结点的个数为出度;检测其他所有顶点对应的边链表,结点中的dst为i的个数是入度。例如:A的出度为1,入度为1,所以A的度为2。
  对于有向图,我们可以选择出度表或者入度表,出度表,简单来说,就是箭头指向的顶点对应的下标存储在链表结点中;入度表,箭头的根部对应的顶点的下标。如下图所示:
例如:

下面看代码:

#include <vector>
#include <iostream>
using namespace std;
template <class W>
struct Node
{
     Node(const W& weight,size_t src,size_t dst)
     : _weight(weight),_src(src),_dst(dst),_pNext(NULL)
     {}
     W _weight;
     size_t _src;
     size_t _dst;
     Node* _pNext;
};
template <class V,bool IsDirect = false>//无向图为false;有向图为true
class Graph
{
     typedef Node<W> Node;
     typedef Node* pNode;
public:
     Graph(const V* arr,arr + size)
     {
          _linkEdges.resize(size);
     }
     int GetIndex(const V& v)
     {
          for (size_t i = 0; i < _v.size(); i++)
          {
               if (_v[i] == v)
                    return i;
          }
          return -1;
     }
     void AddEdges(const V& v1,const V& v2,const W& weight)
     {
          size_t srcIndex = GetIndex(v1);
          size_t dstIndex = GetIndex(v2);
          _Add(srcIndex,dstIndex,weight);
          if (!IsDirect)//false 无向图
               _Add(dstIndex,srcIndex,weight);
     }
     size_t Dev(const V& v)
     {
          size_t count = 0;
          size_t index = GetIndex(v);
          pNode pCur = _linkEdges[index];
          while (pCur)//如果是无向图,直接计算度,如果是有向图先计算出度
          {
               count++;
               pCur = pCur->_pNext;
          }
          if (IsDirect)
          {
               for (size_t i = 0; i < _v.size(); i++)//计算有向图的入度
               {
                    if (i != index)
                    {
                         pCur = _linkEdges[i];
                         while (pCur)
                         {
                              if (pCur->_dst == index)
                                   count++;
                              pCur = pCur->_pNext;
                         }
                    }
               }
          }
          return count;
     }
private:
     void _Add(const size_t src,const size_t dst,const W& weight)
     {
          pNode pNew = new Node(weight,src,dst);
          pNode pCur = _linkEdges[src];

          pNew->_pNext = _linkEdges[src];
          _linkEdges[src] = pNew;
     }
private:
     vector<V> _v;
     vector<pNode> _linkEdges;
};

【数据结构】图的更多相关文章

  1. swift篇第一期:简单的数据结构

    首先我们可以去使用Playground来编码,并且会实时的显示对应的编码信息,这样我们就不用每次都去运行程序来显示输出的东西了哦,也方便了我们对某些语句的验证,这个是比较赞的var与let前者为可变修饰符,后者为不可变从字面意思我们就可以很好的区分了常用的类型呢,跟其他语言基本相同啦,主要有几种:1.int类型2.Float,Double类型3.String类型4.Boolean类型当我们去声明一

  2. Swift 集合数据结构性能分析

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  3. Swift中的集合类数据结构

    在那种情况下,你将会需要一种基本的集合类数据结构。继续学习,你将会比较成熟的Cocoa数据结构与对应的纯Swift结构的性能。常见iOS数据结构iOS中三种最常用的数据结构是arrays,dictionaries和sets。除了在Swift和Objective-C中旧的Foundation框架中的数据结构,现在又有了新的仅支持Swift版本的数据结构与语言紧密结合在一起。Swift数组是同质的,意味着每一个Swift数组都只包含一种类型的对象。

  4. 11.Swift 中的类和结构体

    举例来说,以下情境中适合使用结构体:1.几何形状的大小,封装一个width属性和height属性,两者均为Double类型。这次就讲到这里,下次我们继续

  5. a place you can learn algorithms and data structures(算法和数据结构) in swift

    https://github.com/raywenderlich/swift-algorithm-club

  6. Swift3.0 类和结构体的选择

    结构体实例总是通过值传递,类实例总是通过引用传递先说说值类型和引用类型的区别值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝在Swift中,所有的结构体和枚举类型都是值类型。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体”Swift中,许多基本类型,诸如String,Array和Dictionary类型均以结构体的形式实现。Objective-C中Nsstring,NSArray和NSDictionary类型均以类的形式实现,而并非结构体。

  7. 【Swift】结构体和类

    Swift中结构体和类有很多共同点与结构体相比,类还有如下的附加功能:结构体和枚举是值类型值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝。为了达到这个目的,Swift内建了两个恒等运算符:类和结构体的选择在你的代码中,你可以使用类和结构体来定义你的自定义数据类型。实际中,这意味着绝大部分的自定义数据构造都应该是类,而非结构体。Swift中,许多基本类型,诸如String,Array和Dictionary类型均以结构体的形式实现。

  8. 如何在Swift中创建打包数据结构?

    我正在将一个项目从Objective-C转换为Swift,我正在使用一个打包的结构来输入通过套接字发送的转换二进制消息:我不确定Swift中最好的方法是什么,我能得到的最接近的近似值是:翻译中丢失了两个重要的细节:没有保证整数类型的比特,并且没有结构打包.我不认为这可以在Swift中表达,但如果是这样,怎么样?

  9. android – 如何正确删除保留的实例片段

    解决方法正如@Luksprog所建议的,以下方法有效.但是,它仍然无法解释为什么通过onDetach完成的先前清理不起作用.如果有人能解释为什么这个解决方案有效,而以前没有,我会非常感激.版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  10. android – 数组适配器notifyDataSetChanged()将无法正常工作

    .有任何想法吗?

随机推荐

  1. 【数据结构】单调栈

    显然,每个发射站发来的能量有可能被0或1或2个其他发射站所接受,特别是为了安全,每个发射站接收到的能量总和是我们很关心的问题。由于数据很多,现只需要你帮忙计算出接收最多能量的发射站接收的能量是多少。输入输出格式输入格式:第1行:一个整数N;第2到N+1行:第i+1行有两个整数Hi和Vi,表示第i个人发射站的高度和发射的能量值。输入输出样例输入样例:34235610输出样例:7题解中有讲解代码实现

  2. BZOJ 1798 [Ahoi2009] Seq 维护序列seq [线段树+多重标记下传]【数据结构】

    有长为N的数列,不妨设为a1,a2,…Input第一行两个整数N和P。第二行含有N个非负整数,从左到右依次为a1,aN,。表示把所有满足t≤i≤g的ai改为ai×c。操作2:“2tgc”。同一行相邻两数之间用一个空格隔开,每行开头和末尾没有多余空格。Output对每个操作3,按照它在输入中出现的顺序,依次输出一行一个整数表示询问结果。SampleInput7431234567512553242379313347SampleOutput2358HINT初始时数列为。对第5次操作,和为29+34+15+16=

  3. 陈越《数据结构》第一讲 基本概念

    陈越《数据结构》第一讲基本概念1什么是数据结构1.1引子例子:如何在书架上摆放图书?数据结构是:1.数据对象在计算机中的组织方式;2.数据对象必定与一系列加在其上的操作相关联;3.完成这些操作所用的方法就是算法。抽象数据类型数据类型-数据对象集;-数据集合相关联的操作集。抽象-与存放数据的机器无关;-与数据存储的物理结构无关;-与实现操作的算法和编程语言均无关。

  4. 陈越《数据结构》第二章 线性结构

    表中元素个数称为线性表的长度;线性表没有元素时,称为空表;表起始位置称表头,表结束位置称表尾。插入和删除操作只能在链栈的栈顶进行。

  5. 【数据结构】

    非线性结构:线性结构的元素之间具有线性关系,非线性结构中的元素之间不再是序列的关系,他们呈现的是更复杂的层次关系,即一个数据元素有且仅有一个直接前驱,但可有另个或者多个直接后继,显然比序列关系复杂常见非线性结构:树,图散列表PHP中的hashtable就是哈希表就是由数组和链表组成,一个长度为16的数组中,每个元素存储的是一个链表的头结点。

  6. 【数据结构】【C++STL】FIFO队列&amp;优先队列

    首先都需要打头文件queueFIFO队列是先进先出的就好像排队一样STL定义FIFO队列优先队列的话是有优先级存在的STL定义优先队列定义方式都是大根堆FIFO队列和优先队列都有一些操作COYG

  7. 【数据结构】 堆

    自底向上://增加/减少已有节点值Heap_Increase_Key//向堆插入新的节点HeapInsert自顶向下://替换堆顶后,维持堆函数KeepHeap//弹出堆顶函数Pop

  8. 【数据结构】链表

    线性表的顺序存储结构有存储密度高及能够随机存取等优点,但存在以下不足:线性表的链式存储(单链表)的实现单向循环链表的实现

  9. 伸展树(SPLAY)个人总结+模板 [平衡树]【数据结构】【模板】

    前言最近3个月内,无论是现场赛还线上赛中SPLAY出现的概率大的惊人啊啊啊!!!然而不会的我就GG了,同时发现大家都会SPLAY,,,,然后就学习了一波。——————————————————————————-附上整体代码-md贴上来太卡了,去题解里看吧维护序列的维护一堆数的

  10. BZOJ 1895 &amp; POJ 3580 supermemo [SPLAY]【数据结构】

    Ay}Ttimes.Forexample,performing“REVOLVE242”on{1,5}INSERTxP:insertPafterAx.Forexample,performing“INSERT24”on{1,5}DELETEx:deleteAx.Forexample,performing“DELETE2”on{1,5}MINxy:querytheparticipantwhatistheminimumnumberinsub-sequence{Ax…Ay}.Forexample,thecorrec

返回
顶部