Estructura de datos ------ profundidad primer recorrido

Figura

Por que usar gráficos

La tabla lineal se limita a la relación entre un predecesor directo y un sucesor directo. El
árbol solo puede tener un predecesor directo, que es el nodo padre.
Cuando necesitamos expresar una relación de muchos a muchos, aquí usamos un gráfico .

En otras palabras, el gráfico puede representar la relación entre muchos a muchos

Un gráfico es una estructura de datos en la que un nodo puede tener cero o más elementos adyacentes . La conexión entre dos nodos se llama borde . Los nodos también se pueden llamar vértices.

Conceptos comunes

1. El vértice es nuestro nodo

2. Conexión de borde entre nuestros nodos vecinos

3. ¿Cuántas formas hay de conectarse entre los nodos de ruta?

4. Gráfico no dirigido

Inserte la descripción de la imagen aquí

5. Una gráfica dirigida tiene direcciones en los bordes.

6. Gráficos ponderados con gráficos valorados

Representación

1. Matriz de adyacencia de representación de matriz bidimensional

2. La lista vinculada representa la lista de adyacencia.

Inserte la descripción de la imagen aquí

Descubrimos que muchos lugares no tienen sentido y desperdician espacio

Inserte la descripción de la imagen aquí

Inicio rápido

Inserte la descripción de la imagen aquí

Código

package;

import java.util.ArrayList;
import java.util.Arrays;

public class Graph {
    
    
	private ArrayList<String> vertexList;   //存储顶点集合
	private int[][] edges; //存储图对应的邻接矩阵
	private int numOfEdges;  //表示边的数目
	
	public static void main(String[] args) {
    
    
		int n = 5;   //节点的个数
		String VertexValue[] = {
    
    "A","B","C","D","E"};
		//创建图对象
		Graph graph = new Graph(n);
		//循环添加顶点
		for(String value : VertexValue){
    
    
			graph.insertVertex(value);
		}
		//添加边
		// A-B  A-C  B-C  B-D   B-E
		graph.insertEdge(0, 1, 1);
		graph.insertEdge(0, 2, 1);
		graph.insertEdge(1, 2, 1);
		graph.insertEdge(1, 3, 1);
		graph.insertEdge(1, 4, 1);
		//输出邻接矩阵
		graph.showGraph();
	}
	
	//构造器
	public Graph(int n){
    
    
		//初始化矩阵和vertexList
		edges = new int[n][n];
		vertexList = new ArrayList<String>(n);
		numOfEdges = 0;
	}
	//插入节点
	public void insertVertex(String vertex){
    
    
		vertexList.add(vertex);
	}
	//添加边
	/**
	 * 
	 * @param v1	表示第一个顶点的下标即是第几个顶点
	 * @param v2	第一个顶点的下标
	 * @param weight	表示值是不是1即有没有连接起来
	 */
	public void insertEdge(int v1,int v2,int weight){
    
    
		edges[v1][v2] = weight;
		edges[v2][v1] = weight;
		numOfEdges++;
	}
	//返回节点的个数
	public int getNumOfVertex(){
    
    
		return vertexList.size();
	}
	//返回边的数目
	public int getNumOfEdges(){
    
    
		return numOfEdges;
	}
	//返回节点i对应的数据
	public String getValueByIndex(int i){
    
    
		return vertexList.get(i);
	}
	//返回v1和v2的权值
	public int getWeight(int v1,int v2){
    
    
		return edges[v1][v2];
	}
	//显示图对应的矩阵
	public void showGraph(){
    
    
		for (int[] link : edges) {
    
    
			System.err.println(Arrays.toString(link));
		}
	}
}

Travesía en profundidad primero

Idea básica

Recorrido de profundidad primero, comenzando desde el nodo de acceso inicial , el nodo de acceso inicial puede tener múltiples nodos adyacentes. La estrategia de recorrido de profundidad primero es visitar primero el primer nodo adyacente y luego usar este nodo adyacente visitado como el nodo A inicial , visitando su primer nodo adyacente, se puede entender de la siguiente manera: cada vez que se visita el nodo actual, primero se visita el primer nodo adyacente del nodo actual .
Podemos ver que dicha estrategia de acceso prioriza la excavación en profundidad verticalmente, en lugar de acceder horizontalmente a todos los nodos adyacentes de un nodo.
Obviamente, la búsqueda en profundidad es un proceso recursivo

paso

1. Visite el nodo inicial v y marque que el nodo v ha sido visitado.

2. Encuentre el primer nodo adyacente W del nodo V

3. Si W existe, vaya al paso 4, si w no existe, vuelva al paso 1 y continúe desde el siguiente nodo de v.

4. Si no se ha visitado w, realice una recursividad transversal en profundidad en w (es decir, trate w como otro v y luego continúe con el paso 123).

5. Encuentre el siguiente nodo adyacente del W nodo adyacente del nodo v, y vaya al paso 3

package;

import java.util.ArrayList;
import java.util.Arrays;

public class Graph {
    
    
	private ArrayList<String> vertexList;   //存储顶点集合
	private int[][] edges; //存储图对应的邻接矩阵
	private int numOfEdges;  //表示边的数目
	//定义一个boolean[]  记录某个点是否被访问过
	private boolean[] isVisited;
	public static void main(String[] args) {
    
    
		int n = 5;   //节点的个数
		String VertexValue[] = {
    
    "A","B","C","D","E"};
		//创建图对象
		Graph graph = new Graph(n);
		//循环添加顶点
		for(String value : VertexValue){
    
    
			graph.insertVertex(value);
		}
		//添加边
		// A-B  A-C  B-C  B-D   B-E
		graph.insertEdge(0, 1, 1);
		graph.insertEdge(0, 2, 1);
		graph.insertEdge(1, 2, 1);
		graph.insertEdge(1, 3, 1);
		graph.insertEdge(1, 4, 1);
		//输出邻接矩阵
		graph.showGraph();
		System.out.println("深度遍历");
		graph.dfs();
		
	}
	
	//构造器
	public Graph(int n){
    
    
		//初始化矩阵和vertexList
		edges = new int[n][n];
		vertexList = new ArrayList<String>(n);
		numOfEdges = 0;
		isVisited = new boolean[5];
	}
	//得到第一个邻接节点的下标
	public int getFirstNeighbor(int index){
    
    
		for (int i = 0; i < vertexList.size(); i++) {
    
    
			if(edges[index][i] > 0){
    
    
				return i;
			}
		}
		return -1;
	}
	//根据前一个邻接节点的下标,来获取下一个邻接节点的下标
	public int getNextNeighbor(int v1,int v2){
    
    
		for(int j = v2+1;j<vertexList.size();j++){
    
    
			if(edges[v1][j] > 0){
    
    
				return j;
			}
		}
		return -1;
	}
	//深度优先遍历算法
	public void dfs(boolean[] isVisited,int i){
    
    
		//首先访问该节点
		System.out.println(getValueByIndex(i)+"->");
		//将该节点设置为已访问
		isVisited[i] = true;
		//查找节点i的邻接节点
		int w = getFirstNeighbor(i);
		while(w!=-1){
    
    //有邻接节点
			if(!isVisited[w]){
    
    
				dfs(isVisited,w);
			}
			//如果已经被访问过
			w = getNextNeighbor(i, w);
		}
	}
	//对dfs重载,遍历所有节点,并进行dfs
	public void dfs(){
    
    
		for(int i=0;i<getNumOfVertex();i++){
    
    
			if(!isVisited[i]){
    
    
				dfs(isVisited,i);
			}
		}
	}
	//插入节点
	public void insertVertex(String vertex){
    
    
		vertexList.add(vertex);
	}
	//添加边
	/**
	 * 
	 * @param v1	表示第一个顶点的下标即是第几个顶点
	 * @param v2	第一个顶点的下标
	 * @param weight	表示值是不是1即有没有连接起来
	 */
	public void insertEdge(int v1,int v2,int weight){
    
    
		edges[v1][v2] = weight;
		edges[v2][v1] = weight;
		numOfEdges++;
	}
	//返回节点的个数
	public int getNumOfVertex(){
    
    
		return vertexList.size();
	}
	//返回边的数目
	public int getNumOfEdges(){
    
    
		return numOfEdges;
	}
	//返回节点i对应的数据
	public String getValueByIndex(int i){
    
    
		return vertexList.get(i);
	}
	//返回v1和v2的权值
	public int getWeight(int v1,int v2){
    
    
		return edges[v1][v2];
	}
	//显示图对应的矩阵
	public void showGraph(){
    
    
		for (int[] link : edges) {
    
    
			System.err.println(Arrays.toString(link));
		}
	}
}

Amplitud primer recorrido

Idea básica

De manera similar a un proceso de búsqueda jerárquica, el recorrido en amplitud requiere el uso de una cola para mantener el orden de los nodos visitados, de modo que los nodos adyacentes de estos nodos se puedan visitar en este orden.

paso

  1. Visite el asentamiento inicial y marque el nodo v como visitado.
  2. Cuando el nodo ingrese a la cola
    3, cuando la cola no esté vacía, continuar con la ejecución (el algoritmo finaliza cuando la fragancia es incienso).
  3. Salga de la cola y obtenga el nodo principal u.
  4. Encuentre el segundo nodo adyacente w del nodo u.
  5. Si el nodo adyacente w del punto de aterrizaje u no existe, vaya al paso 3; de lo contrario, los siguientes tres pasos se realizan en un bucle:
    6.1 Si el nodo w aún no se ha visitado, el nodo w se visita y se marca como visitado.
    6.2 El nodo w entra en la cola
    6.3 Encuentre el siguiente nodo adyacente w que sigue al nodo adyacente w del nodo u, y vaya al paso 6.

Código

Simplemente publique nuestro código de método directamente aquí

	//广度优先遍历
	private void bfs(boolean[] isVisited, int i){
    
    
		int u;   //表示队列头结点的下标
		int w;	 //邻接节点的下标
		//需要一个队列,记录节点访问的顺序
		LinkedList queue = new LinkedList();
		//访问节点,输出节点信息
		System.out.print(getValueByIndex(i)+"->");
		//标记已访问
		isVisited[i] = true;
		//将节点加入队列
		queue.addLast(i);
		while(!queue.isEmpty()){
    
    
			//取出队列的头结点下标
			u = (Integer)queue.removeFirst();
			//得到第一个邻接节点的下标
			w = getFirstNeighbor(u);
			while(w != -1){
    
    
				//找到了   是否访问过
				if(!isVisited[w]){
    
    
					System.out.print(getValueByIndex(w)+"->");
					isVisited[w] = true;
					//入队
					queue.addLast(w);
				}
				//以u为前驱点,找w后面的下一个邻接节点
				w = getNextNeighbor(u, w);//体现出广度优先遍历	
			}
		}
	}
	//对所有节点进行广度优先搜索
	public void bfs(){
    
    
		for(int i=0;i<getNumOfVertex();i++){
    
    
			if(!isVisited[i]){
    
    
				bfs(isVisited, i);
			}
		}
	}
广度优先遍历
[0, 1, 1, 0, 0]
[1, 0, 1, 1, 1]
[1, 1, 0, 0, 0]
[0, 1, 0, 0, 0]
[0, 1, 0, 0, 0]
A->B->C->D->E->

La diferencia entre los dos métodos transversales

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_22155255/article/details/113858619
Recomendado
Clasificación