10--Storage of graphs and graphs

This article includes a summary of the basic knowledge of data structures and algorithms. Students who need to know about data structures and algorithms linked lists, binary trees and other related knowledge are welcome to view them.

It refers to the data relationship in the 逻辑结构computer. The data in the computer can only be stored in the computer by two storage structures, namely 顺序存储and 链式存储.

1. Basic knowledge of graphs

image.png

  • 1. The blue marked points in the above figure are called vertices;
  • 2. The connecting lines between vertices are called edges.

1. Definition of graph

A graph is composed of a finite non-empty set of vertices and a set of edges between vertices. Usually denoted as G(V,E), where G represents the graph, V represents the set of vertices, and E represents the set of edges between vertices.

2. Classification of graphs

1. Directed and Undirected Graphs

image.png

  • 1. According to the relationship between vertices and edges;
  • 2. An edge between any two vertices 没有方向. A graph is called 无向图an edge, an edge is called an undirected edge;
  • 3. An edge between any two vertices 有方向can only point from one vertex to another. A graph 有向图is called a directed edge, and an edge is called a directed edge.

2. Undirected complete graphs and directed complete graphs

image.png

任意A vertex in a graph 其他has connections between vertices.

3. Net map

image.png

The edges connected between the vertices in the graph are yes 有权重, the weight of each edge may be different, and the graph with the edge weight between the vertices is called 网图.

4. Connected and Disconnected Graphs

image.png

  • 1. There is no edge connection between some vertices and other vertices in the graph, and no indirect connection can be made through the edges between vertices. This kind of graph is called 非连通图, as shown in Figure 1;
  • 2. All vertices in the graph can be connected by limited edges, that is, all vertices are connected, which is called such a graph 连通图, as shown in Figure 2.

5. Subplots

image.png

A graph consisting of any set of vertices and connected edges in a graph is called a graph 子图.

Second, the storage of pictures

Take Kuaishou interview questions as an example:

image.pngTopic analysis:

  • 1.题目要求:设计一种数据结构,将上面的图存到计算机的内存中;
  • 2.上图是一个有向网图
  • 3.图中有顶点数据[v0 v1 v2 v3 v4],边数据[1(v3->v4) 2(v2->v0) 3(v1->v2) 5(v2->v3) 6(v0->v4) 9(v1->v0)];

思考:如何将顶点和边存到内存中,并且满足图中各顶点之间的关系呢?

(一)顺序存储--邻接矩阵

1.邻接矩阵

(1)图是一个无向图、并且边无权重时 image.png

  • 1.用一个一维数组存储顶点信息;
  • 2.用一个二维数组存储顶点之间的信息,顶点之间有连接用1表示,无连接用0表示;

上图存储边信息的二维数组矩阵有如下特征:

  • 1.第i行第j列的位置存储的是顶点Vi和顶点Vj的边信息,如果Vi和Vj有连接关系,则i行j行记为1,二维数组的对应位置存储1,否则记为0
  • 2.矩阵的对角线上存的数据为0,即任意顶点和自己之间是没有连接关系的。
  • 3.矩阵中的数据以对角线对称,即无向图中Vi和Vj之间的边和Vj和Vi之间的边是相等的。

(2)图是一个有向图,并且边无权重时

image.png

这种情况与(1)的区别主要是图是一个有向图,二维数组矩阵中Vi和Vj之间的边和Vj和Vi之间的边是不相等,即Vi指向Vj,但Vj不一定指向Vi.

(3)图是一个有向图,并且有权重时

image.png

  • 1.这种情况和(2)的区别就是有权重,所以二维数组存的数据是边的权重值;
  • 2.由于权重值有可能是1,所以如果顶点之间的没有边信息,对应的二维数组存的值可以为一个异常的数据,如无穷大

通过上面的分析,我们得到的存储图的顶点与顶点关系的二维数组矩阵即为邻接矩阵。

2.代码实现

1.定义一些状态值和数据类型

#define OK 1

#define ERROR 0

#define TRUE 1

#define FALSE 0

#define MAXVEX 100 //最大顶点数,应由用户定义

#define INFINITYC 0

typedef int Status;    //Status是函数的类型,其值是函数结果状态代码,如OK等

typedef char VertexType; //顶点类型

typedef int EdgeType; //边上的权值类型
复制代码

2.存储结构设计

typedef struct
{
    VertexType vexs[MAXVEX]; //顶点表

    EdgeType arc[MAXVEX][MAXVEX];//邻接矩阵,可看作边表

    int numNodes, numEdges; //图中当前的顶点数和边数

}MGraph;
复制代码

3.存储实现

void CreateMGraph(MGraph *G){

    int i,j,k,w;
    
    printf("输入顶点数和边数:\n");

    //1. 输入顶点数/边数
    scanf("%d,%d",&G->numNodes,&G->numEdges);
    printf("顶点数:%d,边数:%d\n",G->numNodes,G->numEdges);

    //2.输入顶点信息/顶点表
    for(int i = 0; i< G->numNodes;i++)
    {
        getchar();
        scanf("%c",&G->vexs[i]);
    }

    printf("顶点数据:\n");
    for (i = 0; i<G->numNodes; i++) {
        printf("%c ",G->vexs[i]);
    }
    printf("\n");

    //3.初始化邻接矩阵
    for(i = 0; i < G->numNodes;i++)
         for(j = 0; j < G->numNodes;j++)
             G->arc[i][j] = INFINITYC;

    //4.输入边表信息
    for(k = 0; k < G->numEdges;k++){
        printf("输入边(vi,vj)上的下标i,下标j,权w\n");
        scanf("%d,%d,%d",&i,&j,&w);

        G->arc[i][j] = w;

        //如果无向图,矩阵对称;
        G->arc[j][i] = G->arc[i][j];
    }

    //5.打印邻接矩阵
    for (int i = 0; i < G->numNodes; i++) {
        printf("\n");
        for (int j = 0; j < G->numNodes; j++) {
            printf("%d ",G->arc[i][j]);
        }
    }
    printf("\n");
}
复制代码

4.调试

image.png

5.邻接矩阵的缺点

image.png

  • 1.如上面的图,有5个顶点,但却只有一条边信息;
  • 2.但在顺序存储中,需要申请5x5的二维数组矩阵空间来存储这一条边信息;
  • 3.这就导致了大量的空间浪费

(二)链式存储--邻接表

1.邻接表

image.png

  • 1.创建一个一维顶点数组存储顶点信息;
  • 2.顶点数组存的元素是一个顶点数据的结点,顶点的数据结构中有一个指针指向边信息边信息是一个单向链表,这个单向链表存储了所有与顶点有连接的顶点的边信息
  • 3.边信息的单向链表保存的是顶点与其他顶点之间的边数据,它们没有顺序关系

2.代码实现

image.png

以如上例子实现邻接表下的链式存储

1.定义一些状态值和数据类型

#define M 100

#define true 1

#define false 0

typedef char Element;

typedef int BOOL;
复制代码

2.定义结点和存储结构

//邻接表的边结点
typedef struct Node{

    int adj_vex_index;  //边信息对应的顶点在数组中的下标

    Element data;       //边的权重值

    struct Node * next; //边指针:指向下一个边结点

}EdgeNode;

//顶点结点
typedef struct vNode{

    Element data;          //顶点数据

    EdgeNode * firstedge;  //顶点下一个是谁?

}VertexNode, Adjlist[M];


//总图的一些信息
typedef struct Graph{

    Adjlist adjlist;       //顶点表

    int arc_num;           //边数

    int node_num;          //顶点数

    BOOL is_directed;      //是不是有向图

}Graph, *GraphLink;
复制代码

3.存储实现

void creatGraph(GraphLink *g){
    int i,j,k;

    EdgeNode *p;

    //1. 顶点,边,是否有向
    printf("输入顶点数目,边数和有向?:\n");
    scanf("%d %d %d", &(*g)->node_num, &(*g)->arc_num, &(*g)->is_directed);


    //2.顶点表
    printf("输入顶点信息:\n");
    for (i = 0; i < (*g)->node_num; i++) {
        getchar();
        scanf("%c", &(*g)->adjlist[i].data);
        //创建顶点时,顶点数据指向边信息此时还没有,所以指向null
        (*g)->adjlist[i].firstedge = NULL;
    }
    
    //3.边信息
    printf("输入边信息:\n");
    for (k = 0; k < (*g)->arc_num; k++){
        getchar();
        scanf("%d %d", &i, &j);

        //①新建一个节点
        p = (EdgeNode *)malloc(sizeof(EdgeNode));

        //②弧头的下标
        p->adj_vex_index = j;

        //③头插法插进去,插的时候要找到弧尾,那就是顶点数组的下标i
        p->next = (*g)->adjlist[i].firstedge;

        //④将顶点数组[i].firstedge 设置为p
        (*g)->adjlist[i].firstedge = p;

        if(!(*g)->is_directed)
        {
            // j -----> i
            //①新建一个节点
            p = (EdgeNode *)malloc(sizeof(EdgeNode));

            //②弧头的下标i
            p->adj_vex_index = i;

            //③头插法插进去,插的时候要找到弧尾,那就是顶点数组的下标i
            p->next = (*g)->adjlist[j].firstedge;

            //④将顶点数组[i].firstedge 设置为p
            (*g)->adjlist[j].firstedge = p;
        }
    }
}
复制代码
  • 1.输入顶点个数边数是否是有向图等信息;
  • 2.顶点存入一维数组中,一维数组存的是一个带数据域指针域的结构体,数据域存储顶点数据指针域指向存储边信息的单向链表;
  • 3.输入边信息,i是当前顶点下标,j是连接顶点在顶点数组中的下标
  • 4.输入后创建结点,记录权重值、顶点的下标j、指针域指向等;
  • 5. To determine whether it is 有向图, if it is an undirected graph, it is necessary to determine the relationship between j as the original vertex and i as the pointed vertex, and create the relationship between the two vertices of j and i, ie 反向关系.

4. Traverse and print

void putGraph(GraphLink g){
    int i;
    printf("邻接表中存储信息:\n");

    //遍历一遍顶点坐标,每个再进去走一次
    for (i = 0; i < g->node_num; i++) {
        EdgeNode * p = g->adjlist[i].firstedge;

        while (p) {
            printf("%c->%c ", g->adjlist[i].data, g->adjlist[p->adj_vex_index].data);
            p = p->next;
        }
        printf("\n");
    }
}
复制代码

5. Debug

/*
     邻接表实现图的存储
     输入顶点数目,边数和有向?:
     4 5 0

     输入顶点信息:
     0 1 2 3

     输入边信息:
     0 1 0 2 0 3 2 1 2 3

     邻接表中存储信息:
     0->3 0->2 0->1
     1->2 1->0
     2->3 2->1 2->0
     3->2 3->0
    */

    /*

     邻接表实现图的存储
     输入顶点数目,边数和有向?:
     4 5 1

     输入顶点信息:
     0 1 2 3

     输入边信息:
     1 0 1 2 2 1 2 0 0 3

     邻接表中存储信息:
     0->3
     1->2 1->0
     2->0 2->1
     */

    GraphLink g = (Graph *)malloc(sizeof(Graph));
    creatGraph(&g);
    putGraph(g);
复制代码

undirected graph storage

image.png

Directed graph storage

image.png

4. Summary

  • 1. A graph is a type of computer data 逻辑结构that can be used 顺序存储or used 链式存储;
  • 2. The sequential storage of graphs is 邻接矩阵implemented using;
  • 3. The chain test storage of the graph is 邻接表implemented using.

Guess you like

Origin juejin.im/post/7079258498831220773