数据结构-图-Java实现:有向图 图存储(邻接矩阵),最小生成树,广度深度遍历,图的连通性,最短路径

时间:2021-08-11 11:39:06
数据结构存储integerini算法string
  1. import java.util.ArrayList;  
  2.   
  3. import java.util.List;  
  4.   
  5.    
  6.   
  7. // 模块E  
  8.   
  9. public class AdjMatrixGraph<E> {  
  10.   
  11. protected SeqList<E> vertexlist; // 顺序表存储图的顶点集合  
  12.   
  13.    
  14.   
  15. protected int[][] adjmatrix; // 图的邻接矩阵 二维图 存储的是每个顶点的名称(A,B,C,D....)  
  16.   
  17.    
  18.   
  19. private final int MAX_WEIGHT = Integer.MAX_VALUE / 2;  
  20.   
  21.    
  22.   
  23. // private final int MAX_WEIGHT = 10000;  
  24.   
  25.    
  26.   
  27. // -------一,构造图:增删改查-------------------------//  
  28.   
  29. public AdjMatrixGraph(int n) {// n为顶点的数目  
  30.   
  31. this.vertexlist = new SeqList<E>(n);  
  32.   
  33. this.adjmatrix = new int[n][n];  
  34.   
  35. for (int i = 0; i < n; i++)  
  36.   
  37. for (int j = 0; j < n; j++)  
  38.   
  39. this.adjmatrix[i][j] = (i == j) ? 0 : MAX_WEIGHT;  
  40.   
  41. // 对角线上为0,其他的都为无穷大。  
  42.   
  43. }  
  44.   
  45.    
  46.   
  47. // 构造函数内一个是字符串数组,一个是edge的set集合  
  48.   
  49. public AdjMatrixGraph(E[] vertices, Edge[] edges) {  
  50.   
  51. this(vertices.length);  
  52.   
  53. for (int i = 0; i < vertices.length; i++)  
  54.   
  55. insertVertex(vertices[i]);// 添加顶点  
  56.   
  57. for (int j = 0; j < edges.length; j++)  
  58.   
  59. insertEdge(edges[j]);// 添加边  
  60.   
  61. }  
  62.   
  63.    
  64.   
  65. // 构造函数内一个是数组集合,一个是edge的set集合  
  66.   
  67. public AdjMatrixGraph(SeqList<E> list, Edge[] edges) {  
  68.   
  69. this(list.length());  
  70.   
  71. this.vertexlist = list;  
  72.   
  73. for (int j = 0; j < edges.length; j++)  
  74.   
  75. insertEdge(edges[j]);  
  76.   
  77. }  
  78.   
  79.    
  80.   
  81. // 显示出一共顶点的数目  
  82.   
  83. public int vertexCount() {  
  84.   
  85. return this.vertexlist.length();  
  86.   
  87. }  
  88.   
  89.    
  90.   
  91. // 根据编号得到该顶点  
  92.   
  93. public E get(int i) {  
  94.   
  95. return this.vertexlist.get(i);  
  96.   
  97. }  
  98.   
  99.    
  100.   
  101. public boolean insertVertex(E vertex) { // 插入一个顶点,若插入成功,返回true  
  102.   
  103.    
  104.   
  105. return this.vertexlist.add(vertex);  
  106.   
  107. }  
  108.   
  109.    
  110.   
  111. public boolean insertEdge(int i, int j, int weight)  
  112.   
  113. // 插入一条权值为weight的边<vi,vj>,若该边已有,则不插入  
  114.   
  115. {  
  116.   
  117. if (i >= 0 && i < vertexCount() && j >= 0 && j < vertexCount()  
  118.   
  119. && i != j && adjmatrix[i][j] == MAX_WEIGHT) {  
  120.   
  121. // 先判断该边两个顶点的编号是否在范围,该边的值是否为最大值,来确定所添加边的值是否存在;  
  122.   
  123. this.adjmatrix[i][j] = weight;// 添加权值  
  124.   
  125. return true;  
  126.   
  127. }  
  128.   
  129. return false;  
  130.   
  131. }  
  132.   
  133.    
  134.   
  135. public boolean insertEdge(Edge edge) {  
  136.   
  137. if (edge != null)  
  138.   
  139. ;  
  140.   
  141. return insertEdge(edge.start, edge.dest, edge.weight);  
  142.   
  143. }  
  144.   
  145.    
  146.   
  147. public String toString() {  
  148.   
  149. String str = "顶点集合: " + vertexlist.toString() + "\n";  
  150.   
  151. str += "邻近矩阵:    \n";  
  152.   
  153. int n = vertexCount();  
  154.   
  155. for (int i = 0; i < n; i++) {  
  156.   
  157. for (int j = 0; j < n; j++) {  
  158.   
  159. if (adjmatrix[i][j] == MAX_WEIGHT)  
  160.   
  161. str += " ∞";// 最大值(不存在)的时候的显示方式;  
  162.   
  163. else  
  164.   
  165. str += " " + adjmatrix[i][j];// 每一个顶点到其他顶点的权值  
  166.   
  167. }  
  168.   
  169. str += "\n";  
  170.   
  171. }  
  172.   
  173. return str;  
  174.   
  175. }  
  176.   
  177.    
  178.   
  179. public boolean removeEdge(int i, int j) // 删除边〈vi,vj〉,若成功,返回T  
  180.   
  181. {  
  182.   
  183. if (i >= 0 && i < vertexCount() && j >= 0 && j < vertexCount()  
  184.   
  185. && i != j && this.adjmatrix[i][j] != MAX_WEIGHT) {  
  186.   
  187. // 判断该边的两个顶点是否存在,以及改边的值是否为最大值来判断改边是否存在;  
  188.   
  189. this.adjmatrix[i][j] = MAX_WEIGHT; // 设置该边的权值为无穷大,说明已不存在;  
  190.   
  191. return true;  
  192.   
  193. }  
  194.   
  195. return false;  
  196.   
  197. }  
  198.   
  199.    
  200.   
  201. public boolean removeVertex(int v) // 删除序号为v的顶点及其关联的边  
  202.   
  203. {  
  204.   
  205. int n = vertexCount(); // 删除之前的顶点数  
  206.   
  207. if (v >= 0 && v < n) {// V的要求范围  
  208.   
  209. this.vertexlist.remove(v); // 删除顺序表的第i个元素,顶点数已减一  
  210.   
  211. for (int i = v; i < n - 1; i++)  
  212.   
  213. for (int j = 0; j < n; j++)  
  214.   
  215. this.adjmatrix[i][j] = this.adjmatrix[i + 1][j]; // 邻接矩阵:删除点以下往上移动一位  
  216.   
  217. for (int j = v; j < n - 1; j++)  
  218.   
  219. for (int i = 0; i < n - 1; i++)  
  220.   
  221. this.adjmatrix[i][j] = this.adjmatrix[i][j + 1]; // 邻接矩阵:删除点以右往左移动一位  
  222.   
  223. return true;  
  224.   
  225. }  
  226.   
  227. return false;  
  228.   
  229. }  
  230.   
  231.    
  232.   
  233. public int getFirstNeighbor(int v) // 返回顶点v的第一个邻接顶点的序号  
  234.   
  235. {  
  236.   
  237. return getNextNeighbor(v, -1);  
  238.   
  239. // 若不存在第一个邻接顶点,则返回-1  
  240.   
  241.    
  242.   
  243. public int getNextNeighbor(int v, int w) { // 返回v在w后的下一个邻接顶点  
  244.   
  245. if (v >= 0 && v < vertexCount() && w >= -1 && w < vertexCount()// 对v  
  246.   
  247. // w的范围限定  
  248.   
  249. && v != w)  
  250.   
  251. for (int j = w + 1; j < vertexCount(); j++)  
  252.   
  253. // w=-1时,j从0开始寻找下一个邻接顶点  
  254.   
  255. if (adjmatrix[v][j] > 0 && adjmatrix[v][j] < MAX_WEIGHT)  
  256.   
  257. // 遍历和v相关的点,得到下一个点  
  258.   
  259. return j;  
  260.   
  261. return -1;  
  262.   
  263. }  
  264.   
  265.    
  266.   
  267. // -------二,最小生成树-------------------------//  
  268.   
  269.    
  270.   
  271. /* 
  272.  
  273. * 普里姆算法的基本思想: 取图中任意一个顶点 v 作为生成树的根,之后往生成树上添加新的顶点 w。 在添加的顶点 w 
  274.  
  275. * 和已经在生成树上的顶点v之间必定存在一条边, 并且该边的权值在所有连通顶点 v 和 w 之间的边中取值最小。 
  276.  
  277. * 之后继续往生成树上添加顶点,直至生成树上含有 n-1 个顶点为止。 
  278.  
  279. */  
  280.   
  281.    
  282.   
  283. public AdjMatrixGraph minSpanTree_prim() {  
  284.   
  285. Edge[] mst = new Edge[this.vertexCount() - 1]; // n个顶点最小生成树有n-1条边  
  286.   
  287. int un;  
  288.   
  289. List<Integer> u = new ArrayList<Integer>();// 存放所有已访问过的顶点集合  
  290.   
  291. u.add(0);// 起始点默认为标识为0的顶点  
  292.   
  293. for (int i = 0; i < this.vertexCount() - 1; i++) {  
  294.   
  295. int minweight = MAX_WEIGHT;// 最小边的时候,权值  
  296.   
  297. int minstart = MAX_WEIGHT;// 最小边的时候,起点  
  298.   
  299. int mindest = MAX_WEIGHT;// 最小边的时候,终点  
  300.   
  301. for (int j = 0; j < u.size(); j++) {  
  302.   
  303. un = u.get(j);  
  304.   
  305. for (int k = 0; k < this.vertexCount(); k++) {  
  306.   
  307. // 获取最小值的条件:1.该边比当前情况下的最小值小;2.该边还未访问过;  
  308.   
  309. if ((minweight > adjmatrix[un][k]) && (!u.contains(k))) {  
  310.   
  311. minweight = adjmatrix[un][k];  
  312.   
  313. minstart = un;  
  314.   
  315. mindest = k;  
  316.   
  317. }  
  318.   
  319. }  
  320.   
  321. }  
  322.   
  323. System.out.println("一次遍历所添加的最小边:他的权值,起点,终点分别为:weight:" + minweight  
  324.   
  325. "start:" + minstart + "dest:" + mindest);  
  326.   
  327. u.add(mindest);  
  328.   
  329. Edge e = new Edge(minstart, mindest, adjmatrix[minstart][mindest]);  
  330.   
  331. mst[i] = e;  
  332.   
  333. }  
  334.   
  335. return new AdjMatrixGraph(this.vertexlist, mst); // 构造最小生成树相应的图对象  
  336.   
  337. }  
  338.   
  339.    
  340.   
  341. /* 
  342.  
  343. * public AdjMatrixGraph minSpanTree_kruskal() { } 
  344.  
  345. */  
  346.   
  347.    
  348.   
  349. // -------三,图的遍历(广度遍历,深度遍历)-------------------------//  
  350.   
  351. public void DFStraverse() {  
  352.   
  353. int n = this.vertexCount();  
  354.   
  355. boolean[] visited = new boolean[n];  
  356.   
  357. for (int i = 1; i < n; i++) {  
  358.   
  359. visited[i] = false;  
  360.   
  361. }  
  362.   
  363. // 编号0为起始点,进行一次深度优先遍历(一次得到一个连通分量)  
  364.   
  365. for (int j = 0; j < n; j++) {  
  366.   
  367. if (!visited[j]) {  
  368.   
  369. System.out.println("以该顶点为" + j + "起始点的遍历:");  
  370.   
  371. this.DFS(j, visited);  
  372.   
  373. }  
  374.   
  375. }  
  376.   
  377. }  
  378.   
  379.    
  380.   
  381. // 参数1:遍历起始点的编号,参数2:记录各个顶点是否被访问过  
  382.   
  383. public void DFS(int v, boolean[] visited2) {  
  384.   
  385. boolean[] visited = visited2;  
  386.   
  387. visited[v] = true;  
  388.   
  389. System.out.println("遍历顶点" + v);  
  390.   
  391. for (int w = this.getFirstNeighbor(v); w >= 0; w = this  
  392.   
  393. .getNextNeighbor(v, w)) {  
  394.   
  395. if (!visited[w]) {  
  396.   
  397. visited[w] = true;  
  398.   
  399. DFS(w, visited);  
  400.   
  401. }  
  402.   
  403. }  
  404.   
  405. }  
  406.   
  407.    
  408.   
  409. public void BFStraverse() {  
  410.   
  411. int n = this.vertexCount();  
  412.   
  413. boolean[] visited = new boolean[n];  
  414.   
  415. MyQueue myqueue = new MyQueue();  
  416.   
  417. for (int i = 1; i < n; i++) {  
  418.   
  419. visited[i] = false;  
  420.   
  421. }  
  422.   
  423.    
  424.   
  425. for (int j = 0; j < n; j++) {  
  426.   
  427. if (!visited[j]) {  
  428.   
  429. visited[j] = true;  
  430.   
  431. System.out.println("遍历起点:" + j);  
  432.   
  433. myqueue.EnQueue(j);  
  434.   
  435. while (!myqueue.empty()) {  
  436.   
  437. int v = (Integer) myqueue.DeQueue();  
  438.   
  439. System.out.println("遍历点:" + v);  
  440.   
  441. for (int w = this.getFirstNeighbor(v); w >= 0; w = this  
  442.   
  443. .getNextNeighbor(v, w)) {  
  444.   
  445. if (!visited[w]) {  
  446.   
  447. visited[w] = true;  
  448.   
  449. myqueue.EnQueue(w);  
  450.   
  451. }  
  452.   
  453. }  
  454.   
  455. }  
  456.   
  457. }  
  458.   
  459. }  
  460.   
  461.    
  462.   
  463. }  
  464.   
  465.    
  466.   
  467. // -------四,图的最短路径Dijkstra算法-------------------------//  
  468.   
  469. public void Dijkstra() {  
  470.   
  471. int n = this.vertexCount();  
  472.   
  473. int minweight = MAX_WEIGHT;  
  474.   
  475. int minUn = 0;  
  476.   
  477. int[] minmatrix = new int[n];// 存放当前起始点到其余各个顶点的距离;  
  478.   
  479. boolean[] isS = new boolean[n];// 判断各个是否被访问过  
  480.   
  481. String[] route = new String[n];// 每个字符串是显示对应顶点最短距离的路径;  
  482.   
  483. for (int i = 1; i < n; i++) {// 初始化  
  484.   
  485. minmatrix[i] = adjmatrix[0][i];  
  486.   
  487. isS[i] = false;  
  488.   
  489. route[i] = "起点->" + i;  
  490.   
  491. }  
  492.   
  493. for (int i = 1; i < n; i++) {  
  494.   
  495. // 选择 当前 和起点 连通的,且值最小的顶点;  
  496.   
  497. for (int k = 1; k < n; k++) {  
  498.   
  499. if (!isS[k]) {  
  500.   
  501. if (minmatrix[k] < minweight) {  
  502.   
  503. minweight = minmatrix[k];  
  504.   
  505. minUn = k;  
  506.   
  507. }  
  508.   
  509. }  
  510.   
  511. }  
  512.   
  513. isS[minUn] = true;// 将该点设置为已访问;  
  514.   
  515. for (int j = 1; j < n; j++) {  
  516.   
  517. if (!isS[j]) {// 判断:该顶点还没加入到S中/属于U-S;  
  518.   
  519. if (minweight + adjmatrix[minUn][j] < minmatrix[j]) {  
  520.   
  521. // 通过当下最小值 访问到得其他顶点的距离小于原先的最小值 则进行交换值  
  522.   
  523. minmatrix[j] = minweight + adjmatrix[minUn][j];  
  524.   
  525. route[j] = route[minUn] + "->" + j;  
  526.   
  527. }  
  528.   
  529. }  
  530.   
  531. }  
  532.   
  533. minweight = MAX_WEIGHT;// 因为要放到下一个循环中,所以一定要重设置一下,回到最大值  
  534.   
  535. }  
  536.   
  537. for (int m = 1; m < n; m++) {  
  538.   
  539. System.out.println("从V0出发到达" + m + "点");  
  540.   
  541. if (minmatrix[m] == MAX_WEIGHT) {  
  542.   
  543. System.out.println("没有到达该点的路径");  
  544.   
  545. else {  
  546.   
  547. System.out.println("当前从V0出发到达该点的最短距离:" + minmatrix[m]);  
  548.   
  549. System.out.println("当前从V0出发到达该点的最短距离:" + route[m]);  
  550.   
  551.    
  552.   
  553. }  
  554.   
  555. }  
  556.   
  557. }  
  558.   
  559.    
  560.   
  561. // -------五,图的连通性-------------------------//  
  562.   
  563. public boolean isConnect() {  
  564.   
  565. int n = this.vertexCount();  
  566.   
  567. boolean[] visited = new boolean[n];  
  568.   
  569. // 记录不能一次深度优先遍历通过的数目  
  570.   
  571. // 全部顶点作为出发点开始遍历,如果全部都不能一次遍历通过(notConnectNum == n),说明该图不连通。  
  572.   
  573. int notConnectNum = 0;  
  574.   
  575. for (int j = 0; j < n; j++) {  
  576.   
  577. for (int i = 0; i < n; i++) {  
  578.   
  579. visited[i] = false;  
  580.   
  581. }  
  582.   
  583. this.DFS(j, visited);  
  584.   
  585. for (int k = 0; k < n; k++) {  
  586.   
  587. System.out.println(visited[k]);  
  588.   
  589. if (visited[k] == false) {  
  590.   
  591. notConnectNum++;  
  592.   
  593. break;// 一旦有没有被遍历到的顶点(说明该顶点不属于该连通分量),跳出循环  
  594.   
  595. }  
  596.   
  597. }  
  598.   
  599. }  
  600.   
  601. if (notConnectNum == n) {  
  602.   
  603. System.out.println("此图是不连通的");  
  604.   
  605. return false;  
  606.   
  607. else {  
  608.   
  609. System.out.println("此图是连通的");  
  610.   
  611. return true;  
  612.   
  613. }  
  614.   
  615. }  
  616.   
  617.    
  618.   
  619. // -------六,图的拓扑排序-------------------------//  
  620.   
  621. public void topologicalSort() {  
  622.   
  623. int n = this.vertexCount();  
  624.   
  625. int[] indegree = new int[n];  
  626.   
  627. MyStack mystack = new MyStack();  
  628.   
  629. String route = "拓扑排序出发:";  
  630.   
  631. int count = 0;  
  632.   
  633. for (int i = 0; i < n; i++) {  
  634.   
  635. indegree[i] = 0;  
  636.   
  637. for (int j = 0; j < n; j++) {//获取每一个顶点的入度  
  638.   
  639. if (adjmatrix[j][i] != 0 && adjmatrix[j][i] != MAX_WEIGHT) {  
  640.   
  641. indegree[i] += 1;  
  642.   
  643. }  
  644.   
  645. }//先将入度为0的顶点加入到栈中  
  646.   
  647. if (indegree[i] == 0) {  
  648.   
  649. mystack.push(i);  
  650.   
  651. }  
  652.   
  653. }  
  654.   
  655. while (!mystack.empty()) {  
  656.   
  657. int v = (Integer) mystack.pop();//从栈中删除该顶点  
  658.   
  659. route += "->" + v;  
  660.   
  661. ++count;  
  662.   
  663. for (int w = this.getFirstNeighbor(v); w >= 0; w = this  
  664.   
  665. .getNextNeighbor(v, w)) {  
  666.   
  667. indegree[w] -= 1;//因为该顶点被“删除”,所有以该顶点为弧尾的边的弧头的入度减一  
  668.   
  669. if (indegree[w] == 0) {  
  670.   
  671. mystack.push(w);//先将入度为0的顶点加入到栈中  
  672.   
  673. }  
  674.   
  675. }  
  676.   
  677. }  
  678.   
  679. if (count < n) {//当经历拓扑排序遍历后,所有顶点都被“删除”时(count=n),此时实现拓扑排序  
  680.   
  681. System.out.println("存在回路,不满足拓扑排序的条件");  
  682.   
  683. else {  
  684.   
  685. System.out.println("实现拓扑排序" + route);  
  686.   
  687.    
  688.   
  689. }  
  690.   
  691. }  
  692.   
  693.   
  694. }