数据结构---图---存储结构---2

不清楚的看大话数据结构这本书。

图结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在内存中的物理位置来表示元素之间的关系,也就是说,图不可能用简单的顺序存储结构来表示。多重链表虽能实现,也有相应的问题,具体看书。

存储结构有五种

  1. 邻接矩阵:边数少会浪费空间(一维数组+二维数组(或交错数组))(通用型)
  2. 邻接表:适合关注的重点是顶点的无向图(一维数组+一个链表))(对邻接矩阵的优化)
  3. 十字链表:适合有向图,同时关注入度和出度(一维数组+两个链表))(对邻接表的优化)
  4. 邻接多重表:适合关注的重点是边的无向图(一维数组+一个链表))(优化边的操作)
  5. 边集数组:适合对边依次进行处理的操作(两个一维数组)(优化边的操作)

邻接矩阵:边数少会浪费空间
图的邻接矩阵存储方式是用两个数组来表示图。一个一维数组存储图中顶点信息,一个二维数组(称为邻接矩阵)存储图中的边或弧的信息。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/// <summary>
/// 邻接矩阵
/// </summary>
public class AdjacentMatrix<T>
{
	#region 数据 :不需要的可以自行删除  
    private T[] vertexs;        //顶点数组:数据
    private int[,] edges;       //边数组:权值  
    private int maxNumVertex;   //最大顶点数
    private int numVertex;      //顶点数
    private int numEdge;        //边数
    #endregion
    
    /// <summary>
    /// 创建无向网图的邻接矩阵表示
    /// </summary>    
    /// <param name="vertexs">顶点数据</param>
    /// <param name="edges">边数据:权值</param>
    /// <param name="maxNumVertex">最大顶点数组容量</param>
    public AdjacentMatrix(T[] vertexs, int[,] edges, int maxNumVertex)
    {
        maxNumVertex = maxNumVertex < vertexs.Length ? vertexs.Length : maxNumVertex;
        this.vertexs = new T[maxNumVertex];
        this.edges = new int[maxNumVertex, maxNumVertex];
        this.maxNumVertex = maxNumVertex;
        Array.Copy(vertexs, this.vertexs, vertexs.Length);
        Array.Copy(edges, this.edges, edges.Length);
    }
}

邻接表:适合无向图(关注的重点是顶点的无向图)

边数相对于顶点较少的图,邻接矩阵存在存储空间的极大浪费。

所以我们考虑对边或弧使用链式存储的方式避免空间浪费。

数组与链表相结合的存储方法称为邻接表

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/// <summary>
/// 邻接表:一维数组 + 链表(数组和链表自行提供)
/// </summary>
public class AdjacencyList<T> where T : IEquatable<T>
{
    /// <summary>
    /// 边表结点
    /// </summary>
    public class EdgeNode
    {
        public int adjvex;      //邻接点域,存储该顶点在顶点表中对应的下标
        public int weight;      //用于存储权值,对于非网图可以不需要(关键路径需要权值)
        public EdgeNode next;   //链域,指向下一个邻接点
    }

    /// <summary>
    /// 顶点表结点
    /// </summary>
    public class VertexNode<T>
    {
        public int inDegree;            //入度:拓扑排序用
        public T data;                  //顶点域,存储顶点信息
        public EdgeNode firstEdge;      //边表头指针
    }

    private int numVertexes;             //顶点数   
    private VertexNode<T>[] adjacencyArr;   //顶点表

    /// <summary>
    /// 说明:没有按书上写,需要的数据自行提供,包括顶点数据和边表数据
    /// </summary>
    /// <param name="vertexData">顶点数据</param>
    /// <param name="edgeData">边表数据</param>
    public AdjacencyList(VertexNode<T>[] vertexData, EdgeNode[] edgeData)
    {        
        numVertexes = vertexData.Length;
        adjacencyArr = new VertexNode<T>[numVertexes];

        for (int i = 0; i < numVertexes; i++)                //建立顶点表
        {
            adjacencyArr[i].data = vertexData[i];            //顶点数据
            adjacencyArr[i].firstEdge = edgeData[i];         //建立边表
        }
    }
}

十字链表:适合有向图

对于有向图来说,邻接表是有缺陷的,关心出度问题,想了解入度就必须要遍历整个图才能知道,反之,逆邻接表解决了入度却不了解出度的情况。

十字链表:把邻接表和逆邻接表结合起来

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

/// <summary>
/// 泛型十字链表:有向图的优化,同时关心入度和出度
/// </summary>
public class OrthogonalList<T>
{
    /// <summary>
    /// 边表结点
    /// </summary>
    public class EdgeNode
    {
        public int tailIndex;       //弧起点在顶点表的下标
        public int headIndex;       //弧终点在顶点表的下标
        public int weight;          //用于存储权值,对于非网图可以不需要
        public EdgeNode headLink;   //入边表指针域,指向终点相同的下一条边
        public EdgeNode tailLink;   //出边表指针域,指向起点相同的下一条边
    }

    /// <summary>
    /// 顶点表结点
    /// </summary>
    public class VertexNode<T>
    {
        public T data;                  //顶点域,存储顶点信息
        public EdgeNode firstIn;        //入边表头指针
        public EdgeNode firstOut;       //出边表头指针
    }

    public int numVertexes;             //顶点数
    public int numEdges;                //边数
    public VertexNode<T>[] orthList;       //顶点表

    /// <summary>   
    /// 说明:没有按书上写,需要的数据自行提供,包括顶点数据和边表数据   
    /// </summary>
    /// <param name="vertexData">顶点数据</param>
    /// <param name="tailEdgeData">出边表数据</param>
    /// <param name="headEdgeData">入边表数据</param>
    public OrthogonalList(T[] vertexData, EdgeNode[] tailEdgeData, EdgeNode[] headEdgeData)
    {
        numVertexes = vertexData.Length;
        orthList = new VertexNode<T>[numVertexes];

        for (int i = 0; i < numVertexes; i++)               //建立顶点表
        {
            orthList[i].data = vertexData[i];               //顶点数据
            orthList[i].firstIn = headEdgeData[i];          //建立入边表
            orthList[i].firstOut = tailEdgeData[i];         //建立出边表
        }
    }
}

邻接多重表:对无向图的邻接表的优化(更关注边的操作)
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述

在这里插入图片描述

/// <summary>
/// 邻接多重表:无向图的优化
/// </summary>
public class AdjacencyMultiList<T>
{
    /// <summary>
    /// 边表结点
    /// </summary>
    public class EdgeNode
    {
        public int iVex;            //该顶点在顶点表中的下标
        public EdgeNode iLink;      //指向依附顶点iVex的下一条边
        public int jVex;            //该顶点在顶点表中的下标
        public EdgeNode jLink;      //指向依附顶点jVex的下一条边
        public int weight;          //用于存储权值,对于非网图可以不需要        
    }

    /// <summary>
    /// 顶点表结点
    /// </summary>
    public class VertexNode<T>
    {
        public T data;                	//顶点域,存储顶点信息
        public EdgeNode firstEdge;      //边表头指针
    }

    public int numVertexes;             //顶点数   
    public VertexNode<T>[] adjacencyMultiList;   //顶点表

    /// <summary>
    /// 说明:没有按书上写,需要的数据自行提供,包括顶点数据和边表数据
    /// </summary>   
    /// <param name="datas">顶点数据</param>
    /// <param name="edgeData">边数据</param>
    public AdjacencyMultiList(T[] datas, EdgeNode[] edgeData)
    {        
        numVertexes = datas.Length;
        adjacencyMultiList = new VertexNode<T>[numVertexes];
        for (int i = 0; i < numVertexes; i++)      //建立顶点表
        {
            adjacencyMultiList[i].data = datas[i];            //顶点数据
            adjacencyMultiList[i].firstEdge = edgeData[i];    //建立边表
        }
    }
}

边集数组:关注的是边的集合,适合对边依次进行处理的操作,不适合对顶点的相关操作

边集数组是有两个一维数组构成。一个是存储顶点的信息;另一个是存储边的信息,这个边数组每个数据元素由一条边的起点下标(begin)、终点下标 (end) 和权 (weight) 组成。

学习了克鲁斯卡尔(Kruskal)算法时在补充上
在这里插入图片描述

/// <summary>
/// 边集数组
/// </summary>
public class EdgeArrary<T>
{
    public class Edge
    {
        public int begin;		//起点下标
        public int end;			//终点下标
        public int weight;		//权值
    }

    private T[] vertexArr;		//顶点数据
    private Edge[] edgeArr;		//边数据

    /// <summary>
    /// 创建编辑数组
    /// </summary>
    /// <param name="vertexData">顶点数据</param>
    /// <param name="edgeData">边数据</param>
    public EdgeArrary(T[] vertexData,Edge[] edgeData)
    {
        vertexArr = vertexData;
        edgeArr = edgeData;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值