An article to help you understand the difference between adjacency matrix, adjacency list and chain forward star

Foreword:

When I was learning C++, faced with various image storage methods, my brain was a lot bigger, and various algorithms were still rushing towards me. As a result, an adjacency matrix/adjacency list/linked list easily gave me a crit Let me KO directly, and while my mind is still clear, I will introduce the essence and code implementation of these three image storage methods in detail.

Idea realization:

Chained forward star and adjacency matrix are suitable for storing dense graphs, while adjacency lists are suitable for storing sparse graphs. When doing questions, you can choose three ways to store graphs according to different data ranges.
Now that the picture is mentioned, let's introduce it first.

1. What is a picture?

A graph is a data structure. For beginners, it can be understood that a graph is a graph with many points connected by edges.
Graphs are divided into undirected graphs and directed graphs. An undirected graph means that there is no clear directionality between two points, and the two points can visit and traverse each other.
The directed graph is different from this. After the directivity is input, the computer can only traverse according to the previously built directed graph.


insert image description here
The two diagrams are similar, but some details are very different. However, the input of the directed graph and the undirected graph are exactly the same, but the meaning is slightly different. Here is an example from the above graph: Here
we assume that there is an edge from uv in the graph, and the inputs of the two graphs are:

1 2
1 4
5 1
1 3

Here, take "1 2" in the first line as an example;
in an undirected graph, I can access node ② from node ①, and I can also access node ① from node ②;
in a directed graph: Because the input sequence is '1' first and then '2', in the process of traversing and accessing the graph, you can only visit node ② from node ①.
Apart from the edge relationship, another important thing in the graph is the edge weight. Simply put, it is the "cost" required to visit two nodes.
insert image description here
Here is a directed graph as an example. It is not difficult to find in the above figure that the edge weight from node ① to node ② is 3, and the edge weight from node ② to node ③ is 4...here the edge weight is The function is that in some questions, what is the sum of edge weights required to go from a certain node to a certain node.
Graphs are also divided into dense graphs and sparse graphs. Sparse graphs have fewer edges than complete graphs, and dense graphs have edges close to complete graphs.
After talking about the graph, the following will introduce the principle and code implementation of the forward star, adjacency matrix and adjacency table storage graph one by one.

2. Chain forward star

The essence of the chained forward star is a linked list, but it also has a head array to record the head node. Using the linked list, the image storage operation can be performed according to the characteristics of one node accessing another node. Suppose it has n points and m edges. Then its space efficiency and space efficiency are both O(m), which is suitable for storing dense graphs. The following uses the code to explain the principle;

struct EDGE{
    
    
	int v,w,next;
	//v变量记录的是当前点到达那一条边。
	//w变量记录的是走过当前这条边所需的"代价"即权值
	//next变量记录的是以某一个定点为起点,读的上一条边的编号。
	//这三个变量的意义一定要搞明白,不搞明白这个,前向星的写法死记硬背也不一定行。
}e[N<<1];
int head[N],tot=1;
void add(int u,int v,int w)
{
    
    
	e[tot].v=v;
	e[tot].w=w;
	e[tot].next=head[u];
	head[u]=tot++;
}

Suppose there is a graph here:
insert image description here
this is a directed weighted graph, so the input between its sides should be:
insert image description here
the three variables corresponding to v, w, and next in the structure array should be:
insert image description here
it is not difficult to see that here Tot records the number of the previous line, that is to say, I can find the number of the previous line through tot, so as to find out the to, w, next of the previous saved image; then what is the head array for
? Let's draw another graph;
insert image description here

It can be seen from this figure that the head array is actually the number of the last edge that I read starting from the i-th numbered point.
For those who don't understand, the blogger is giving an example to explain it based on code and pictures.
It can be said that the head array is the core idea of ​​the chain forward star

Suppose we want to find the edge whose starting point is 1, the ending point is 4, and the edge weight is 9.
Because the starting point is 1, we find that the value stored in head[1] is 4, which means that the number of the last edge we read in starting from 1 is 4.
insert image description here
According to the number, we find the set of data on the horizontal line in the above figure. So far, the role of the head array has been played, and then the next variable comes into play.
The next variable value of the line with the red line in the above figure is 3, indicating that the number of the previous edge starting from 1 is 3, so we find the line with the number 3, since it is not what we are looking for, so let’s look at the line numbered as The next of the row of 3 is 2, so we visit the row numbered 2, and find that it is exactly the edge we are looking for, and then end the search.
insert image description here
Therefore, we find the edge numbered 2 from the edge numbered 3 and find the edge of the result, as shown in the figure above. Therefore, the continuous search is not just like a chain, so this way of storing pictures is called a chain forward star.
The principle is clear, and then I will explain each step of the code one by one according to the legend and principle mentioned above.

Code explanation:

We divide it into two parts, one part is the structure array, and the other part is the edge-building add operation.

struct EDGE{
    
    
	int v,w,next;
}e[N<<1];

The 'v, w, next' stored in the structure array are respectively the edge pointed to, the edge weight and the number of the previous edge read from a fixed point as the starting point.

void add(int u,int v,int w)
{
    
    
	e[tot++].v=v;//将指向的边存进去。这里注意一个点,此时是新的一条边,cnt要++;
	e[tot].w=w;//将当前的边的边权存进去
	//下面两步是最为核心的两步。
	e[tot].next=head[u];
	//我们说了,next数组存的是以某个定点为起点,读的上一条边的编号。head数组里记录的是以某个点为起点,
	//我读进去的最后一条边的编号。想一下,此时的e[tot]的这条边还没有加进去,所以此时的e[tot]的数组的
	//上一条边的编号就是我head数组存的最后一条边的编号。所以我得e[tot].next=head[u]就行啦!
	head[u]=tot;
	//此时我已经读进去了新的一条边,那此时head最后指向的是不是就是当前的边?就是此时的cnt呀,我直接赋
	//值给head[u]就行
}

Huh~ This is the idea + code of the chained forward star. The blogger thinks that it is more detailed. While writing, he also stroked his own ideas, so he adopted the most clumsy method. Next, I will explain to you the adjacency matrix!

3. Adjacency matrix

Matrix matrix, as soon as you hear the name, you can probably guess that it is a two-dimensional array (I want to mention here, whoever thinks it is a one-dimensional array does not need to learn it, your brain is too stupid... like me ... . )
Pulling away, pull back~ But this is not a simple two-dimensional array. When there is no bounds, the numbers '1' and '0' stored in the array, as to why there are two numbers stored, wait I will explain that for graphs with edge weights, the edge weights are stored in our array.
Different from the chained forward star, the adjacency matrix needs to consider directed graphs, undirected graphs, and weighted graphs...but the idea is slightly simpler than the forward star, both of which are densely stored graphs.
Let's consider from the perspective of directed and undirected graphs (1) Directed graphs:
For directed graphs, I go from the i-th point to the j-th point and from the j-th point to the i-th point The point is completely two different roads, if it is not added to the graph in advance, it is impossible to go without advance declaration, it can also be understood as e[i][j]!=e[j][i];
( 2) Undirected graph:
An undirected graph is completely different from a directed graph. If I say that there is an edge to go from i to j, then it is feasible for me to go from i to j and from j to i, which is understandable Become e[i][j]==e[j][i];
After talking about directed & undirected graphs, it comes to the issue of right and no right. Before talking about this, let’s talk about how Use a two-dimensional array to store edge weights or the '0' '1' mentioned earlier?
As we all know, the writing method of a two-dimensional array is a[i][j], then we assume that there is a side with a side weight of 4 from the second side to the third side, then we can use e[2][
3 ] stores a value of 4, if we want to check which side it points to which side, can we just use double for loops to look at its i and j values. Just like the picture below.

#include<iostream>
using namespace std;
int main()
{
    
    
	int m;
	int u,v,w;
	int e[10][10];
	for(int i=0;i<m;i++)
	{
    
    
		cin>>u>>v>>w;
		e[u][v]=w;
	}
	return 0;
}

In the above code, we can see that our two points are the basis for finding its edge weight. If you want to query the edge weight of 2-3 in the title, you can directly output
e[2][3]. Of course, this is just the code for directed and weighted graphs. For undirected and weighted graphs, you only need to build an edge in reverse after e[u][v]=w.
After talking about the graph with weights, how to write the graph without weights?
Our idea is that if there is an edge from the point ij, then we assign the value of e[i][j] to 1. After inputting it once, we traverse the e array again, and all the values ​​in it are not 1. The dot means that there is no edge from ij, so the values ​​​​without edges in the middle are all assigned to 0.
Because there is no code here, i and j have been mentioned many times. Students who do not understand can see the code explanation below.

#include<iostream>
using namespace std;
const int N=10005;
int e[N][N];
int main()
{
    
    
	int m;//m条边
	for(int i=0;i<m;i++)
	{
    
    
		int u,v;//说明从u-v有一条边
		e[u][v]=1;//其值赋为1
	}
	for(int i=1;i<=m;i++)
	{
    
    
		for(int j=1;j<=m;j++)
		{
    
    
			if(e[i][j]!=1) e[i][j]=0;//!=1说明之前没有输入过,说明i-j没有边,赋为0;
		}
	}
	return 0;
}

The processing method of the unweighted undirected graph is roughly the same as the processing method of the weighted undirected graph before, so I won’t go into details here.

3. Adjacency list

The adjacency list is good at storing sparse graphs. It is mainly used to replace the adjacency matrix to store some graphs that would consume a lot of space complexity with the adjacency matrix. . . Based on my own problem-solving experience, unless it is very disgusting, I will not get stuck in space, as long as it is enough to use an adjacency matrix.
If the follow-up understanding is thorough, update another issue.

It's not easy to create, please don't go whoring for nothing www! Please give the author a like + triple! thanks~

Guess you like

Origin blog.csdn.net/2301_76331300/article/details/131852295