算法系列(十三)图论基本概念和拓扑排序

图的定义

一个图G=(V,E),由定点的集合V,和边的集合E组成。每一条边都是一副点对(v,w),边也称作弧,边上可以有权值。如果点对是有序的,那么图就是有向的。

图中的一条路径是一个顶点序列w1,w2,w3……wN,如果图中包含一条从顶点到自身的边,那么这个路径就是环。

有向无环图也成为DAG

如果在一个无向图中每个顶点到其它顶点都存在路径,则称这个无向图是连通的。具有这样性质的有向图被称为是强连通的。如果一个有向图不是强连通的,但是去掉方向后的基础图是连通的,那么该有向图称为是弱连通的。完全图是每一对顶点间都存在一条边的图。

进入一个顶点的边的个数称为该顶点的入度。每个有向无环图必定至少存在一个入度为0的顶点,至少存在一个出度为0的顶点,否则图中必然存在环。

图的表示

表示图的一种简单方法是使用一个二维数组,称为邻接矩阵。

如果图是稀疏的,更好的解决方法是使用邻接表。

《算法系列(十三)图论基本概念和拓扑排序》


拓扑排序

拓扑排序是对有向五环图的顶点排序,使得如果存在一条vi到vj的路径,那么在排序中vj在vi的后面。拓扑排序是不唯一的。

《算法系列(十三)图论基本概念和拓扑排序》该DAG的拓扑序列为A B C D或者A C B D

拓扑排序的实现

先找出任意一个没有入边的顶点,然后显示该顶点,将它及其边删除,然后对图的其余部分做相同处理。

package com.algorithm.graphics;

import java.util.Stack;
import java.util.Vector;

/**
 * 拓扑排序
 * 
 * @author chao
 *
 */

public class TopSortGraph {

	int vertexNum;
	Vector[] vector;
	Stack stack;
	int[] result;
	int[] in;// 入度

	/**
	 * 
	 * 构造一个图
	 * 
	 * @param num
	 *            图的顶点数
	 * 
	 */
	public TopSortGraph(int num) {

		vertexNum = num;
		vector = new Vector[vertexNum];
		stack = new Stack();
		result = new int[vertexNum];
		in = new int[vertexNum];

	}

	/**
	 * 向图中添加无向边
	 * 
	 * @param I
	 *            边的一个顶点
	 * @param J
	 *            边的另一个顶点
	 * @return 是否添加成功
	 */
	public boolean addEdge(int I, int J) {

		/**
		 * 判断用户输入的是否是一个顶点,如果是,则返回flase,添加不成功
		 */
		if (J == I) {
			return false;
		}

		/**
		 * 判断所输入的顶点值是否在图所顶点范围值内,如果不在,则提示顶点不存在
		 * 
		 */
		if (I < vertexNum && J < vertexNum && I >= 0 && J >= 0) {

			/**
			 * 
			 * 判断边是否存在
			 */

			if (isEdgeExists(I, J)) {

				return false;
			}

			/**
			 * 添加边,将孤头的入度加1
			 */

			vector[I].add(J);
			in[J]++;
			return true;
		}
		return false;
	}

	/**
	 * 判断有向边是否存在
	 * 
	 * @param i
	 *            要查询的有向边的一个孤尾
	 * @param j
	 *            要查询的有向边的另一个孤头
	 * @return 边是否存在,false:不存在,true:存在
	 */

	public boolean isEdgeExists(int i, int j) {

		/**
		 * 判断所输入的顶点值是否在图所顶点范围值内,如果不在,则提示顶点不存在
		 * 
		 */
		if (i < vertexNum && j < vertexNum && i >= 0 && j >= 0) {

			if (i == j) {
				return false;
			}

			/**
			 * 判断i的邻接结点集是否为空
			 */

			if (vector[i] == null) {
				vector[i] = new Vector();
			}

			/**
			 * 判断这条边是否存在,如果存在,则提示边已经存在
			 */
			for (int q = 0; q < vector[i].size(); q++) {

				if (((Integer) vector[i].get(q)).intValue() == j) {
					System.out.println("顶点" + i + "和" + "顶点" + j + "这两点之间存在边");
					return true;

				}
			}
		}
		return false;
	}

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

		for (int i = 0; i < vertexNum; i++)
			if (in[i] == 0)
				stack.push(i);
		int k = 0;
		while (!stack.isEmpty()) {

			result[k] = (Integer) stack.pop();

			if (vector[result[k]] != null) {
				for (int j = 0; j < vector[result[k]].size(); j++) {

					int temp = (Integer) vector[result[k]].get(j);
					if (--in[temp] == 0) {
						stack.push(temp);
					}

				}

			}
			k++;

		}

		if (k < vertexNum) {
			System.out.println("有回路");
			System.exit(0);

		}

	}

	/**
	 * 拓扑结果
	 * 
	 * @return
	 */
	public int[] getResult() {
		return result;

	}

}

代码实现可以看github,地址https://github.com/robertjc/simplealgorithm
github代码也在不断完善中,有些地方可能有问题,还请多指教

欢迎扫描二维码,关注公众号

《算法系列(十三)图论基本概念和拓扑排序》

    原文作者:拓扑排序
    原文地址: https://blog.csdn.net/robertcpp/article/details/51879346
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞