2
头图

Preface

From the beginning of this article, we will learn graph-related algorithms together. Graph calculation has many practical algorithms, such as: garbage collector's mark removal algorithm, the shortest distance to find the path on the map, topological sorting, etc. Before we start learning these algorithms, we need to understand the basic definition of the following graph and what kind of data structure is used to represent a graph. In this article, we will start with undirected graphs.

Definition of graph

Figure: It is composed of a set of vertices and a set that can connect two orders. The edge connecting two vertices has no direction. This kind of graph is called an undirected graph.

Graph terms

We call the two vertices connected by the same edge adjacent ;

A vertex degrees i.e. represents the total number of edges connecting the vertices; as FIG: 3 is the degree of vertex 1

An edge connects a vertex to itself, we call it self-loop

The edge connecting the same pair of vertices is called parallel edge

There are still many terms. For the time being, only the terms we need to use in this article are listed here, and other terms will be explained later. Too many are not easy to remember.

How to show the graph

What data structure is used to represent the graph mainly refers to two requirements:

  1. When developing graph-related algorithms, the data structure represented by the graph is the foundation, so this data structure is highly efficient
  2. In the actual process, the size of the picture is uncertain and may be very large, so it is necessary to reserve enough space

After considering these two requirements, the big guys proposed the following three methods to choose from:

  • Adjacency matrix

Type in a graph with v vertices, we can use the matrix of v multiplied by v to represent, if the vertex v is connected to w, then set the v row and w column to true, so that it can indicate that the two vertices are connected, but this way has This is a problem. If you encounter a large picture, it will cause a waste of space. Does not meet the second point. Secondly, there is no way to express parallel sides in this way

  • Array of edges

You can define an edge object that contains two int attributes to represent vertices, but if we need to find out which vertices are connected to a vertex, we need to traverse all the edges. The efficiency of this data structure is poor

  • Adjacency list array

Define an array, the size of the array is the number of vertices, the data subscript represents the vertex, each element in the array is a linked list object (LinkedListQueue), and the value stored in the linked list is the vertex connected to the vertex. (LinkedListQueue has been implemented in the previous article, you can refer to the article " https://juejin.cn/post/6926685994347397127 ")

API definition of undirected graph

public class Graph {
    public Graph(int V); //创建含有v个顶点不含边的图
    
    public int V(); //返回顶点的个数
    
    public int E(); //返回图中边的总数
    
    public void addEdge(int v, int w); //向图中添加一条边 v-W 
        
    public Iterable<Integer> adj(int v); //返回与v相邻的所有顶点
    
    public String toString(); //使用字符串打印出图的关系
}

Implementation of Undirected Graph API

To implement the API defined above, we need three member variables, v represents the number of vertices in the graph, e represents the data of the total edges of the graph, and the array of LinkedListQueue is used to store adjacent nodes of vertex v;

The constructor initializes an empty adjacency list array

Because it is an undirected graph, the addEdge method needs to add an edge v->w when adding an edge to the graph, and there is a need to add an edge w->v

public class Graph {
    private final int v;
    private int e;
    private LinkedListQueue<Integer>[] adj;

    public Graph(int v) {
        this.v = v;
        this.adj = (LinkedListQueue<Integer>[]) new LinkedListQueue[v];
        for (int i = 0; i < v; i++) {
            this.adj[i] = new LinkedListQueue<>();
        }
    }

    public int V() {
        return v;
    }

    public int E() {
        return e;
    }

    public void addEdge(int v, int w) {
        this.adj[v].enqueue(w);
        this.adj[w].enqueue(v);
        this.e++;
    }

    public Iterable<Integer> adj(int v) {
        return this.adj[v];
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(v).append(" 个顶点,").append(e).append(" 条边\n");
        for (int i = 0; i < v; i++) {
            sb.append(i).append(": ");
            for (int j : this.adj[i]) {
                sb.append(j).append(" ");
            }
            sb.append("\n");
        }
        return sb.toString();
    }
}

Diagram of common tools and methods

Based on the realization of the graph data structure, we can provide some tools and methods

  1. Calculate the degree of vertex v

The degree of a vertex is equal to the number of vertices connected to it

public static int degree(Graph graph, int v) {
    int degree = 0;
    for (int w : graph.adj(v)) {
        degree++;
    }
    return degree;
}
  1. Calculate the maximum degree of all vertices
public static int maxDegree(Graph graph) {
    int maxDegree = 0;
    for (int v = 0; v < graph.V(); v++) {
        int degree = degree(graph, v);
        if (maxDegree < degree) {
            maxDegree = degree;
        }
    }
    return maxDegree;
}
  1. Calculate the average degree of all vertices

Each edge has two vertices, so the total degree of all vertices in the graph is twice that of the edge

public static double avgDegree(Graph graph) {
    return 2.0 * graph.E() / graph.V();
}
  1. Calculate the number of self-loops in the graph

For vertex v, if v also appears in the adjacency list of v, it means that v has a self-loop; because it is an undirected graph, each edge is recorded twice (if you don’t understand it, you can put the toString of the graph It can be understood by printing)

public static int numberOfSelfLoops(Graph graph) {
    int count = 0;
    for (int v = 0; v < graph.V(); v++) {
        for (int w : graph.adj(v)) {
            if (v == w) {
                count++;
            }
        }
    }
    return count / 2;
}

to sum up

In this article, we mainly learn what data structure to use to represent a graph, and implement several simple tool methods based on this data structure. In the next article, we will learn the first search algorithm for graphs in the future-depth-first search

All the source code in the article has been placed in the github warehouse:
https://github.com/silently9527/JavaCore


A must-read list for programmers to vomit blood: https://github.com/silently9527/ProgrammerBooks

WeChat public account: Beta learns Java

Finally (point attention, don’t get lost)

There may be more or less deficiencies and mistakes in the article. If you have suggestions or comments, you are welcome to comment and exchange.

Finally, is not easy to write, please don’t use me , I hope friends can like and comment and follow Sanlian, because these are all the sources of motivation for my sharing🙏


Herman
632 声望3.7k 粉丝

知识星球:Herman's Notes


引用和评论

0 条评论