备忘
这里写目录标题
文档前提
n = 图的节点数;m=图的边数;
{u,v,w} 分别为一条边的起点、终点、权值
1.邻接矩阵
临界矩阵创建图的方式比较适合边较多的情况,毕竟要开nn大小的空间。遍历由邻接矩阵构成的图,时间复杂度为O(nn),空间复杂度为O(n*n)。
定义:
int[][] map = new int[n][n]
建边:
map[u][v] = w
1.1构建图
public void build(){
//输入 节点数n 和 边的个数
Scanner scanner = new Scanner(System.in);
System.out.println("输入节点数:");
int n = scanner.nextInt(); //节点数
System.out.println("输入边数:");
int m = scanner.nextInt(); //边数
System.out.println("输入基本信息:");
//初始化邻接矩阵
arr = new int[n+1][n+1];
visit = new int[n+1];
Arrays.fill(visit,-1);
for(int i = 0;i<m;i++){
//切割数组
String[] str = scanner.next().split(",");
//System.out.println(Arrays.toString(str));
int a = Integer.parseInt(str[0]);
int b = Integer.parseInt(str[1]);
int c = Integer.parseInt(str[2]);
arr[a][b] = c;
arr[b][a] = c;
}
}
1.2遍历图
public void dfs(int u){
visit[u] = 1;
for(int i = 1;i<arr.length;i++){
if(arr[u][i]!=0){
System.out.println("起点:"+u+",终点:"+i+",权值:"+arr[u][i]);
}
//终点访问过 就不想下访问了
if(visit[i] == 1){
continue;
}
dfs(i);
}
}
2.边集数组
相比于临界矩阵,边界数组以边为出发点,构成以边为元素的数组,边的内部属性包括:起点、终点、权值。遍历由边集数组构成的图,时间复杂度为O(n*m),空间复杂度为O(m)。
定义:
class Edge{ int u;int v;int w}
Edge[] edges= new Edge[m]
建边:
edges[i] = {u,v,w}
2.1构建图
public void build(){
Scanner scanner = new Scanner(System.in);
System.out.println("输入节点个数");
int n = scanner.nextInt();
System.out.println("输入边的个数");
int m = scanner.nextInt();
edges = new Edge[m];
visit = new int[n+1];
Arrays.fill(visit,-1);
System.out.println("输入详细信息");
for(int i = 0;i<m;i++){
String[] split = scanner.next().split(",");
int a = Integer.parseInt(split[0]);
int b = Integer.parseInt(split[1]);
int c = Integer.parseInt(split[2]);
edges[i] = new Edge(a,b,c);
}
}
2.2遍历图
int[] visit = new int[n+1];
public void dfs(int u){
visit[u] = 1;
for(int i = 0;i<edges.length;i++){
if(edges[i].u == u){
System.out.println("起点:"+edges[i].u+",终点:"+edges[i].v+",权值:"+edges[i].w);
if(visit[edges[i].v]>0){
continue;
}
dfs(edges[i].v);
}
}
}
3.邻接表
邻接表则考虑以图中的点作为下标构建list数组,以n1为下标的数组元素指向一个list对象,该对象中的属性为以n1为起点的边的终点、和该边的权值。遍历由邻接数组构成的图,时间复杂度为O(n+m),空间复杂度为O(n+m)。
定义:
class Edge{ int v;int w} //定义边:终点、权值
List<Edge>[] h = new LinkedList[n];
建边:
h[u].add(new Edge(v,w)); //新建边 并将边的引用 压入h[u]集合
3.1构建图
public void build(){
Scanner scanner = new Scanner(System.in);
System.out.println("输入节点个数");
int n = scanner.nextInt();
System.out.println("输入边的个数");
int m = scanner.nextInt();
e = new LinkedList[n+1];
for(int i = 0;i<n+1;i++){
e[i] = new LinkedList<>();
}
for(int i = 0;i<m;i++){
String[] strs = scanner.next().split(",");
int a = Integer.parseInt(strs[0]);
int b = Integer.parseInt(strs[1]);
int c = Integer.parseInt(strs[2]);
e[a].add(new Edge(b,c));
e[b].add(new Edge(a,c));
}
}
3.2遍历图
//注意 这里没有考虑图中有环的情况,如需要请加入visited数组,判断
public void dfs(int u,int fa){
for(Edge child:e[u]){
if(child.v==fa){
continue;
}
System.out.println("起点:"+u+",终点:"+child.v+",权值:"+child.w);
dfs(child.v,u);
}
}
4.链式邻接表
链式邻接表私以为可以看作邻接表的变种,将边的信息单独存储在的list集合中,不用之前的list来存储每个点的邻边,取而代之的是邻边在list集合中的索引。遍历由链式邻接表构成的图,时间复杂度为O(n+m),空间复杂度为O(n+m)
class Edge{ int u,int v;int w} //定义边 :起点、终点、权值
List<Integer>[] h = new LinkedList[n];
List<Edge> e = new LinekedList<>();
建边:
public void add(int u,int v,int w){
e.add(new Edge(u,v,w)); //新建边 并压入 e集合
h[u].add(e.size()-1); //将新建立的 边的索引 压入h[u]集合(注意于邻接表区分)
}
4.1构建图
public void build(){
Scanner scanner = new Scanner(System.in);
//节点数量
System.out.println("输入节点数量:");
int n = scanner.nextInt();
//边的数量
System.out.println("输入边的数量:");
int m = scanner.nextInt();
e = new LinkedList<>(); //用来存放边
h = new LinkedList[n+1]; //类似邻接表
//初始化
for(int i = 0;i<=n;i++){
h[i] = new LinkedList<>();
}
System.out.println("输入边的数据");
for(int i = 0;i<m;i++){
String[] str = scanner.next().split(",");
int a = Integer.parseInt(str[0]);
int b = Integer.parseInt(str[1]);
int c = Integer.parseInt(str[2]);
add(a,b,c);
add(b,a,c);
}
}
4.2遍历图
//注意 这里没有考虑图中有环的情况,如需要请加入visited数组,判断
public void dfs(int u,int fa){
//遍历以u为起点的边
for(int child:h[u]){
Edge ee = e.get(child);
if(ee.v==fa){
continue;
}
System.out.println("起点:"+u+",终点:"+ee.v+",权值:"+ee.w);
dfs(ee.v,u);
}
}
5.链式前向星
链式前向星也是邻接表的变种,但相比于链式邻接表,这次不需要用list存储点的邻边的索引,而是直接拉一条链表存储,这就需要在边的定义中定义下一条边的索引,就像链表节点node中的next一样!遍历由链式前向星构成的图,时间复杂度为O(n+m),空间复杂度为O(n+m)。
定义
class Edge{ int v;int w;int ne} //定义边:终点、权值、下个边的索引
int[] h = new int[n];
Edge[] e = new Edge[m*2]; // 考虑无向边图,因此大小为m*2
int ids = 0; //为边数组的指针,始终指向待插入新数据的数组元素
建边:
public void add(int u,int v,int w){
e[ids] = new Edge(v,w,h[u]); //新建边 并压入 e集合
h[u] = ids++; //将新建立的 边的索引 压入h[u]集合(注意于邻接表区分)
}
5.1构建图
public void build(){
Scanner scanner = new Scanner(System.in);
//
System.out.println("输入节点数量:");
int n = scanner.nextInt();
System.out.println("输入边的数量:");
int m = scanner.nextInt();
e = new Edge[2*m];
h = new int[n+1];
//初始化h 每个下标代表一个节点 一开始节点不指向任何边 因此设为-1
Arrays.fill(h,-1);
ids = 0;
for(int i = 0;i<m;i++){
String[] str = scanner.next().split(",");
int a = Integer.parseInt(str[0]);
int b = Integer.parseInt(str[1]);
int c = Integer.parseInt(str[2]);
add(a,b,c);
add(b,a,c);
}
}
5.2遍历图
//注意 这里没有考虑图中有环的情况,如需要请加入visited数组,判断
public void dfs(int u,int fa){
//遍历链表
for(int i = h[u];i!=-1;i=e[i].ne){
Edge ee = e[i];
if(ee.v==fa){
continue;
}
System.out.println("起点:"+u+",终点:"+ee.v+",权值:"+ee.w);
dfs(ee.v,u);
}
}