图的遍历(Java)构造器

图的遍历

一、DFS(Depth First Search)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200321001951462.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0c
概念:
从初始访问点出发,访问其第一个邻接节点;然后把这个邻接节点作为初始节点,继续访问它的第一个邻接节点。

即每次都在访问完当前节点过后,访问它的第一个邻接节点。

算法:

  1. 访问初始节点v(下标),并标记v已被访问;
  2. 查找节点v的第一个邻接节点w(下标);
  3. 如果w存在,则继续4步骤;如果w不存在,则返回1步骤;
  4. 如果w未被访问过,对w进行dfs递归操作(重复123操作);
  5. 查找节点v的w邻接节点的下一个邻接节点,返回3步骤

源代码如下:

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

public class graph {

	private ArrayList<String> vertexList;// 定义顶点列表
	private int[][] edges;// 存储图对应的邻接矩阵
	private int numOfEdges;// 存储边
	private boolean isVisited[];// 标记顶点是否已被访问

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 测试图
		int n = 5;// 定义顶点个数
		String vertexs[] = { "A", "B", "C", "D", "E" };
		// 创建图对象
		graph graph = new graph(n);
		// 循环添加顶点
		for (String vertex : vertexs) {// 每次循环从vertexValue取出来一个值(定义为value)
			graph.insertVertex(vertex);// 把顶点加进去
		}
		// 添加边
		// A-B A-C B-C B-D B-E
		// 权值默认为是1
		graph.insertEdges(0, 1, 1);// A-B
		graph.insertEdges(0, 2, 1);// A-C
		graph.insertEdges(1, 2, 1);// B-C
		graph.insertEdges(1, 3, 1);// B-D
		graph.insertEdges(1, 4, 1);// B-E
		// 显示邻接矩阵
		graph.show();

		// DFS
		graph.dfs();

	}

	// ————————————--------------------------------------------------------
	// 首先定义图的属性
	// 1.构造器
	public graph(int n) {// 首先要传入顶点的数目
		// 初始化矩阵和vertexList
		edges = new int[n][n];
		vertexList = new ArrayList<String>();// 初始化顶点列表
		numOfEdges = 0;// 可省略,因为默认为0
		isVisited = new boolean[5];

	}

	// 2.插入顶点
	public void insertVertex(String vertex) {
		vertexList.add(vertex);
	}

	// 3.设置边
	/**
	 * 
	 * @param v1     第一个顶点的下标
	 * @param v2     第二个顶点的下标
	 * @param weight 权值
	 */
	public void insertEdges(int v1, int v2, int weight) {
		// 这里是定义无向图,所以两个方向都要定义
		edges[v1][v2] = weight;
		edges[v2][v1] = weight;
		numOfEdges++;
	}

	// 4.返回顶点个数
	public int getnumOfVertexs() {
		return vertexList.size();
	}

	// 5.返回边个数
	public int getnumOfEdges() {
		return numOfEdges;
	}

	// 6.返回顶点i(顶点的下标)的对应的数据
	/**
	 * 
	 * @param i返回数据下标
	 * @return 返回数据 例:0->A 1->B 2->C 3->D 4->E
	 */
	public String getValueByIndex(int i) {
		return vertexList.get(i);
	}

	// 7.返回v1,v2两顶点之间的权值
	public int getWeight(int v1, int v2) {
		return edges[v1][v2];
	}

	// 8.打印邻接矩阵(本质:遍历图)
	public void show() {
		for (int[] link : edges) {
			System.out.println(Arrays.toString(link));
		}
	}
//————————————--------------------------------------------------------	

	// DFS算法步骤

	// 1.得到第一个邻接节点下标w
	/**
	 * 
	 * @param index
	 * @return 如果存在就返回它的下标,没有就返回-1
	 */
	public int getFirstNerghborIndex(int index) {// 传入当前节点的下标index
		for (int w = 0; w < vertexList.size(); w++) {
			if (edges[index][w] > 0) {// 如果下一个邻接节点存在
				return w;// 返回它的下标
			}
		}
		return -1;// 没有返回就返回-1
	}

	// 2.根据前一个邻接节点的下标来获取下一个邻接节点
	/**
	 * 
	 * @param v1
	 * @param v2
	 * @return
	 */
	public int getNextNeighbor(int v1, int v2) {
		for (int w = v2 + 1; w < vertexList.size(); w++) {
			if (edges[v1][w] > 0) {
				return w;
			}
		}
		return -1;
	}

	// 3.开始深搜遍历
	public void dfs(boolean[] isVisited, int i) {// 判断是否遍历过的标记,定义节点下标
		// 首先访问当前节点,输出
		System.out.print(getValueByIndex(i) + "->");
		// 访问过后,要标记节点已访问
		isVisited[i] = true;
		// 查找节点i的第一个邻接节点
		int w = getFirstNerghborIndex(i);
		while (w != -1) {// 存在
			if (!isVisited[w]) {// 如果没有被标记过
				dfs(isVisited, w);// 以w为初始节点重新开始,递归操作dfs
			}
			// 如果已经被访问过
			w = getNextNeighbor(i, w);
		}
	}

	// 对dfs进行重载,遍历所有节点
	public void dfs() {
		for (int i = 0; i < getnumOfVertexs(); i++) {
			while (!isVisited[i]) {// 如果没被访问过
				dfs(isVisited, i);
			}
		}
	}
}

二、BFS(Broad First Search)

.addLast()获取最后一个节点

在这里插入图片描述
概念:
类似一个分层搜索过程,BFS需要一个队列以保持访问过节点的顺序,以便按照这个顺序来访问他们的邻接节点。

算法:

  1. 访问初始节点v,并将其标记已经访问;
  2. 把节点v加入队列;
  3. 当队列非空时,继续执行,否则算法结束;
  4. 出队列,取得队头结点u;
  5. 查找初始节点也是队头结点u第一个邻接节点w;
  6. 若节点u的第一个邻接节点w不存在,执行步骤3,否则循环执行下述三个操作:
    (1)若节点w未被访问,访问它并标记已经访问;
    (2)节点w入队列;
    (3)查找节点u的继w邻接节点后的下一个邻接节点,转到步骤6

源代码如下:

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

public class graph {

	private ArrayList<String> vertexList;// 定义顶点列表
	private int[][] edges;// 存储图对应的邻接矩阵
	private int numOfEdges;// 存储边
	private boolean isVisited[];// 标记顶点是否已被访问

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 测试图
		int n = 5;// 定义顶点个数
		String vertexs[] = { "A", "B", "C", "D", "E" };
		// 创建图对象
		graph graph = new graph(n);
		// 循环添加顶点
		for (String vertex : vertexs) {// 每次循环从vertexValue取出来一个值(定义为value)
			graph.insertVertex(vertex);// 把顶点加进去
		}
		// 添加边
		// A-B A-C B-C B-D B-E
		// 权值默认为是1
		graph.insertEdges(0, 1, 1);// A-B
		graph.insertEdges(0, 2, 1);// A-C
		graph.insertEdges(1, 2, 1);// B-C
		graph.insertEdges(1, 3, 1);// B-D
		graph.insertEdges(1, 4, 1);// B-E
		// 显示邻接矩阵
		graph.show();
		/*// DFS
		System.out.println();
		System.out.println("DFS:");
		graph.dfs();
        */
		System.out.println();
		System.out.println();
		System.out.println("BFS:");
		graph.bfs();

	}

	// ————————————--------------------------------------------------------
	// 首先定义图的属性
	// 1.构造器
	public graph(int n) {// 首先要传入顶点的数目
		// 初始化矩阵和vertexList
		edges = new int[n][n];
		vertexList = new ArrayList<String>();// 初始化顶点列表
		numOfEdges = 0;// 可省略,因为默认为0
		isVisited = new boolean[vertexList.size() + 1];

	}

	// 2.插入顶点
	public void insertVertex(String vertex) {
		vertexList.add(vertex);
	}

	// 3.设置边
	/**
	 * 
	 * @param v1     第一个顶点的下标
	 * @param v2     第二个顶点的下标
	 * @param weight 权值
	 */
	public void insertEdges(int v1, int v2, int weight) {
		// 这里是定义无向图,所以两个方向都要定义
		edges[v1][v2] = weight;
		edges[v2][v1] = weight;
		numOfEdges++;
	}

	// 4.返回顶点个数
	public int getnumOfVertexs() {
		return vertexList.size();
	}

	// 5.返回边个数
	public int getnumOfEdges() {
		return numOfEdges;
	}

	// 6.返回顶点i(顶点的下标)的对应的数据
	/**
	 * 
	 * @param i返回数据下标
	 * @return 返回数据 例:0->A 1->B 2->C 3->D 4->E
	 */
	public String getValueByIndex(int i) {
		return vertexList.get(i);
	}

	// 7.返回v1,v2两顶点之间的权值
	public int getWeight(int v1, int v2) {
		return edges[v1][v2];
	}

	// 8.打印邻接矩阵(本质:遍历图)
	public void show() {
		for (int[] link : edges) {
			System.out.println(Arrays.toString(link));
		}
	}
//————————————--------------------------------------------------------	

	// DFS算法步骤

	// 1.得到第一个邻接节点下标w
	/**
	 * 
	 * @param index
	 * @return 如果存在就返回它的下标,没有就返回-1
	 */
	public int getFirstNerghborIndex(int index) {// 传入当前节点的下标index
		for (int w = 0; w < vertexList.size(); w++) {
			if (edges[index][w] > 0) {// 如果下一个邻接节点存在
				return w;// 返回它的下标
			}
		}
		return -1;// 没有返回就返回-1
	}

	// 2.根据前一个邻接节点的下标来获取下一个邻接节点
	/**
	 * 
	 * @param v1为前驱点
	 * @param v2为前驱点的当前邻接节点
	 * @return
	 */
	public int getNextNeighbor(int v1, int v2) {
		for (int w = v2 + 1; w < vertexList.size(); w++) {
			if (edges[v1][w] > 0) {
				return w;
			}
		}
		return -1;
	}

	// 3.开始深搜遍历
	private void dfs(boolean[] isVisited, int i) {// 判断是否遍历过的标记,定义节点下标
		// 首先访问当前节点,输出
		System.out.print(getValueByIndex(i) + "->");
		// 访问过后,要标记节点已访问
		isVisited[i] = true;
		// 查找节点i的第一个邻接节点
		int w = getFirstNerghborIndex(i);
		while (w != -1) {// 存在
			if (!isVisited[w]) {// 如果没有被标记过
				dfs(isVisited, w);// 以w为初始节点重新开始,递归操作dfs
			}
			// 如果已经被访问过
			// 以u为前驱点,找w的下一个邻接节点
			// w为辅助变量,每次进行此操作的时候更新值
			w = getNextNeighbor(i, w);
		}
	}

	// 对dfs进行重载,遍历所有节点
	public void dfs() {
		for (int i = 0; i < getnumOfVertexs(); i++) {
			while (!isVisited[i]) {// 如果没被访问过
				dfs(isVisited, i);
			}
		}
	}

	// ————————————--------------------------------------------------------
	// BFS算法步骤
	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
			w = getFirstNerghborIndex(u);
			while (w != -1) {// 找到邻接节点
				// 判断是否访问过
				if (!isVisited[w]) {// 如果没有访问过
					System.out.print(getValueByIndex(w) + "->");// 访问
					isVisited[w] = true;// 标记为已访问
					// 邻接节点入队列
					queue.addLast(w);
				}
				// 以u为前驱点,访问w的下一个邻接节点
				w = getNextNeighbor(u, w);
			}
		}
	}

	// 对bfs进行重载,遍历所有节点
	public void bfs() {
		for (int i = 0; i < getnumOfVertexs(); i++) {
			while (!isVisited[i]) {// 如果没被访问过
				bfs(isVisited, i);
			}
		}
	}
}

如果要同时显示DFS和BFS遍历结果,需将构造器中的初始化部分摘出来,分别放到DFS和BFS的重载方法里,每次调用时重新分配,就不会出现执行完一种遍历无法执行第二种遍历的情况。

代码如下:

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

public class graph {

	private ArrayList<String> vertexList;// 定义顶点列表
	private int[][] edges;// 存储图对应的邻接矩阵
	private int numOfEdges;// 存储边
	private boolean isVisited[];// 标记顶点是否已被访问

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 测试图
		int n = 5;// 定义顶点个数
		String vertexs[] = { "A", "B", "C", "D", "E" };
		// 创建图对象
		graph graph = new graph(n);
		// 循环添加顶点
		for (String vertex : vertexs) {// 每次循环从vertexValue取出来一个值(定义为value)
			graph.insertVertex(vertex);// 把顶点加进去
		}
		// 添加边
		// A-B A-C B-C B-D B-E
		// 权值默认为是1
		graph.insertEdges(0, 1, 1);// A-B
		graph.insertEdges(0, 2, 1);// A-C
		graph.insertEdges(1, 2, 1);// B-C
		graph.insertEdges(1, 3, 1);// B-D
		graph.insertEdges(1, 4, 1);// B-E
		// 显示邻接矩阵
		graph.show();
		// DFS
		System.out.println();
		System.out.println("DFS:");
		graph.dfs();
		System.out.println();
		System.out.println();
		System.out.println("BFS:");
		graph.bfs();

	}

	// ————————————--------------------------------------------------------
	// 首先定义图的属性
	// 1.构造器
	public graph(int n) {// 首先要传入顶点的数目
		// 初始化矩阵和vertexList
		edges = new int[n][n];
		vertexList = new ArrayList<String>();// 初始化顶点列表
		numOfEdges = 0;// 可省略,因为默认为0

	}

	// 2.插入顶点
	public void insertVertex(String vertex) {
		vertexList.add(vertex);
	}

	// 3.设置边
	/**
	 * 
	 * @param v1     第一个顶点的下标
	 * @param v2     第二个顶点的下标
	 * @param weight 权值
	 */
	public void insertEdges(int v1, int v2, int weight) {
		// 这里是定义无向图,所以两个方向都要定义
		edges[v1][v2] = weight;
		edges[v2][v1] = weight;
		numOfEdges++;
	}

	// 4.返回顶点个数
	public int getnumOfVertexs() {
		return vertexList.size();
	}

	// 5.返回边个数
	public int getnumOfEdges() {
		return numOfEdges;
	}

	// 6.返回顶点i(顶点的下标)的对应的数据
	/**
	 * 
	 * @param i返回数据下标
	 * @return 返回数据 例:0->A 1->B 2->C 3->D 4->E
	 */
	public String getValueByIndex(int i) {
		return vertexList.get(i);
	}

	// 7.返回v1,v2两顶点之间的权值
	public int getWeight(int v1, int v2) {
		return edges[v1][v2];
	}

	// 8.打印邻接矩阵(本质:遍历图)
	public void show() {
		for (int[] link : edges) {
			System.out.println(Arrays.toString(link));
		}
	}
//————————————--------------------------------------------------------	

	// DFS算法步骤

	// 1.得到第一个邻接节点下标w
	/**
	 * 
	 * @param index
	 * @return 如果存在就返回它的下标,没有就返回-1
	 */
	public int getFirstNerghborIndex(int index) {// 传入当前节点的下标index
		for (int w = 0; w < vertexList.size(); w++) {
			if (edges[index][w] > 0) {// 如果下一个邻接节点存在
				return w;// 返回它的下标
			}
		}
		return -1;// 没有返回就返回-1
	}

	// 2.根据前一个邻接节点的下标来获取下一个邻接节点
	/**
	 * 
	 * @param v1
	 * @param v2
	 * @return
	 */
	public int getNextNeighbor(int v1, int v2) {
		for (int w = v2 + 1; w < vertexList.size(); w++) {
			if (edges[v1][w] > 0) {
				return w;
			}
		}
		return -1;
	}

	// 3.开始深搜遍历
	private void dfs(boolean[] isVisited, int i) {// 判断是否遍历过的标记,定义节点下标
		// 首先访问当前节点,输出
		System.out.print(getValueByIndex(i) + "->");
		// 访问过后,要标记节点已访问
		isVisited[i] = true;
		// 查找节点i的第一个邻接节点
		int w = getFirstNerghborIndex(i);
		while (w != -1) {// 存在
			if (!isVisited[w]) {// 如果没有被标记过
				dfs(isVisited, w);// 以w为初始节点重新开始,递归操作dfs
			}
			// 如果已经被访问过
			w = getNextNeighbor(i, w);
		}
	}

	// 对dfs进行重载,遍历所有节点
	public void dfs() {
		isVisited = new boolean[5];
		for (int i = 0; i < getnumOfVertexs(); i++) {
			while (!isVisited[i]) {// 如果没被访问过
				dfs(isVisited, i);
			}
		}
	}

	// ————————————--------------------------------------------------------
	// BFS算法步骤
	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
			w = getFirstNerghborIndex(u);
			while (w != -1) {// 找到邻接节点
				// 判断是否访问过
				if (!isVisited[w]) {// 如果没有访问过
					System.out.print(getValueByIndex(w) + "->");// 访问
					isVisited[w] = true;// 标记为已访问
					// 邻接节点入队列
					queue.addLast(w);
				}
				// 以u为前驱点,访问w的下一个邻接节点
				w = getNextNeighbor(u, w);
			}
		}
	}

	// 对bfs进行重载,遍历所有节点
	public void bfs() {
		isVisited = new boolean[5];
		for (int i = 0; i < getnumOfVertexs(); i++) {
			while (!isVisited[i]) {// 如果没被访问过
				bfs(isVisited, i);
			}
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值