本文旨作于收集整理使用!!
导航
- Java数据结构算法(一)链表
- Java数据结构算法(二)栈和队列
- Java数据结构算法(三)树
- Java数据结构算法(五)排序
- ......
一、图的简介
图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。在图中的数据元素,我们称之为顶点(Vertex),顶点集合有穷非空。在图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。
图主要运用在路径规划以及模型建立中。
二、图的分类
1、 无向图
若顶点v1到v2之间的边没有方向,则称这条边为无向边。如果图中任意两个顶点之间的边都是无向边,则称该图为无向图。
在无向图中,若任意两个顶点之间都存在边,则称该图为无向完全图
2、 有向图
有向边:若顶点v1到v2的边有方向,则称这条边为有向边或为弧。
若图中任意两个顶点之间的连线都是有向边,则称该图为有向图。
在有向图中,若任意两个顶点之间都存互为相反的两条弧,则称该图为有向完全图
3、其他
权:有些图的边或弧具有与他相关的数字,这种与图相关的边或弧叫做权。
连通图:在无向图中任意两个顶点之间都是连通的。
度:无向图顶点的边数叫做度;有向图的边数叫做出度和入度。
三、图的存储结构
图的存储结构较为复杂,无法用简单的顺序存储结构存储,因此使用邻接矩阵来存储图。
邻接矩阵的存储方式是用一维数组存储顶点信息,用二维数组存储图中边或弧的信息。
1、无向图
设图有n个顶点,则邻接矩阵就是一个n×n的方阵,定义为:
若两个顶点之间有连线则值为1,若无连线则为0。如下图所示
2、有向图
设图有n个顶点,则邻接矩阵就是一个n×n的方阵,定义为:
若两个顶点之间从一个顶点到另一个顶点之间有对应的箭头则为1,无则为0。如下图所示,v1到v0有弧线则为1,而v0到v1无弧则为0.
3、带权的图
设图有n个顶点,则邻接矩阵就是一个n×n的方阵,定义为:
我们将对应连线之间的权作为连线的依据,两定点之间无弧线咋舌为无穷大,有弧线则设为对应的权值。
4、图的简单实现(JAVA)
/**
* Author: Active_Loser
* Date: 2018/8/1 22:24
* Content:
*/
public class Graph {
private static final int MAX_WEIGHT = 1000;
private int vertexSize;
private int[] vertexs;
private int[][] matrix;
private boolean[] isVisted;
public Graph(int vertexSize) {
this.vertexSize = vertexSize;
matrix = new int[vertexSize][vertexSize];
vertexs = new int[vertexSize];
for (int i = 0; i < vertexSize; i++) {
vertexs[i] = i;
}
isVisted = new boolean[vertexSize];
}
/**
* 获取某个顶点的出度
*
* @param index 顶点下标
* @return 返回该顶点的出度
*/
public int getOutDeGree(int index) {
int deGree = 0;
for (int i = 0; i < matrix[index].length; i++) {
int weight = matrix[index][i];
if (weight != 0 && weight != MAX_WEIGHT) {
deGree++;
}
}
return deGree;
}
/**
* 获取某个顶点的入度
*
* @param index 顶点下标
* @return 返回该顶点的出度
*/
public int getIntDeGree(int index) {
int deGree = 0;
for (int i = 0; i < vertexSize; i++) {
int weight = matrix[i][index];
if (weight != 0 && weight != MAX_WEIGHT) {
deGree++;
}
}
return deGree;
}
/**
* 获取权值
*
* @param v1
* @param v2
* @return
*/
public int getWeight(int v1, int v2) {
return matrix[v1][v2] == 0 ? 0 : (matrix[v1][v2] == MAX_WEIGHT ? -1 : matrix[v1][v2]);
}
public int[][] getMatrix() {
return matrix;
}
}
图的构造,实现带权的图
private static final int MAX_WEIGHT = 1000;
public static void main(String[] args) {
Graph graph = new Graph(4);
int[] a0 = {0, MAX_WEIGHT, MAX_WEIGHT, 1};
int[] a1 = {30, 0, MAX_WEIGHT, MAX_WEIGHT};
int[] a2 = {4, 15, 0, 5};
int[] a3 = {MAX_WEIGHT, MAX_WEIGHT, MAX_WEIGHT, 0};
int[][] matrix = graph.getMatrix();
matrix[0]=a0;
matrix[1]=a1;
matrix[2]=a2;
matrix[3]=a3;
//graph.方法
}
四、图的遍历
1、图的深度优先遍历
深度优先遍历(Depth_First_Search(DFS))也被称为深度优先搜索,它是从图中的某个v点出发,访问此顶点,然后从v的未被访问的点邻接点出发深度优先遍历,直到图中所有和v点有路径相通的点都被访问到。
图的深度优先遍历类似于树的前序遍历,如下图,可以将树转化为图。
深度优先遍历主要代码,完整代码移至最后。
/**
* 深度优先遍历,对外界提供访问
*/
public void dfs(int index) {
if (index<0||index>vertexSize-1){
return;
}
//重新初始化
isVisted = new boolean[vertexSize];
//优先访问开始的点
System.out.println("访问到了"+index+"顶点");
depth_first_search(index);
//通过遍历查看那些点没有被访问(主要针对于有向图)
for (int i = 0; i < vertexSize; i++) {
if (!isVisted[i]) {
System.out.println("访问到了"+i+"顶点");
depth_first_search(i);
}
}
//重新初始化
isVisted = new boolean[vertexSize];
}
/**
* 提供访问的方法
* @param index
*/
private void depth_first_search(int index) {
isVisted[index] = true;
int w = getFirstNeighbor(index);
while (w!=-1){
if (!isVisted[w]){
depth_first_search(w);
System.out.println("访问到了"+w+"顶点");
}
w=getNextNeighbor(index,w);
}
}
//获取某个顶点的第一个邻接点
private int getFirstNeighbor(int v1) {
for (int i = 0; i < vertexSize; i++) {
if (matrix[v1][i] > 0 && matrix[v1][i] < MAX_WEIGHT) {
return i;
}
}
return -1;
}
/**
* 根据前一个邻接点的下标获取一个邻接点
*
* @param v1 表示查找的顶点
* @param index 表示该顶点相对于哪个邻接点获取下一个邻接点
* @return
*/
private int getNextNeighbor(int v1, int index) {
for (int i = index+1; i < vertexSize; i++) {
if (matrix[index][i] > 0 && matrix[index][i] < MAX_WEIGHT) {
return i;
}
}
return -1;
}
2、图的广度优先遍历
图的广度优先遍历,类似于树种的层次遍历,如下图将图转化为可以广层次遍历的树。
广度优先遍历主要代码,完整代码移至最后。
/**
* 实现广度优先遍历
*
* @param index
*/
public void bfs(int index) {
//重新初始化
isVisted = new boolean[vertexSize];
//优先访问开始的点
System.out.println("访问到了"+index+"顶点");
depth_first_search(index);
//通过遍历查看那些点没有被访问(主要针对于有向图)
for (int i = 0; i < vertexSize; i++) {
if (!isVisted[i]) {
System.out.println("访问到了" + i + "顶点");
broadFirstSearch(i);
}
}
//重新初始化
isVisted = new boolean[vertexSize];
}
/**
* 广度优先遍历算法
*
* @param index
*/
private void broadFirstSearch(int index) {
int u, w;
//使用队列实现
LinkedList queue = new LinkedList<>();
isVisted[index] = true;
queue.add(index);
while (!queue.isEmpty()){
u= queue.removeFirst();
w=getFirstNeighbor(u);
while (w!=-1){
if (!isVisted[w]){
System.out.println("访问到了" + w + "顶点");
isVisted[w]=true;
queue.add(w);
}
w=getNextNeighbor(u,w);
}
}
}
//获取某个顶点的第一个邻接点
private int getFirstNeighbor(int v1) {
for (int i = 0; i < vertexSize; i++) {
if (matrix[v1][i] > 0 && matrix[v1][i] < MAX_WEIGHT) {
return i;
}
}
return -1;
}
/**
* 根据前一个邻接点的下标获取一个邻接点
*
* @param v1 表示查找的顶点
* @param index 表示该顶点相对于哪个邻接点获取下一个邻接点
* @return
*/
private int getNextNeighbor(int v1, int index) {
for (int i = index + 1; i < vertexSize; i++) {
if (matrix[index][i] > 0 && matrix[index][i] < MAX_WEIGHT) {
return i;
}
}
return -1;
}
完整代码
import java.util.LinkedList;
/**
* Author: Active_Loser
* Date: 2018/8/1 22:24
* Content:
*/
public class Graph {
private static final int MAX_WEIGHT = 1000;
private int vertexSize;
private int[] vertexs;
private int[][] matrix;
private boolean[] isVisted;
public Graph(int vertexSize) {
this.vertexSize = vertexSize;
matrix = new int[vertexSize][vertexSize];
vertexs = new int[vertexSize];
for (int i = 0; i < vertexSize; i++) {
vertexs[i] = i;
}
isVisted = new boolean[vertexSize];
}
/**
* 深度优先遍历,对外界提供访问
*/
public void dfs(int index) {
if (index < 0 || index > vertexSize - 1) {
return;
}
//重新初始化
isVisted = new boolean[vertexSize];
//优先访问开始的点
System.out.println("访问到了" + index + "顶点");
depth_first_search(index);
//通过遍历查看那些点没有被访问(主要针对于有向图)
for (int i = 0; i < vertexSize; i++) {
if (!isVisted[i]) {
System.out.println("访问到了" + i + "顶点");
depth_first_search(i);
}
}
//重新初始化
isVisted = new boolean[vertexSize];
}
/**
* 提供访问的方法
*
* @param index
*/
private void depth_first_search(int index) {
isVisted[index] = true;
int w = getFirstNeighbor(index);
while (w != -1) {
if (!isVisted[w]) {
depth_first_search(w);
System.out.println("访问到了" + w + "顶点");
}
w = getNextNeighbor(index, w);
}
}
//获取某个顶点的第一个邻接点
private int getFirstNeighbor(int v1) {
for (int i = 0; i < vertexSize; i++) {
if (matrix[v1][i] > 0 && matrix[v1][i] < MAX_WEIGHT) {
return i;
}
}
return -1;
}
/**
* 根据前一个邻接点的下标获取一个邻接点
*
* @param v1 表示查找的顶点
* @param index 表示该顶点相对于哪个邻接点获取下一个邻接点
* @return
*/
private int getNextNeighbor(int v1, int index) {
for (int i = index + 1; i < vertexSize; i++) {
if (matrix[index][i] > 0 && matrix[index][i] < MAX_WEIGHT) {
return i;
}
}
return -1;
}
/**
* 实现广度优先遍历
*
* @param index
*/
public void bfs(int index) {
//重新初始化
isVisted = new boolean[vertexSize];
//优先访问开始的点
System.out.println("访问到了"+index+"顶点");
depth_first_search(index);
//通过遍历查看那些点没有被访问(主要针对于有向图)
for (int i = 0; i < vertexSize; i++) {
if (!isVisted[i]) {
System.out.println("访问到了" + i + "顶点");
broadFirstSearch(i);
}
}
//重新初始化
isVisted = new boolean[vertexSize];
}
/**
* 广度优先遍历算法
*
* @param index
*/
private void broadFirstSearch(int index) {
int u, w;
//使用队列实现
LinkedList queue = new LinkedList<>();
isVisted[index] = true;
queue.add(index);
while (!queue.isEmpty()){
u= queue.removeFirst();
w=getFirstNeighbor(u);
while (w!=-1){
if (!isVisted[w]){
System.out.println("访问到了" + w + "顶点");
isVisted[w]=true;
queue.add(w);
}
w=getNextNeighbor(u,w);
}
}
}
/**
* 获取某个顶点的出度
*
* @param index 顶点下标
* @return 返回该顶点的出度
*/
public int getOutDeGree(int index) {
int deGree = 0;
for (int i = 0; i < matrix[index].length; i++) {
int weight = matrix[index][i];
if (weight != 0 && weight != MAX_WEIGHT) {
deGree++;
}
}
return deGree;
}
/**
* 获取某个顶点的入度
*
* @param index 顶点下标
* @return 返回该顶点的出度
*/
public int getIntDeGree(int index) {
int deGree = 0;
for (int i = 0; i < vertexSize; i++) {
int weight = matrix[i][index];
if (weight != 0 && weight != MAX_WEIGHT) {
deGree++;
}
}
return deGree;
}
/**
* 获取权值
*
* @param v1
* @param v2
* @return
*/
public int getWeight(int v1, int v2) {
return matrix[v1][v2] == 0 ? 0 : (matrix[v1][v2] == MAX_WEIGHT ? -1 : matrix[v1][v2]);
}
public int[][] getMatrix() {
return matrix;
}
}