图的定义
一个图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代码也在不断完善中,有些地方可能有问题,还请多指教
欢迎扫描二维码,关注公众号