图
图是一种数据结构,其中节点可以具有零个或者多个相邻的元素,两个节点之间的连接成为边。节点也可以成为顶点。
常用概念
- 顶点 vertex 图中的每一个节点都是一个顶点 通常记做V
- 边 edge 两个顶点之间的连接 通常记做E
- 路径 从一个顶点到另一个顶点经过的边的总和,如果带权则是所有边的权重和
- 无向图 顶点与顶点之间没有方向,即可以从顶点A到顶点B,也可以动B到A
- 有向图 与无向图相反顶点与顶点之间存在明显的方向
- 带权图 边上面带有权值的图称为带权图
- 弧头 弧尾 在有向图中,无箭头端的顶点称为起始点或者弧尾,有箭头的顶点称为终端点或者弧头
- (V1,V2)和<V1,V2>的区别 ,(V1,V2)表示无向图中2个顶点V1和V2,<V1,V2>表示有向图V1到V2的单向关系
图的表示方式
主要有两种,二维数组表示的邻接矩阵或者链表表示的邻接表
- 邻接矩阵: 表示图中顶点之间相邻关系的矩阵,若有N个顶点的图来讲,矩阵的row和col都是N,上图就是由一个二维数据表示的01234 5个顶点之间的连接关系 数组中的值为1表示连接 0表示未连接如 arr[0,1]=1 表示 0顶点和1顶点是连同的即存在边 arr[0,2]=0 表示顶点0和顶点2没有直接连接的边
- 邻接表: 邻接表一般采用数组+链表的形式,数组表示各个顶点,链表中的元素表示该顶点与链表中的元素相连,与链表本身的指针没有关系。如上图 数组0 对应的链表1->3->4 表示0这个顶点与1 3 4这个顶点连接 数组1 表示1这个顶点与 0 2 4顶点相连以此类推
- 邻接矩阵和邻接表的区别 邻接矩阵会为每个顶点都分配N个边的空间,其实很多表都不存在,存在了空间的损失,邻接表值关心存在边,因此没有空间的损失。
核心方法
/**
* 添加顶点
*
* @param vertex
*/
public void addVertex(String vertex) {
vertexList.add(vertex);
}
/**
* 为V1顶点和V2顶点添加边 如果只为1就是
*
* @param v1 第一个顶点
* @param v2 第二个顶点
* @param weight 权 约定1为连接 0未连接
*/
public void insertEdge(int v1, int v2, int weight) {
if (vertexSize < maxVertexSize) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
vertexSize++;
}
/**
* 打印图
*/
public void show() {
for (String s : vertexList) {
System.out.print("\t" + s);
}
System.out.println();
for (int i = 0; i < edges.length; i++) {
int[] edge = edges[i];
System.out.print(vertexList.get(i) + "\t");
for (int j : edge) {
System.out.print(j + "\t");
}
System.out.println();
}
}
完整代码
package com.corn.datastruct.graph;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class GraphDemo {
public static void main(String[] args) {
//测试一把图是否创建ok
int n = 5; //结点的个数
String[] vertexs = {"A", "B", "C", "D", "E"};
// String Vertexs[] = {"1", "2", "3", "4", "5", "6", "7", "8"};
//创建图对象
Graph graph = new Graph(n);
//循环的添加顶点
for (String vertex : vertexs) {
graph.addVertex(vertex);
}
graph.insertEdge(0, 1, 1); // A->B
graph.insertEdge(0, 2, 1); // A->C
graph.insertEdge(1, 2, 1); // B->C
graph.insertEdge(1, 3, 1); // B->D
graph.insertEdge(1, 4, 1); // B->E
graph.show();
}
}
class Graph {
/**
* 顶点集合
*/
public List<String> vertexList;
/**
* 表示顶点之间边关系的二维数组
*/
public int[][] edges;
/**
* 最多顶点个数
*/
public final int maxVertexSize;
/**
* 当前图顶点的个数
*/
public int vertexSize;
Graph(int maxVertexSize) {
this.maxVertexSize = maxVertexSize;
/**
* 初始化 顶点集合 和顶点边关系二维数组
*/
this.vertexList = new ArrayList<>(maxVertexSize);
this.edges = new int[maxVertexSize][maxVertexSize];
}
/**
* 获取某一个顶点的 第一个连接顶点 相当于从arr[v]中的一维数组中获取第一个为1的元素的下标
*
* @param v
* @return
*/
public int getFirstNeighbor(int v) {
int firstIndex = 0;
while (firstIndex < vertexSize) {
if (edges[v][firstIndex] == 1) {
return firstIndex;
} else {
firstIndex++;
}
}
return -1;
}
/**
* 获取v1顶点 从v2连接点之后的第一个连接点的下标
* 比如V1=A V2=B
* 如测试 ABCDE 这个图中 A->B 连接后 一个就是A-C 则下标为2
* V1=D V2=A D->A没有连接 下一个看D->B是有连接的 则返回1
*
* @param v1
* @param v2
* @return
*/
public int getNextNeighbor(int v1, int v2) {
for (int i = v2 + 1; i < getVertexSize(); i++) {
if (edges[v1][i] == 1) {
return i;
}
}
return -1;
}
/**
* 添加顶点
*
* @param vertex
*/
public void addVertex(String vertex) {
vertexList.add(vertex);
}
/**
* 为V1顶点和V2顶点添加边 如果只为1就是
*
* @param v1 第一个顶点
* @param v2 第二个顶点
* @param weight 权 约定1为连接 0未连接
*/
public void insertEdge(int v1, int v2, int weight) {
if (vertexSize < maxVertexSize) {
edges[v1][v2] = weight;
edges[v2][v1] = weight;
vertexSize++;
}
}
/**
* 获取2个顶点的权重 (边信息)
*
* @param v1
* @param v2
*/
public int getWeight(int v1, int v2) {
return edges[v1][v2];
}
/**
* 获取index获取 顶点集合中的顶点元素
*
* @param index
* @return
*/
public String getVertexByIndex(int index) {
return vertexList.get(index);
}
/**
* 获取当前图中有多少个顶点
*
* @return
*/
public int getVertexSize() {
return vertexSize;
}
/**
* 打印图
*/
public void show() {
for (String s : vertexList) {
System.out.print("\t" + s);
}
System.out.println();
for (int i = 0; i < edges.length; i++) {
int[] edge = edges[i];
System.out.print(vertexList.get(i) + "\t");
for (int j : edge) {
System.out.print(j + "\t");
}
System.out.println();
}
}
}