数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
2012-08-06 11:37
1081 查看
import java.util.ArrayList; import java.util.List; // 模块E public class AdjMatrixGraph<E> { protected SeqList<E> vertexlist; // 顺序表存储图的顶点集合 protected int[][] adjmatrix; // 图的邻接矩阵 二维图 存储的是每个顶点的名称(A,B,C,D....) private final int MAX_WEIGHT = Integer.MAX_VALUE / 2; // private final int MAX_WEIGHT = 10000; // -------一,构造图:增删改查-------------------------// public AdjMatrixGraph(int n) {// n为顶点的数目 this.vertexlist = new SeqList<E>(n); this.adjmatrix = new int ; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) this.adjmatrix[i][j] = (i == j) ? 0 : MAX_WEIGHT; // 对角线上为0,其他的都为无穷大。 } // 构造函数内一个是字符串数组,一个是edge的set集合 public AdjMatrixGraph(E[] vertices, Edge[] edges) { this(vertices.length); for (int i = 0; i < vertices.length; i++) insertVertex(vertices[i]);// 添加顶点 for (int j = 0; j < edges.length; j++) insertEdge(edges[j]);// 添加边 } // 构造函数内一个是数组集合,一个是edge的set集合 public AdjMatrixGraph(SeqList<E> list, Edge[] edges) { this(list.length()); this.vertexlist = list; for (int j = 0; j < edges.length; j++) insertEdge(edges[j]); } // 显示出一共顶点的数目 public int vertexCount() { return this.vertexlist.length(); } // 根据编号得到该顶点 public E get(int i) { return this.vertexlist.get(i); } public boolean insertVertex(E vertex) { // 插入一个顶点,若插入成功,返回true return this.vertexlist.add(vertex); } public boolean insertEdge(int i, int j, int weight) // 插入一条权值为weight的边<vi,vj>,若该边已有,则不插入 { if (i >= 0 && i < vertexCount() && j >= 0 && j < vertexCount() && i != j && adjmatrix[i][j] == MAX_WEIGHT) { // 先判断该边两个顶点的编号是否在范围,该边的值是否为最大值,来确定所添加边的值是否存在; this.adjmatrix[i][j] = weight;// 添加权值 return true; } return false; } public boolean insertEdge(Edge edge) { if (edge != null) ; return insertEdge(edge.start, edge.dest, edge.weight); } public String toString() { String str = "顶点集合: " + vertexlist.toString() + "\n"; str += "邻近矩阵: \n"; int n = vertexCount(); for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { if (adjmatrix[i][j] == MAX_WEIGHT) str += " ∞";// 最大值(不存在)的时候的显示方式; else str += " " + adjmatrix[i][j];// 每一个顶点到其他顶点的权值 } str += "\n"; } return str; } public boolean removeEdge(int i, int j) // 删除边〈vi,vj〉,若成功,返回T { if (i >= 0 && i < vertexCount() && j >= 0 && j < vertexCount() && i != j && this.adjmatrix[i][j] != MAX_WEIGHT) { // 判断该边的两个顶点是否存在,以及改边的值是否为最大值来判断改边是否存在; this.adjmatrix[i][j] = MAX_WEIGHT; // 设置该边的权值为无穷大,说明已不存在; return true; } return false; } public boolean removeVertex(int v) // 删除序号为v的顶点及其关联的边 { int n = vertexCount(); // 删除之前的顶点数 if (v >= 0 && v < n) {// V的要求范围 this.vertexlist.remove(v); // 删除顺序表的第i个元素,顶点数已减一 for (int i = v; i < n - 1; i++) for (int j = 0; j < n; j++) this.adjmatrix[i][j] = this.adjmatrix[i + 1][j]; // 邻接矩阵:删除点以下往上移动一位 for (int j = v; j < n - 1; j++) for (int i = 0; i < n - 1; i++) this.adjmatrix[i][j] = this.adjmatrix[i][j + 1]; // 邻接矩阵:删除点以右往左移动一位 return true; } return false; } public int getFirstNeighbor(int v) // 返回顶点v的第一个邻接顶点的序号 { return getNextNeighbor(v, -1); } // 若不存在第一个邻接顶点,则返回-1 public int getNextNeighbor(int v, int w) { // 返回v在w后的下一个邻接顶点 if (v >= 0 && v < vertexCount() && w >= -1 && w < vertexCount()// 对v // w的范围限定 && v != w) for (int j = w + 1; j < vertexCount(); j++) // w=-1时,j从0开始寻找下一个邻接顶点 if (adjmatrix[v][j] > 0 && adjmatrix[v][j] < MAX_WEIGHT) // 遍历和v相关的点,得到下一个点 return j; return -1; } // -------二,最小生成树-------------------------// /* * 普里姆算法的基本思想: 取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w。 在添加的顶点 w * 和已经在生成树上的顶点v之间必定存在一条边, 并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。 * 之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。 */ public AdjMatrixGraph minSpanTree_prim() { Edge[] mst = new Edge[this.vertexCount() - 1]; // n个顶点最小生成树有n-1条边 int un; List<Integer> u = new ArrayList<Integer>();// 存放所有已访问过的顶点集合 u.add(0);// 起始点默认为标识为0的顶点 for (int i = 0; i < this.vertexCount() - 1; i++) { int minweight = MAX_WEIGHT;// 最小边的时候,权值 int minstart = MAX_WEIGHT;// 最小边的时候,起点 int mindest = MAX_WEIGHT;// 最小边的时候,终点 for (int j = 0; j < u.size(); j++) { un = u.get(j); for (int k = 0; k < this.vertexCount(); k++) { // 获取最小值的条件:1.该边比当前情况下的最小值小;2.该边还未访问过; if ((minweight > adjmatrix[un][k]) && (!u.contains(k))) { minweight = adjmatrix[un][k]; minstart = un; mindest = k; } } } System.out.println("一次遍历所添加的最小边:他的权值,起点,终点分别为:weight:" + minweight + "start:" + minstart + "dest:" + mindest); u.add(mindest); Edge e = new Edge(minstart, mindest, adjmatrix[minstart][mindest]); mst[i] = e; } return new AdjMatrixGraph(this.vertexlist, mst); // 构造最小生成树相应的图对象 } /* * public AdjMatrixGraph minSpanTree_kruskal() { } */ // -------三,图的遍历(广度遍历,深度遍历)-------------------------// public void DFStraverse() { int n = this.vertexCount(); boolean[] visited = new boolean ; for (int i = 1; i < n; i++) { visited[i] = false; } // 编号0为起始点,进行一次深度优先遍历(一次得到一个连通分量) for (int j = 0; j < n; j++) { if (!visited[j]) { System.out.println("以该顶点为" + j + "起始点的遍历:"); this.DFS(j, visited); } } } // 参数1:遍历起始点的编号,参数2:记录各个顶点是否被访问过 public void DFS(int v, boolean[] visited2) { boolean[] visited = visited2; visited[v] = true; System.out.println("遍历顶点" + v); for (int w = this.getFirstNeighbor(v); w >= 0; w = this .getNextNeighbor(v, w)) { if (!visited[w]) { visited[w] = true; DFS(w, visited); } } } public void BFStraverse() { int n = this.vertexCount(); boolean[] visited = new boolean ; MyQueue myqueue = new MyQueue(); for (int i = 1; i < n; i++) { visited[i] = false; } for (int j = 0; j < n; j++) { if (!visited[j]) { visited[j] = true; System.out.println("遍历起点:" + j); myqueue.EnQueue(j); while (!myqueue.empty()) { int v = (Integer) myqueue.DeQueue(); System.out.println("遍历点:" + v); for (int w = this.getFirstNeighbor(v); w >= 0; w = this .getNextNeighbor(v, w)) { if (!visited[w]) { visited[w] = true; myqueue.EnQueue(w); } } } } } } // -------四,图的最短路径Dijkstra算法-------------------------// public void Dijkstra() { int n = this.vertexCount(); int minweight = MAX_WEIGHT; int minUn = 0; int[] minmatrix = new int ;// 存放当前起始点到其余各个顶点的距离; boolean[] isS = new boolean ;// 判断各个是否被访问过 String[] route = new String ;// 每个字符串是显示对应顶点最短距离的路径; for (int i = 1; i < n; i++) {// 初始化 minmatrix[i] = adjmatrix[0][i]; isS[i] = false; route[i] = "起点->" + i; } for (int i = 1; i < n; i++) { // 选择 当前 和起点 连通的,且值最小的顶点; for (int k = 1; k < n; k++) { if (!isS[k]) { if (minmatrix[k] < minweight) { minweight = minmatrix[k]; minUn = k; } } } isS[minUn] = true;// 将该点设置为已访问; for (int j = 1; j < n; j++) { if (!isS[j]) {// 判断:该顶点还没加入到S中/属于U-S; if (minweight + adjmatrix[minUn][j] < minmatrix[j]) { // 通过当下最小值 访问到得其他顶点的距离小于原先的最小值 则进行交换值 minmatrix[j] = minweight + adjmatrix[minUn][j]; route[j] = route[minUn] + "->" + j; } } } minweight = MAX_WEIGHT;// 因为要放到下一个循环中,所以一定要重设置一下,回到最大值 } for (int m = 1; m < n; m++) { System.out.println("从V0出发到达" + m + "点"); if (minmatrix[m] == MAX_WEIGHT) { System.out.println("没有到达该点的路径"); } else { System.out.println("当前从V0出发到达该点的最短距离:" + minmatrix[m]); System.out.println("当前从V0出发到达该点的最短距离:" + route[m]); } } } // -------五,图的连通性-------------------------// public boolean isConnect() { int n = this.vertexCount(); boolean[] visited = new boolean ; // 记录不能一次深度优先遍历通过的数目 // 全部顶点作为出发点开始遍历,如果全部都不能一次遍历通过(notConnectNum == n),说明该图不连通。 int notConnectNum = 0; for (int j = 0; j < n; j++) { for (int i = 0; i < n; i++) { visited[i] = false; } this.DFS(j, visited); for (int k = 0; k < n; k++) { System.out.println(visited[k]); if (visited[k] == false) { notConnectNum++; break;// 一旦有没有被遍历到的顶点(说明该顶点不属于该连通分量),跳出循环 } } } if (notConnectNum == n) { System.out.println("此图是不连通的"); return false; } else { System.out.println("此图是连通的"); return true; } } // -------六,图的拓扑排序-------------------------// public void topologicalSort() { int n = this.vertexCount(); int[] indegree = new int ; MyStack mystack = new MyStack(); String route = "拓扑排序出发:"; int count = 0; for (int i = 0; i < n; i++) { indegree[i] = 0; for (int j = 0; j < n; j++) {//获取每一个顶点的入度 if (adjmatrix[j][i] != 0 && adjmatrix[j][i] != MAX_WEIGHT) { indegree[i] += 1; } }//先将入度为0的顶点加入到栈中 if (indegree[i] == 0) { mystack.push(i); } } while (!mystack.empty()) { int v = (Integer) mystack.pop();//从栈中删除该顶点 route += "->" + v; ++count; for (int w = this.getFirstNeighbor(v); w >= 0; w = this .getNextNeighbor(v, w)) { indegree[w] -= 1;//因为该顶点被“删除”,所有以该顶点为弧尾的边的弧头的入度减一 if (indegree[w] == 0) { mystack.push(w);//先将入度为0的顶点加入到栈中 } } } if (count < n) {//当经历拓扑排序遍历后,所有顶点都被“删除”时(count=n),此时实现拓扑排序 System.out.println("存在回路,不满足拓扑排序的条件"); } else { System.out.println("实现拓扑排序" + route); } } }
相关文章推荐
- 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
- 数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径
- 图的遍历和生成树求解实现|图遍历,生成树,实现,邻接矩阵,邻接表,深度广度遍历,最小生成树
- 图(有向图,无向图)的邻接矩阵表示C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency matrix
- Java实现图:邻接矩阵表示、深度优先搜索、广度优先搜索、无向图的最小生成树
- (c++)数据结构与算法之图:邻接矩阵、深度广度遍历、构造最小生成树(prim、kruskal算法)
- 利用广度优先遍历(BFS)计算最短路径 - Java实现
- 数据结构:图的存储、图的遍历、最小生成树、最短路径、拓扑排序
- Java实现利用广度优先遍历(BFS)计算最短路径的方法
- 基于邻接矩阵实现图的深度和广度遍历(JAVA实现)
- 图(有向图)的邻接表表示 C++实现(遍历,拓扑排序,最短路径,最小生成树) Implement of digraph and undigraph using adjacency list
- 数据结构-图-as3实现-有向图 图存储(邻接矩阵),广度深度遍历
- 单源最短路径、最小生成树及堆的Java实现
- C数据结构(文件操作,随机数,排序,栈和队列,图和遍历,最小生成树,最短路径)程序例子
- [数据结构]--图(图的遍历,最小生成树,最短路径算法)
- 数据结构和算法之:图的深度优先和广度优先遍历及其Java实现
- 存储结构与邻接矩阵,深度优先和广度优先遍历及Java实现
- 邻接矩阵c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)
- 数据结构--图的理解:深度优先和广度优先遍历及其 Java 实现
- 邻接表c源码(构造邻接矩阵,深度优先遍历,广度优先遍历,最小生成树prim,kruskal算法)