[Data structure] Graph creation and depth (DFS) breadth (BFS) first traversal

1. Figure

1. The concept of graph

A graph is composed of a finite non-empty set of vertices and a set of edges between vertices, expressed as G(V,E), where G denotes a graph, V is the set of vertices in graph G, and E is the set of vertices in graph G. A collection of edges .

2. Types of graphs

Graphs are divided into undirected graphs and directed graphs

Undirected graph: If the edge between the vertices Vi and Vj has no direction, this edge is called an undirected edge (Edge), and it is represented by an order pair (Vi, Vj).

Directed graph: If the edge from vertex Vi to Vj is directional, then this edge is a directed edge, also known as an arc (Arc). Marked by an ordered pair (Vi, Vj), Vi is called the arc tail, and Vj is called the arc head. If there is a direction between any two edges, the graph is called a directed graph.

Undirected graph:

ed4d5b49293142e4b45ceec6ea69eaf3.png

 Directed graph:

2ad05866ec784190804e4c005ec24c72.png

Second, the creation of the graph (adjacency matrix)

Use the information of the vertices in the one-dimensional array graph, and use a two-dimensional array to store the information of the edges in the graph (the adjacency relationship between each vertex). A two-dimensional array that stores the adjacency relationship between vertices is called an adjacency matrix. The adjacency matrix A of the graph G=(V,E) with n nodes is n*n, and the vertices of G are numbered as v1, v2,...vn. If (vi, vj)∈E, then A[i][j]=1, otherwise A[i][j]=0.

The adjacency matrix is ​​used to store edges. If two vertices are connected by an edge, then their corresponding values ​​in the adjacency matrix are 1, otherwise they are 0.

Just like A and B are connected by an edge, then their corresponding value is one, and A and A have no edge, then it is zero

1. Schematic diagram of adjacency matrix

0d955af480b44fcc957bb139fa58e728.png

 The conclusions obtained through the adjacency matrix:

  • The matrix is ​​symmetric and can be stored compressively (upper (lower) triangular) ;
  • The number of 1s in the i-th row or i- th column is the degree of vertex i ;
  • Half of the number of 1s in the matrix is ​​the number of edges in the graph ;
  • It is easy to judge whether there is an edge between vertex i and vertex j ( see whether the value of row i and column j in the matrix is ​​1) .

Advantages of the adjacency matrix method :

It is easy to implement graph operations, such as finding the degree of a vertex, judging whether there is an edge (arc) between vertices, finding the adjacent points of vertices, etc.

Disadvantages of adjacency matrix method:

n vertices require n^2 cells to store edges (arcs); space efficiency is O(n^2). Suitable for storing dense graphs, waste space for sparse graphs.

2. First create the structure of the graph

typedef struct
{
	char* vexs;//存放顶点的数组
	int** arcs;//存放边的二维数组
	int vexsnum;//顶点个数
	int arcsnum;//边的数目
}graph;

3. Initialization diagram

First apply for the nodes of the related array

graph* InitGraph(int vexsnum)
{
	graph* g = new graph; //申请一个图结构体的节点
	
	g->vexs = new char[vexsnum];//申请顶点个数大小的数组
	
	g->arcs = new int* [vexsnum];//申请顶点个数大小的二维数组
	
	for (int i = 0; i < vexsnum; ++i)
	{
		g->arcs[i] = new int [vexsnum];  //给二维数组中的元素申请一个数组
		
	}
	g->vexsnum = vexsnum;
	g->arcsnum = 0;
	return g;
}

4. Create a graph

Where vexs represents an array of vertex elements, and arcs represents a two-dimensional array storing edges

void CreateGraph(graph* g,char* vexs,int* arcs)
{
	for (int i = 0; i < g->vexsnum; ++i)
	{
		g->vexs[i] = vexs[i]; //将顶点存入存放顶点的数组中
	}

	for ( int i = 0; i < g->vexsnum; ++i)
	{
		for (int j = 0; j < g->vexsnum; ++j)
		{
			g->arcs[i][j] = *(arcs+i*g->vexsnum+j);//将传入的二维数组赋值给图结构体中的二维数组
			if (g->arcs[i][j] != 0)
			{
				++g->arcsnum;//判断边的个数
			}
		}
	}
	g->arcsnum /= 2;//得到有效边的个数
}

g->arcs[i][j] = *(arcs+i*g->vexsnum+j); This statement assigns the arcs one-dimensional array to g->arcs two-dimensional array

g->arcsnum /= 2; The reason for dividing by two:

When judging the number of edges, each vertex has judged how many edges the vertex has, so the judgment is repeated

Need to divide by two to get the number of real edges

3. Depth-first traversal and breadth-first traversal

3.1 The main idea of ​​depth-first traversal:

Starting from an unvisited vertex V in the graph, go all the way to the end along one road, then return to the previous node from the node at the end of this road, and then go to the end from another road..., repeating this process recursively, Until all the vertices are traversed, its characteristic is that it does not hit the south wall and does not look back. It finishes one path first, and then continues on another path.

Just like the preorder traversal in a binary tree, first visit the root, the left subtree, and then the right subtree

bf1fd80c6d8e489e877b359b5622a346.png

 Just like the pre-order access of the binary tree above, don't turn back if you don't hit the south wall

3.2 Depth-first traversal of graphs

visited represents a one-dimensional array used to mark the visited nodes

index indicates from which vertex to start accessing

void DFS(graph*g, int* visited, int index)
{
	printf("%c ", g->vexs[index]);

	visited[index] = 1;//标记已经被访问过的顶点

	for (int i = 0; i < g->vexsnum; ++i)
	{
        //判断如果有边且该顶点没有被访问过,则可以访问
		if (g->arcs[index][i] == 1 && !visited[i])
		{
			DFS(g, visited, i);//递归访问
		}
	}
}

3.3 The main idea of ​​breadth-first traversal:

Starting from a certain node (source point), visit all unvisited adjacent points at one time, and then start from these visited adjacent points in turn, visit layer by layer. As shown in the figure below, breadth-first traversal traverses the graph in the way of breadth-first search.

871f5ca560774dfa9a0e5822d8b8f367.pngBy looking at the adjacency matrix on the right, we can find that starting from point A, the first line is actually finished first, then the line corresponding to B, then the line corresponding to D, then the line corresponding to C, and finally The line corresponding to E

373f43cddcf7455c8d97446de3eb10db.png

Starting from point B, through the adjacency matrix, it can be found that the line corresponding to B is actually finished first, then the line corresponding to A, then the line corresponding to C, then the line corresponding to D, and finally go The line corresponding to E

3.4 Breadth-first traversal of graphs

 Breadth-first traversal is like the number of layers in a binary tree, one layer at a time.

From the above example, it can be found that the graph is also completed layer by layer, but it is not in order, but in the line that visits first.

With this idea, it is obvious that we can use the queue to implement it at this time, put the visited vertex into the queue, and then wait for the adjacent vertices of the vertex to be visited, then go out of the queue to visit the dequeued vertex and its adjacent vertex, repeat the above steps in turn until the queue is empty

void BFS(graph*g,int* visited, int index)
{
	queue<int> q;
	printf("%c ", g->vexs[index]);
	visited[index] = 1;//标记
	q.push(index);//入队
	while (!q.empty())
	{
		int top = q.front();//出队
		q.pop();
		for (int i = 0; i < g->vexsnum; ++i)
		{
			if (g->arcs[top][i] == 1 && !visited[i])
			{
				printf("%c ", g->vexs[i]);
				visited[i] = 1;
				q.push(i);
			}
		}
	}
}

3.5 Implementation code of the graph

#include<iostream>
#include<queue>
using namespace std;

#define N 5  //N表示图的节点个数

typedef struct
{
	char* vexs;
	int** arcs;
	int vexsnum;
	int arcsnum;
}graph;

graph* InitGraph(int vexsnum)
{
	graph* g = new graph; //申请一个图结构体的节点
	
	g->vexs = new char[vexsnum];//申请顶点个数大小的数组
	
	g->arcs = new int* [vexsnum];//申请顶点个数大小的二维数组
	
	for (int i = 0; i < vexsnum; ++i)
	{
		g->arcs[i] = new int [vexsnum];  //给二维数组中的元素申请一个数组
		
	}
	g->vexsnum = vexsnum;
	g->arcsnum = 0;
	return g;
}

void CreateGraph(graph* g,char* vexs,int* arcs)
{
	for (int i = 0; i < g->vexsnum; ++i)
	{
		g->vexs[i] = vexs[i]; //将顶点存入存放顶点的数组中
	}

	for ( int i = 0; i < g->vexsnum; ++i)
	{
		for (int j = 0; j < g->vexsnum; ++j)
		{
		  g->arcs[i][j] = *(arcs+i*g->vexsnum+j);//将传入的二维数组赋值给图结构体中的二维数组
			if (g->arcs[i][j] != 0)
			{
				++g->arcsnum;//判断边的个数
			}
		}
	}
	g->arcsnum /= 2;//得到有效边的个数,
}

void DFS(graph*g, int* visited, int index)
{
	printf("%c ", g->vexs[index]);
	visited[index] = 1;
	for (int i = 0; i < g->vexsnum; ++i)
	{
		if (g->arcs[index][i] == 1 && !visited[i])
		{
			DFS(g, visited, i);
		}
	}
}

void BFS(graph*g,int* visited, int index)
{
	queue<int> q;
	printf("%c ", g->vexs[index]);
	visited[index] = 1;//标记
	q.push(index);//入队
	while (!q.empty())
	{
		int top = q.front();//出队
		q.pop();
		for (int i = 0; i < g->vexsnum; ++i)
		{
			if (g->arcs[top][i] == 1 && !visited[i])
			{
				printf("%c ", g->vexs[i]);
				visited[i] = 1;
				q.push(i);
			}
		}
	}
}

int main()
{
	graph* g = InitGraph(N);//初始化图
	char vexs[] = {'A','B','C','D','E'};//顶点元素
	int visited[N] = { 0 };//用来标记的数组
	int arcs[N][N] =
	{
		0,1,0,1,0,
		1,0,1,1,0,
		0,1,0,1,1,
		1,1,1,0,1,
		0,0,1,1,0
	};//邻接矩阵

	CreateGraph(g, vexs, (int*)arcs);//创建图

	DFS(g, visited, 0);//深度优先遍历
	printf("\n");

	memset(visited, 0, sizeof(int) * N);//将标记数组重新置为0

	BFS(g, visited, 1);//广度优先遍历
	return 0;
}

The knowledge about the picture is shared here, thank you for your support!

Guess you like

Origin blog.csdn.net/m0_72532428/article/details/130641194