package B28_tujiqiyingyong;
import java.util.*;
/**
* @author Fjj
* @Time 2023/3/11 14:01
* @title UnweightedGraph
* @Software: IntelliJ IDEA
* @description TODO
*/
public class UnweightedGraph<V> implements Graph<V> {
/** 定义了数据域vertices 来进行顶点的存储 */
protected List<V> vertices = new ArrayList<>();
/** 定义了数据域neighbors 来在邻接边线性表中 存储边 Adjacency Edge lists */
protected List<List<Edge>> neighbors = new ArrayList<>();
/** 创建一个空的图 */
protected UnweightedGraph(){}
/** 利用边和顶点的数组 进行图的创建 */
protected UnweightedGraph(V[] vertices, int[][] edges){
for (int i = 0; i < vertices.length; i++)
addVertex(vertices[i]);
createAdjacencyLists(edges, vertices.length);
}
/** 利用边和顶点的线性表 进行图的创建 */
protected UnweightedGraph(List<V> vertices, List<Edge> edges){
for (int i = 0; i < vertices.size(); i++)
addVertex(vertices.get(i));
createAdjacencyLists(edges, vertices.size());
}
/** construct a graph for integer vertices 0, 1, 2 and edge list 构造整数顶点0、1、2和边线性表的图 */
protected UnweightedGraph(List<Edge> edges, int numberOfVertices){
for (int i = 0; i < numberOfVertices; i++)
addVertex((V)(Integer.valueOf(i)));
createAdjacencyLists(edges, numberOfVertices);
}
/** 构造整数顶点0、1、2和边数组的图 */
protected UnweightedGraph(int[][] edges, int numberOfVertices){
for (int i = 0; i < numberOfVertices; i++)
addVertex((V)(Integer.valueOf(i)));
createAdjacencyLists(edges, numberOfVertices);
}
/** 利用一个数组中的边 创建邻接线性表 */
private void createAdjacencyLists(int[][] edges, int numberOfVertices){
for (int i = 0; i < edges.length; i++)
addEdge(edges[i][0], edges[i][1]);
}
/** 利用一个线性表中的边 创建邻接线性表 */
private void createAdjacencyLists(List<Edge> edges, int numberOfVertices){
for (Edge edge: edges)
addEdge(edge.u, edge.v);
}
@Override
/** 返回图中的顶点数 */
public int getSize() {
return vertices.size();
}
@Override
/** 返回图的顶点 */
public List<V> getVertices() {
return vertices;
}
@Override
/** 返回指定顶点下标的顶点对象 */
public V getVertex(int index) {
return vertices.get(index);
}
@Override
/** 返回指定顶点v的下标,如果该顶点不在图中则返回-1 */
public int getIndex(V v) {
return vertices.indexOf(v);
}
@Override
/** 返回指定下标的顶点的 邻居 返回顶点u的邻接定点线性表 , Return the degree for a specified vertex */
public List<Integer> getNeighbors(int index) {
List<Integer> result = new ArrayList<>();
for (Edge e: neighbors.get(index))
result.add(e.v);
return result;
}
@Override
/** 返回指定顶点下标的度 与顶点相关联的边的个数 */
public int getDegree(int index) {
return neighbors.get(index).size();
}
@Override
/** 打印边 */
public void printEdges() {
for (int u = 0; u < neighbors.size(); u++){
System.out.print(getVertex(u) + "(" + u + "): ");
for (Edge e:neighbors.get(u))
System.out.print("(" + getVertex(e.u) + ", " + getVertex(e.v) + ") ");
System.out.println();
}
}
@Override
/** 清除图 */
public void clear() {
vertices.clear();
neighbors.clear();
}
@Override
/** 如果将v添加到了图中,返回true; 如果v已经在图中,返回false */
public boolean addVertex(V vertex) {
// System.out.println(vertices.size());
if (!vertices.contains(vertex)){
vertices.add(vertex);
neighbors.add(new ArrayList<>());
return true;
}else
return false;
}
@Override
/** 添加从u到v的边到图中,如果u或者v是无效的,则抛出IllegalArgumentException异常。
* 如果边添加成功则返回true, 如果(u, v)已经在图中则返回false */
public boolean addEdge(int u, int v) {
return addEdge(new Edge(u,v));
}
@Override
/** 添加一条边到邻接边线性表 */
public boolean addEdge(Edge e) {
if (e.u < 0 || e.u > getSize() - 1)
throw new IllegalArgumentException("No such index: " + e.u);
if (e.v < 0 || e.v > getSize() - 1)
throw new IllegalArgumentException("No such index: " + e.v);
if (!neighbors.get(e.u).contains(e)){
neighbors.get(e.u).add(e);
return true;
}else
return false;
}
@Override
/** 从图中移除一个顶点 Remove vertex v and return true if successful 删除顶点v,如果成功则返回true */
public boolean remove(V v) {
return vertices.remove(v);
}
@Override
/** 从图中一处一条边 Remove edge (u, v) and return true if successful */
public boolean remove(int u, int v) {
for (Edge e:neighbors.get(u))
if (e.v == v){
neighbors.get(u).remove(e);
return true;
}
return false;
}
@Override
/** 得到从v开始的 一棵深度优先搜索树 */
public SearchTree dfs(int v) {
// 搜索过的顶点存储,在一个线性表searchOrder中 这里存储的顶点的位置 如:顶点0
List<Integer> searchOrder = new ArrayList<>();
// 每个顶点的父节点存储,在数组parent中
int[] parent = new int[vertices.size()];
// 初始化父节点的存储
for (int i = 0; i < parent.length; i++)
parent[i] = -1;
// Mark visited vertices 使用数组isVisited来表示已经被访问过的顶点
boolean[] isVisited = new boolean[vertices.size()];
// Recursively search 调用辅助方法 dfs(v, parent, searchOrders, isVisited)来完成深度优先搜索
dfs(v, parent, searchOrder, isVisited);
return new SearchTree(v, parent, searchOrder);
}
/** Recursive method for DFS search */
private void dfs(int v, int[] parent, List<Integer> searchOrder, boolean[] isVisited){
searchOrder.add(v);
isVisited[v] = true;
for (Edge e: neighbors.get(v)){ // e.u is v
int w = e.v; // e.v is w 这里是获取V点的边的信息,并用于下面的判断
if (!isVisited[w]){ // 判断 这个顶点 是否访问过了
parent[w] = v; // The parent of vertex w is v w的父节点是v
dfs(w, parent, searchOrder, isVisited); // Recursive search 进行回溯
}
}
}
/** 利用栈来建立深度优先搜索树 */
private SearchTree dfs_stack(int v){
int[] parent = new int[vertices.size()];
for (int i = 0; i < parent.length; i++)
parent[i] = -1;
List<Integer> searchOrder = new ArrayList<>();
// 利用isVisited约束 这个点我们是否走过
boolean[] isVisited = new boolean[vertices.size()];
// 利用stack来进行 进栈与出栈的选择,也就是进行深度优先遍历
Stack<Integer> stack = new Stack<>();
// 先将初始点 推入栈中
stack.push(v);
// 修改我们的 searchOrder 搜索路径
searchOrder.add(v);
// 修改isVisited
isVisited[v] = true;
while (!stack.isEmpty()){
// 将点 推出来
int u = stack.pop();
// 获取与这个点相连的 边
for (Edge e: neighbors.get(u)){ // e.u
int w = e.v;
if (!isVisited[w]){
stack.push(w);
isVisited[w] = true;
}
}
}
return new SearchTree(v, parent, searchOrder);
}
@Override
/** 得到从v开始的 一棵广度优先搜索树 */
public SearchTree bfs(int v) {
// 搜索过的顶点存储,在一个线性表searchOrder中 这里存储的顶点的位置 如:顶点0
List<Integer> searchOrder = new ArrayList<>();
// 每个顶点的父节点存储,在数组parent中
int[] parent = new int[vertices.size()];
for (int i = 0 ; i < parent.length; i++)
parent[i] = -1;
// list used as a queue 使用队列 来进行 广度的判断
java.util.LinkedList<Integer> queue = new java.util.LinkedList<>();
boolean[] isVisited = new boolean[vertices.size()];
// 下面就是BFS的主要代码
queue.offer(v); // Enqueue v
isVisited[v] = true; // Mark it visited
while (!queue.isEmpty()){
int u = queue.poll(); // Dequeue to u
searchOrder.add(u); // u searched
for (Edge e:neighbors.get(u)){ // Note that e.u is u
int w = e.v; // e.v is w
if (!isVisited[w]){
queue.offer(w);
parent[w] = u;
isVisited[w] = true;
}
}
}
return new SearchTree(v, parent, searchOrder);
}
/** SearchTree类 */
public class SearchTree {
private int root; // The root of the tree
private int[] parent; // Store the parent of each vertex 存储每个顶点的父对象 存储对应的边
private List<Integer> searchOrder; // Store the search order 存储搜索顺序
/** Construct a tree with root, parent, and searchOrder */
public SearchTree(int root, int[] parent, List<Integer> searchOrder){
this.root = root;
this.parent = parent;
this.searchOrder = searchOrder;
}
/** Return the root of the tree */
public int getRoot(){
return root;
}
/** Return the parent of vertex v */
public int getParent(int v){
return parent[v];
}
/** Return an array representing search order */
public List<Integer> getSearchOrder(){
return searchOrder;
}
/** Return number of vertices found 输出当前构建的搜索树的节点的个数 */
public int getNumberOfVerticesFound(){
return searchOrder.size();
}
/** Return the path of vertices from a vertex to the root 返回从顶点到根的顶点路径 */
// 这样是 从index 到 根节点
public List<V> getPath(int index){
ArrayList<V> path = new ArrayList<>();
do {
// 先将index位置的顶点 存入
path.add(vertices.get(index));
// 后对 index顶点的 父顶点进行下标获取 从下向根进行获取
index = parent[index];
}
while (index != -1);
return path;
}
/** Print a path from the root to vertex v */
public void printPath(int index){
List<V> path = getPath(index); // index到根节点的路径
System.out.print("A path from " + vertices.get(root) + " to " + vertices.get(index) + ": ");
// path.size() i-- 反过来,从根节点 到index节点的路径
for (int i = path.size() - 1; i >= 0; i--)
System.out.print(path.get(i) + " ");
}
/** Print the whole tree 打印整个树 打印树中所有的边 */
public void printTree(){
System.out.println("Root is: " + vertices.get(root));
System.out.print("Edges: ");
for (int i = 0; i < parent.length; i++){
if (parent[i] != -1){
System.out.print("(" + vertices.get(parent[i]) + ", " + vertices.get(i) + ") ");
}
}
System.out.println();
}
}
}
java语言程序设计UnWeightedGraph图
于 2023-04-07 21:57:59 首次发布