Java数据结构——topoSort算法+dijkstra算法

三、拓扑排序

(一)、定义

  • 拓扑排序: Topological Sort,函数命名:topoSort
  • AOV-网: 有向无环网,顶点活动网。
  • 用法: 用于判断有向图中死否存在回路(或环)。
  • 若图中所有顶点都在拓扑排序的序列中,则图一定无环。
  • 实际意义:
  • 例如,假定一个计算机专业的学生必须完成图3-4所列出的全部课程。在这里,课程代表活动,学习一门课程就表示进行一项活动,学习每门课程的先决条件是学完它的全部先修课程。如学习《数据结构》课程就必须安排在学完它的两门先修课程《离散数学》和《算法语言》之后。学习《高等数学》课程则可以随时安排,因为它是基础课程,没有先修课。若用AOV网来表示这种课程安排的先后关系,则如图3-5所示。图中的每个顶点代表一门课程,每条有向边代表起点对应的课程是终点对应课程的先修课。从图中可以清楚地看出各课程之间的先修和后续的关系。如课程C5的先修课为C2,后续课程为C4和C6。
  • 算法:
  1. 找一个入读为0的顶点
  2. 删除该顶点和以该顶点为起点的边
  3. 重复 1, 2

(二)、Java代码

1. 更新MGraph.java文件

package graph;

/**
 * 接口
 */
interface IGraph {

	/**
	 * 得到顶点的数目
	 * 
	 * @return
	 */
	public int getVexNum();

	/**
	 * 得到边的数目
	 * 
	 * @return
	 */
	public int getArcNum();

	/**
	 * 定位顶点的位置
	 * 
	 * @param data
	 * @return
	 */
	public int indexOfVex(String data);

	/**
	 * 定位指定位置的顶点
	 * 
	 * @param index
	 * @return
	 */
	public String valueOfVex(int index);

	/**
	 * 打印邻接矩阵
	 */
	public void printMGraph();

} // IGraph

/**
 * @MatrixGraph 邻接矩阵
 * 
 * @author 己千之
 * @time 2022/2/20
 */
public class MGraph implements IGraph {

	/**
	 * @INF 无穷大 private static final int INF=Integer.MAX_VALUE; @1.
	 *      因为有时侯要打印邻接矩阵,太大了不好看 @2. 因为最小生成数涉及到网
	 */
	public static final int INF = 99; // 最大值

	/**
	 * 存储图的顶点的一维数组
	 */
	String[] vexs;

	/**
	 * @邻接矩阵 存储图的边的二维数组
	 */
	int[][] arcs;

	/**
	 * 顶点的实际数量
	 */
	int vexNum;

	/**
	 * 边数
	 */
	int arcNum;

	/**
	 * 构造函数
	 */
	public MGraph(String[] vertexs, int[][] adjMatrix) {

		// 1. 初始成员变量
		int num = vertexs.length;
		int row = adjMatrix.length;
		int col = adjMatrix[0].length;
		if (row != col && row != num) {
			throw new RuntimeException("row != col,邻接矩阵有误!");
		}
		vexNum = num;
		vexs = new String[vexNum];
		arcs = new int[vexNum][vexNum];

		// 1.1 初始化值
		for (int i = 0; i < vexNum; i++) {
			vexs[i] = vertexs[i];
		}
		for (int i = 0; i < vexNum; i++) {
			for (int j = 0; j < vexNum; j++) {
				arcs[i][j] = adjMatrix[i][j];
			}
		}

		// 1.2 设置边数
		for (int i = 0; i < vexNum; i++) {
			for (int j = 0; j < vexNum; j++) {
				if (arcs[i][j] != 0 && arcs[i][j] != INF) {
					arcNum++;
				}
			}
		}

	}

	@Override
	public int getVexNum() {
		return this.vexNum;
	}

	@Override
	public int getArcNum() {
		return this.arcNum;
	}

	@Override
	public int indexOfVex(String data) {
		for (int i = 0; i < vexNum; i++) {
			if (vexs[i] == data)
				return i;
		}
		return -1;
	}

	@Override
	public String valueOfVex(int index) {
		if (index < 0 || index >= vexNum) {
			throw new RuntimeException("位置错误!");
		}
		return vexs[index];
	}

	@Override
	public void printMGraph() {
		System.out.println("邻接矩阵:");
		int t = 0; // 格式控制
		for (int i = 0; i < arcs.length; i++) {
			for (int j = 0; j < arcs.length; j++) {
				System.out.printf("%3d", arcs[i][j]);
				t++;
				if (t % arcs.length == 0) {
					System.out.println();
				}
			}
		}
	} // printMGraph

} // MGraph

2. topoSort算法

package graph;

/**
 * @ 图的应用
 * 
 * @ 1. 用的是MGraph,邻接矩阵。 
 * @ 2. MGraph代码在 邻接矩阵那一天 
 * @ 3. 图的应用,我会打很多注释,其实代码不多。 
 * @ 4. 最后一天汇总
 * @author 己千之
 * @time 2022/2/18
 */
public class GraphApp extends MGraph {

	public GraphApp(String[] vertexs, int[][] adjMatrix) {
		super(vertexs, adjMatrix);
	}

	/**
	 * 从邻接矩阵中获取每个顶点的入度
	 * 
	 * @1. arcs[j][i]入度 @2. arcs[j][i] == 1,拓扑排序1代表有边
	 * 
	 * @return
	 */
	public int[] getIndegrees() {
		int[] indegrees = new int[vexNum];

		for (int i = 0; i < vexNum; i++) {
			int count = 0;
			for (int j = 0; j < vexNum; j++) {
				if (arcs[j][i] == 1) {
					count++;
				}
			}
			indegrees[i] = count;
		}
		return indegrees;
	}

	/**
	 * 拓扑排序
	 */
	public void topoSort() {

		// 1. 计算各入度
		int[] indegrees = getIndegrees();
		String[] topos = new String[vexNum];

		// 2. 拓扑算法
		int count = 0; // 用于计算当前遍历的顶点个数
		boolean flag = true;
		while (flag) {
			for (int i = 0; i < vexNum; i++) {
				if (indegrees[i] == 0) { // 当第i个顶点入度为0时,遍历该顶点
					topos[count++] = vexs[i];
					indegrees[i] = -1; // 代表第i个顶点已被遍历
					for (int j = 0; j < vexNum; j++) { // 寻找第i个顶点的出度顶点
						if (arcs[i][j] == 1)
							indegrees[j] -= 1; // 第j个顶点的入度减1
					}
				}
			}
			if (count == vexNum) {
				flag = false;
			}
		} // end while

		// 3. 打印
		System.out.println("给出图的拓扑排序结果:");
		for (int i = 0; i < vexNum; i++) {
			System.out.print(topos[i] + "\t");
		}
		System.out.println();
	} // topoSort

	public static void main(String[] args) {
		System.out.println("《测试拓扑排序》");

		String[] vertexs = { "v1", "v2", "v3", "v4", "v5", "v6" };
		int[][] adjMatrix = { { 0, 1, 1, 1, 0, 0 }, { 0, 0, 0, 0, 0, 0 }, { 0, 1, 0, 0, 1, 0 }, { 0, 0, 0, 0, 1, 0 },
				{ 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 1, 1, 0 } };

		GraphApp DG = new GraphApp(vertexs, adjMatrix);

		// 1.打印邻接矩阵
		DG.printMGraph();

		// 2. 打印各顶点的入度
		int[] indegrees = DG.getIndegrees();
		System.out.println("给出图的所有节点(按照字母顺序排列)的入度值:");
		for (int i = 0; i < indegrees.length; i++)
			System.out.print(indegrees[i] + "\t");
		System.out.println();

		// 3. 打印拓扑排序
		DG.topoSort();
	} // main

} // GraphApp

(三)、输出样例


  • 在这里插入图片描述

  • 在这里插入图片描述

(三)、输出样例

四、最短路径

(一)、Java代码

1. dijkstra

package graph;

public class GraphApp extends MGraph {

	public GraphApp(String[] vertexs, int[][] adjMatrix) {
		super(vertexs, adjMatrix);
		// TODO 自动生成的构造函数存根
	}

	public int[] dijkstra(int start) {
		int length = vexNum; // 接口思想

		// 1. 把不可达设为无穷大,除对角线
		for (int i = 0; i < vexNum; i++) {
			for (int j = 0; j < vexNum; j++) {
				if (arcs[i][j] == 0) {
					arcs[i][j] = INF;
				}
				if (i == j) {
					arcs[i][j] = 0;
				}
			}
		}

		// 2. 变量
		int[] dijkstras = new int[length];// 存放从start到各个点的最短距离
		dijkstras[start] = 0;// start到他本身的距离最短为0
		String shortPath[] = new String[length];// 存放从start点到各点的最短路径的字符串表示
		for (int i = 0; i < length; i++) {
			shortPath[i] = start + "->" + i;
		}
		boolean visited[] = new boolean[length];// 标记当前该顶点的最短路径是否已经求出,1表示已经求出
		visited[start] = true;// start点的最短距离已经求出

		// 3. dijkstra
		for (int count = 1; count < length; count++) {

			// 3.1 标志初始
			int index = -1;
			int minDistance = Integer.MAX_VALUE;

			// 3.2 贪心,选出一个距离start最近的未标记的顶点
			for (int i = 0; i < length; i++) {
				if (visited[i] == false && arcs[start][i] < minDistance) {
					minDistance = arcs[start][i];
					index = i;
				}
			}

			// 3.3 index已访问
			dijkstras[index] = minDistance;
			visited[index] = true;

			// 3.4 以index为中间点,更新从start到未访问各点的距离
			for (int i = 0; i < length; i++) {
				if (visited[i] == false && arcs[start][index] + arcs[index][i] < arcs[start][i]) {
					arcs[start][i] = arcs[start][index] + arcs[index][i];
					shortPath[i] = shortPath[index] + "->" + i;
				}
			}
		} // end for

		// 4. 打印
		for (int i = 0; i < length; i++) {
			System.out.println(shortPath[i] + " = " + dijkstras[i]);
		}

		// 5. 返回
		return dijkstras;
	}

	public static void main(String[] args) {
		String[] vertexs = { "v0", "v1", "v2", "v3", "v4", "v5" };
		int[][] adjMatrix = { { 0, 0, 10, 0, 30, 100 }, { 0, 0, 5, 0, 0, 0, 0 }, { 0, 0, 0, 50, 0, 0 },
				{ 0, 0, 0, 0, 0, 10 }, { 0, 0, 0, 20, 0, 60 }, { 0, 0, 0, 0, 0, 0 } };

		Test test = new Test(vertexs, adjMatrix);
		test.printMGraph();
		test.dijkstra(0);
	}
}

(二)、输出样例


  • 在这里插入图片描述

  • 在这里插入图片描述
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

姜满月

鼓励,鼓励,更加努力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值