图的操作

图的存储方式主要有两种:邻接矩阵和邻接表,零阶矩阵主要是用二维数组的方式来存储点与点之间的关系,而邻接表主要是一维数组加链表的方式来记录点与点之间的关系。下面我们从两个不同的方式来编写代码。

1、邻接矩阵

代码如下:

package graph_arr;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 带权有向图
 * 
 * @author JustGeeker
 *
 */
public class Graph {
	private List<String> vertexes;// 用来存放结点信息
	private int[][] graphEgdes;// 又来记录边
	private int numofEdges;// 记录边的个数
	private boolean[] visited;

	public Graph() {
		super();

	}

	public Graph(int n) {
		super();
		visited = new boolean[n];
		this.vertexes = new ArrayList<>(n);
		this.graphEgdes = new int[n][n];
		this.numofEdges = 0;

	}

	public Graph(String[] vertexarr) {
		super();

		int len = vertexarr.length;
		this.vertexes = new ArrayList<>(len);
		visited = new boolean[len];

		for (String vertex : vertexarr) {

			vertexes.add(vertex);
		}
		this.graphEgdes = new int[len][len];
		this.numofEdges = 0;

	}

	/**
	 * 插入结点
	 * 
	 * @param str结点信息
	 */
	public void addVertex(String str) {
		vertexes.add(str);
	}

	/**
	 * 根据结点索引添加有向边
	 * 
	 * @param index1 起始节点结点的索引
	 * @param index2 终止结点的索引
	 * @param weight 两点之间权值
	 */
	public void addEdge(int index1, int index2, int weight) {
		int len = graphEgdes.length;
		if (index1 > len || index1 < 0 | index2 > len || index2 < 0) {
			System.out.println("索引越界");
			return;
		}
		graphEgdes[index1][index2] = weight;
		numofEdges++;
	}

	/**
	 * 根据两个结点添加有向边
	 * 
	 * @param index1 起始节点结点
	 * @param index2 终止结点
	 * @param weight 两点之间权值
	 */
	public void addEdge(String vertex1, String vertex2, int weight) {

		int index1 = getIndex(vertex1);
		int index2 = getIndex(vertex2);
		int len = graphEgdes.length;
		if (index1 < -1 || index2 < -1) {
			System.out.println("结点不存在");
			return;
		}
		graphEgdes[index1][index2] = weight;
		numofEdges++;
	}

	/**
	 * 根据两个结点添加有向边
	 * 
	 * @param index1 起始节点结点
	 * @param index2 终止结点
	 * @param weight 两点之间权值
	 */
	public void addEdges(String vertex1, String vertex2, int weight) {

		addEdge(vertex1, vertex2, weight);
		addEdge(vertex2, vertex1, weight);
	}

	/**
	 * 添加两个结点之间的无向边
	 * 
	 * @param index1 起始节点结点的索引
	 * @param index2 终止结点的索引
	 * @param weight 两点之间权值
	 */
	public void addEdges(int index1, int index2, int weight) {
		addEdge(index1, index2, weight);
		addEdge(index2, index1, weight);
	}

	/**
	 * 返回结点个数
	 * 
	 * @return
	 */
	public int getVertexsNum() {
		return vertexes.size();
	}

	/**
	 * 返回图中边的个数
	 * 
	 * @return
	 */
	public int getEdgesNum() {
		return numofEdges;
	}

	/**
	 * 根据索引返回结点信息
	 * 
	 * @param i
	 * @return
	 */
	public String getVertex(int i) {
		return vertexes.get(i);
	}

	/**
	 * 根据结点信息返回索引
	 * 
	 * @param vertex
	 * @return
	 */
	public int getIndex(String vertex) {

		if (vertexes.contains(vertex)) {
			return vertexes.indexOf(vertex);
		}
		return -1;
	}

	/**
	 * 打印临界矩阵
	 */
	public void showEdge() {
		System.out.println(" " + vertexes);
		for (int i = 0; i < graphEgdes.length; i++) {
			System.out.print(vertexes.get(i));
			System.out.println(Arrays.toString(graphEgdes[i]));
		}
		System.out.println();

	}

	/**
	 * 深度遍历
	 * 
	 * @param index 出发点
	 */
	public void DFS(int index) {
		int num = vertexes.size();
		if (index < 0 || index > num) {
			return;
		}

		System.out.println(vertexes.get(index));// 打印出当前结点
		visited[index] = true;// 标记访问
		for (int i = 0; i < num; i++) {// 遍历其他点和该点的连通关系
			if (!visited[i] && graphEgdes[index][i] == 1) {
				DFS(i);// 递归遍历
			}
		}
	}

	/**
	 * 
	 * 广度遍历
	 * 
	 * @param index
	 */
	public void BFS(int index) {
		int num = vertexes.size();
		if (index < 0 || index > num) {
			return;
		}
		int front = 0, rear = 0;// 设置前标和后标
		int[] arr = new int[num];// 存储队列
		System.out.println(vertexes.get(index));// 打印出当前结点
		visited[index] = true;// 设置访问过
		arr[rear++] = index;// 将当前访问的结点的索引放到存储对列
		while (front != rear) {
			index = arr[front++];// 取出当前存储队列队头的下表
			for (int i = 0; i < num; i++) {// 遍历其他点和该点的连通关系
				if (!visited[i] && graphEgdes[index][i] == 1) {
					System.out.println(vertexes.get(i));// 打印当前点
					visited[i] = true;// 标记访问
					arr[rear++] = i;// 将访问后的下标存入队列
				}
			}
		}
	}

}

2、邻接表

代码如下:
先是结点和边的代码

package graph_link;

public class Vertex {
	String value;// 结点的值
	Edge firstEdge;// 表示第一条边

	public Vertex(String val) {
		super();
		this.value = val;
	}

	public Vertex() {
		super();
	}

	@Override
	public String toString() {
		return "Vertex [value=" + value + "]";
	}

}


public class Edge {
	int order;// 下一个结点的序号
	int weight;// 权重
	Edge next;// 下一条边

	public Edge() {
		super();
	}

	public Edge(int order, int weight) {
		super();
		this.order = order;
		this.weight = weight;
	}

	@Override
	public String toString() {
		return "Edge [order=" + order + "]";
	}
}

下面是邻接表的详细操作,具体的细节我记录在代码中的注释中

import java.util.ArrayList;
import java.util.List;

/**
 * 有向的邻接表
 * 
 * @author JustGeeker
 *
 */
public class GraphLink {
	List<Vertex> vertexes; // 结点集合
	private boolean[] visited;// 结点访问标记数组
	int numofEdge;// 边的数量

	public GraphLink() {
		// TODO Auto-generated method stub
		super();
	}

	/**
	 * 
	 * @param n 结点的个数
	 */
	public GraphLink(int n) {
		super();
		this.vertexes = new ArrayList<>(n);
		visited = new boolean[n];
		this.numofEdge = 0;
	}

	public void addVertex(String vertex) {
		Vertex v = new Vertex(vertex);
		vertexes.add(v);
	}

	/**
	 * 
	 * @param vertices 结点数组
	 */
	public GraphLink(String[] vertices) {
		super();
		this.vertexes = new ArrayList<>(vertices.length);
		visited = new boolean[vertices.length];
		int len = vertices.length;
		for (String vertex : vertices) {
			addVertex(vertex);
		}
		this.numofEdge = 0;
	}

	/**
	 * 返回结点个数
	 * 
	 * @return
	 */
	public int getVertexsNum() {
		return vertexes.size();
	}

	/**
	 * 返回图中边的个数
	 * 
	 * @return
	 */
	public int getEdgesNum() {
		return numofEdge;
	}

	/**
	 * 根据索引返回结点信息
	 * 
	 * @param i
	 * @return
	 */
	public Vertex getVertex(int i) {
		return vertexes.get(i);
	}

	/**
	 * 根据结点信息返回索引
	 * 
	 * @param vertex
	 * @return
	 */
	public int getIndex(String vertex) {
		for (int i = 0; i < vertexes.size(); i++) {
			if (vertexes.get(i).value.equals(vertex)) {
				return i;
			}
		}

		return -1;
	}

	/**
	 * 插入边
	 * 
	 * @param i      起始结点的索引
	 * @param j      终止结点的索引
	 * @param weight 该边的权值
	 */
	public void addEdge(int i, int j, int weight) {

		int len = vertexes.size();
		if (i < 0 || j < 0 || i > len || j > len) {
			System.out.println("索引越界");
			return;
		}
//		System.out.println(vertexes.get(i) + " " + vertexes.get(j));
		Edge edge = vertexes.get(i).firstEdge;
		if (edge == null) {
			vertexes.get(i).firstEdge = new Edge(j, weight);
			return;
		}

		while (edge.next != null) {
			edge = edge.next;
		}
		edge.next = new Edge(j, weight);
	}

	/**
	 * 根据点来插入边
	 * 
	 * @param vertex1 起始结点
	 * @param vertex2 终止结点
	 * @param weight  权值
	 */
	public void addEdge(String vertex1, String vertex2, int weight) {
		int i = getIndex(vertex1);
		int j = getIndex(vertex2);
		if (i < 0 || j < 0) {
			System.out.println("图中没有该结点");
			return;
		}
		addEdge(i, j, weight);

	}

	/**
	 * 升序遍历
	 * 
	 * @param index 起始结点的索引
	 */
	public void DFS(int index) {
		int len = vertexes.size();
		if (index < 0 || index > len) {
			return;
		}
		System.out.println(vertexes.get(index).value);// 打印出当前结点

		visited[index] = true;// 标记当前结点访问记录
		Edge edge = vertexes.get(index).firstEdge;// 获取当前结点的第一个边
		while (edge != null) {
			int order = edge.order;// 获取与当前结点相连的另一个结点
			if (!visited[order]) {
				DFS(order);// 继续递归下去
			}
			edge = edge.next;// 继续指向当前结点的下一个边
		}

	}

	public void BFS(int index) {
		int len = vertexes.size();

		if (index < 0 || index > len) {
			return;
		}
		int rear = 0, front = 0;// 前标和后标
		int[] queue = new int[len];// 索引队列
		System.out.println(vertexes.get(index).value);
		visited[index] = true;
		queue[rear++] = index;// 将当前结点的索引放入队列
		while (front < rear) {
			index = queue[front++];// 取出队列头部的索引
			Edge edge = vertexes.get(index).firstEdge;// 找到与它相连的边
			while (edge != null) {
				int order = edge.order;// 与它相连的结点的索引
				if (!visited[order]) {
					System.out.println(vertexes.get(order).value);
					visited[order] = true;
					queue[rear++] = order;// 将遍历完成的结点放入队列
				}
				edge = edge.next;// 指向下一条边
			}
		}

	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值