java实现自定义图

1|0图的表示

图的表示方法有俩种,邻接矩阵和邻接表。俩种方法各有特色。

邻接矩阵:边的关系使用二维数组保存。邻接表:边的关系使用链表

本文以邻接矩阵来演示图的基本操作。

2|0图顶点类

  • isVisited代表该节点是否访问过
public class Vertex { //显示A,B,C,D public char label; public boolean isVisited=false; public Vertex(char lable){ this.label=lable; } }

3|0图类

  • 成员变量需要有保存顶点的数组

  • 保存边的二维数组

  • 顶点的最大数目

  • 当前顶点数

  • 栈和队列是dfs和bfs使用的,我调用的是我自己写的api

3|1初始化

public Graph(){ verticesList=new Vertex[maxSize]; adjMat=new int[maxSize][maxSize]; //初始化邻接矩阵,为0代表没有链接 for (int i = 0; i < maxSize; i++) { for (int j = 0; j < maxSize; j++) { adjMat[i][j]=0; } } nVertext=0; stack=new MyStack(maxSize); queue=new MyQueue(maxSize); }

3|2深度优先搜索

public void dfs(){ //首先访问0号顶点 verticesList[0].isVisited=true; //显示该顶点 displayVertex(0); //压入栈 stack.push(0); while (!stack.empty()){ int v=getUnvisitedVertex(stack.peek()); if(v==-1){ //找不到 stack.pop(); } else { verticesList[v].isVisited=true; displayVertex(v); stack.push(v); } } //搜索完成以后复原 for (int i = 0; i < nVertext; i++) { verticesList[i].isVisited=false; } }

3|3广度优先搜索

public void bfs(){ //首先访问0号顶点 verticesList[0].isVisited=true; //显示该顶点 displayVertex(0); //添加到队列 queue.insert(0); while (!queue.empty()){ int v=getUnvisitedVertex(queue.peek()); //添加未被访问的节点 while (v!=-1){ verticesList[v].isVisited=true; displayVertex(v); queue.insert(v); v=getUnvisitedVertex(queue.peek()); } queue.remove(); } //搜索完成以后复原 for (int i = 0; i < nVertext; i++) { verticesList[i].isVisited=false; } }

3|4图的最小生成树

最小生成树就是走最少的路线遍历完整个图,实现和dfs几乎一模一样

我只是做了简单的修改,打印出最小生成树路径

public void mst(){ //首先访问0号顶点 verticesList[0].isVisited=true; //压入栈 stack.push(0); while (!stack.empty()){ int cur=stack.peek(); int v=getUnvisitedVertex(stack.peek()); if(v==-1){ //找不到 stack.pop(); } else { verticesList[v].isVisited=true; stack.push(v); //打印路径 displayVertex(cur); System.out.print("-"); displayVertex(v); System.out.print(" "); } } //搜索完成以后复原 for (int i = 0; i < nVertext; i++) { verticesList[i].isVisited=false; } }

3|5总体实现

public class Graph { //顶点数组 private Vertex[] verticesList; //邻接矩阵adjacent matrix private int[][] adjMat; //顶点的最大数目 private int maxSize=10; //已经添加的顶点 private int nVertext; //栈,dfs private MyStack stack; //队列 private MyQueue queue; public Graph(){ verticesList=new Vertex[maxSize]; adjMat=new int[maxSize][maxSize]; //初始化邻接矩阵,为0代表没有链接 for (int i = 0; i < maxSize; i++) { for (int j = 0; j < maxSize; j++) { adjMat[i][j]=0; } } nVertext=0; stack=new MyStack(maxSize); queue=new MyQueue(maxSize); } /** * 添加顶点 */ public void addVertex(char lable){ verticesList[nVertext++]=new Vertex(lable); } /** * 添加边 */ public void addEdge(int start,int end){ adjMat[start][end]=1; adjMat[end][start]=1; } /** * 获得邻接的未访问过的节点,-1表示找不到 */ public int getUnvisitedVertex(int v){ for(int i=0;i<nVertext;i++){ if(adjMat[v][i]==1&&verticesList[i].isVisited==false) return i; } return -1; } public void dfs(){ //首先访问0号顶点 verticesList[0].isVisited=true; //显示该顶点 displayVertex(0); //压入栈 stack.push(0); while (!stack.empty()){ int v=getUnvisitedVertex(stack.peek()); if(v==-1){ //找不到 stack.pop(); } else { verticesList[v].isVisited=true; displayVertex(v); stack.push(v); } } //搜索完成以后复原 for (int i = 0; i < nVertext; i++) { verticesList[i].isVisited=false; } } public void bfs(){ //首先访问0号顶点 verticesList[0].isVisited=true; //显示该顶点 displayVertex(0); //添加到队列 queue.insert(0); while (!queue.empty()){ int v=getUnvisitedVertex(queue.peek()); //添加未被访问的节点 while (v!=-1){ verticesList[v].isVisited=true; displayVertex(v); queue.insert(v); v=getUnvisitedVertex(queue.peek()); } queue.remove(); } //搜索完成以后复原 for (int i = 0; i < nVertext; i++) { verticesList[i].isVisited=false; } } //最小生成树,链接每个顶点最少的连线,定点数-1 public void mst(){ //首先访问0号顶点 verticesList[0].isVisited=true; //压入栈 stack.push(0); while (!stack.empty()){ int cur=stack.peek(); int v=getUnvisitedVertex(stack.peek()); if(v==-1){ //找不到 stack.pop(); } else { verticesList[v].isVisited=true; stack.push(v); //打印路径 displayVertex(cur); System.out.print("-"); displayVertex(v); System.out.print(" "); } } //搜索完成以后复原 for (int i = 0; i < nVertext; i++) { verticesList[i].isVisited=false; } } public void displayVertex(int v){ System.out.print(verticesList[v].label+""); } }

4|0测试类

结点构成了互相连接的五角星,测试dfs,bfs和图的最小生成树

public class GraphTest { public static void main(String[] args) { Graph graph=new Graph(); graph.addVertex('A'); graph.addVertex('B'); graph.addVertex('C'); graph.addVertex('D'); graph.addVertex('E'); graph.addEdge(0,1); graph.addEdge(0,2); graph.addEdge(0,3); graph.addEdge(0,4); graph.addEdge(1,2); graph.addEdge(1,3); graph.addEdge(1,4); graph.addEdge(2,3); graph.addEdge(2,4); graph.addEdge(3,4); graph.dfs(); System.out.println(); graph.bfs(); System.out.println(); graph.mst(); } }

1587896003849

5|0总结

  1. 图的顶点最重要的是要有一个访问属性
  2. 图的主要操作是增加节点,增加边,遍历,求最小生成树

6|0反思

  1. 从测试中就看出代码写的比较繁琐,预想中构造一个图直接传入边就好了,比如 new Graph('A','B')
  2. 节点类型可以拓展成泛型
  3. dfs和bfs可以使用递归实现,比较懒就不写了
  4. 有时间再修改完善

__EOF__

本文作者程序员小宇
本文链接https://www.cnblogs.com/treasury/p/12781533.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   程序员小宇  阅读(339)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示