个人随笔
目录
图的存储结构之十字链表(Java实现)
2020-04-22 23:17:17

我们想要知道出度方向的顶点,可以使用邻接表,我们要了解入度就需要使用逆邻接表。但是我们既想要了解入度有想要了解出度,那么我们该如何处理?

这时就需要使用到有向图的一种存储方法:十字链表

顶点表结点结构

  1. firstin表示入边表头指针,指向该顶点的入边表中第一个结点。
  2. firstout表示出边表头指针,指向该顶点的出边表中第一个结点。

边表结点结构

  1. tailvex是指弧起点在顶点表的下标
  2. headvex是指弧终点在顶点表的下标。
  3. headlink是指入边表指针域,指向终点相同的下一条边
  4. taillink是指边表指针域,指向起点相同的下一条边。
  5. 如果是网,我们还要在其中加入权值域,来存储权值

  1. 我们可以看做横向是出度,竖向是入度
  2. 顶点的出度和入度。除了结构复杂一点外,其实创建图算法的时间复杂度和邻接表是相同的,因此很好的应用在有向图中。
  3. 注意:整张图的出度和入度是一致的(不是某个顶点,而是这张图)

代码实现:

  1. //十字链表
  2. public class OrthogonalList {
  3. private int MAXVEX;
  4. private VertexNode[] verArr;
  5. // 顶点数组赋值
  6. public OrthogonalList(String[] arr) {
  7. this.MAXVEX = arr.length;
  8. this.verArr = new VertexNode[this.MAXVEX];
  9. for (int i = 0; i < arr.length; i++) {
  10. this.verArr[i] = new VertexNode(arr[i]);
  11. }
  12. }
  13. //获取顶点在顶点数组中的位置
  14. private int getPosition(String str) {
  15. int pos = 0;
  16. for(int i=0;i<this.MAXVEX;i++){
  17. if(this.verArr[i].getData().equals(str)){
  18. pos=i;
  19. break;
  20. }
  21. }
  22. return pos;
  23. }
  24. /**
  25. * 输入的是边数组
  26. * @param strArr
  27. */
  28. public void addAdj(String[][] strArr) {
  29. for (int i = 0; i < strArr.length; i++) {
  30. //弧的起点在顶点数组中的下标
  31. int tailvex = getPosition(strArr[i][0]);
  32. //弧终点在顶点数组中的下标
  33. int headvex = getPosition(strArr[i][1]);
  34. //初始化边表邻接点
  35. EdgeNode adj = new EdgeNode();
  36. //设置位置开始位置
  37. adj.setTailvex(tailvex);
  38. //设置结束位置
  39. adj.setHeadvex(headvex);
  40. //获取开始节点的出边表邻接点
  41. EdgeNode firstout = this.verArr[tailvex].getFristout();
  42. //获取结束节点的入边表邻接点
  43. EdgeNode firstin = this.verArr[headvex].getFristin();
  44. //直接使用头插法
  45. this.verArr[tailvex].setFristout(adj);
  46. if (firstout != null) {
  47. adj.setTaillink(firstout);
  48. }
  49. /**
  50. * 尾插法
  51. //处理开始节点的出边表(邻接矩阵)
  52. if (firstout == null) {
  53. this.verArr[tailvex].setFristout(adj);
  54. } else {
  55. //这里是找到最后的出边表,其实可以放在第一个即可
  56. while (true) {
  57. if (firstout.getTaillink() != null) {
  58. firstout = firstout.getTaillink();
  59. } else {
  60. firstout.setTaillink(adj);
  61. break;
  62. }
  63. }
  64. }
  65. **/
  66. //直接使用头插法
  67. this.verArr[headvex].setFristin(adj);
  68. if (firstin != null) {
  69. adj.setHeadlink(firstin);
  70. }
  71. /**
  72. * 尾插法
  73. //处理结束节点的入边表(逆邻接矩阵)
  74. if (firstin == null) {
  75. this.verArr[headvex].setFristin(adj);
  76. } else {
  77. //这里也可以在
  78. while (true) {
  79. if (firstin.getHeadlink() != null) {
  80. firstin = firstin.getHeadlink();
  81. } else {
  82. firstin.setHeadlink(adj);
  83. break;
  84. }
  85. }
  86. }
  87. **/
  88. }
  89. }
  90. /**
  91. * 获取入度
  92. * @param str
  93. * @return
  94. */
  95. public int getIndegree(String str) {
  96. int i = 0;
  97. int pos=getPosition(str);
  98. EdgeNode temp = this.verArr[pos].getFristin();
  99. if (temp == null)
  100. return i;
  101. while (true) {
  102. if (temp != null) {
  103. i++;
  104. temp = temp.getHeadlink();
  105. } else {
  106. break;
  107. }
  108. }
  109. return i;
  110. }
  111. /**
  112. * 获取出度
  113. * @param str
  114. * @return
  115. */
  116. public int getOutdegree(String str) {
  117. int i = 0;
  118. int pos=getPosition(str);
  119. EdgeNode temp = this.verArr[pos].getFristout();
  120. if (temp == null)
  121. return i;
  122. while (true) {
  123. if (temp != null) {
  124. i++;
  125. temp = temp.getTaillink();
  126. } else {
  127. break;
  128. }
  129. }
  130. return i;
  131. }
  132. public static void main(String[] args) {
  133. // TODO Auto-generated method stub
  134. String[] str={"v0","v1","v2","v3"};
  135. OrthogonalList adj=new OrthogonalList(str);
  136. String[][] edges=new String[][]{
  137. {"v0","v3"},
  138. {"v1","v0"},
  139. {"v1","v2"},
  140. {"v2","v0"},
  141. {"v2","v1"}
  142. };
  143. adj.addAdj(edges);
  144. //出度
  145. System.out.println(adj.getOutdegree("v1"));
  146. //入度
  147. System.out.println(adj.getIndegree("v0"));
  148. }
  149. }
  150. // 顶点表节点
  151. class VertexNode {
  152. private String data = null;
  153. private EdgeNode fristin = null;// 入边表(顶点为弧尾)
  154. private EdgeNode fristout = null;// 出边表(顶点为弧头)
  155. public VertexNode(String data) {
  156. super();
  157. this.data = data;
  158. }
  159. public String getData() {
  160. return data;
  161. }
  162. public void setData(String data) {
  163. this.data = data;
  164. }
  165. public EdgeNode getFristin() {
  166. return fristin;
  167. }
  168. public void setFristin(EdgeNode fristin) {
  169. this.fristin = fristin;
  170. }
  171. public EdgeNode getFristout() {
  172. return fristout;
  173. }
  174. public void setFristout(EdgeNode fristout) {
  175. this.fristout = fristout;
  176. }
  177. }
  178. //边表节点
  179. class EdgeNode {
  180. private int tailvex = -1;// 弧的起点在顶点数组中的下标
  181. private int headvex = -1;// 弧终点在顶点数组中的下标
  182. private EdgeNode headlink = null;// 指向下一个终点相同的邻接点
  183. private EdgeNode taillink = null;// 指向下一个起点相同的邻接点
  184. public int getTailvex() {
  185. return tailvex;
  186. }
  187. public void setTailvex(int tailvex) {
  188. this.tailvex = tailvex;
  189. }
  190. public int getHeadvex() {
  191. return headvex;
  192. }
  193. public void setHeadvex(int headvex) {
  194. this.headvex = headvex;
  195. }
  196. public EdgeNode getHeadlink() {
  197. return headlink;
  198. }
  199. public void setHeadlink(EdgeNode headlink) {
  200. this.headlink = headlink;
  201. }
  202. public EdgeNode getTaillink() {
  203. return taillink;
  204. }
  205. public void setTaillink(EdgeNode taillink) {
  206. this.taillink = taillink;
  207. }
  208. }

运行结果如下:

  1. 2
  2. 2
 702

啊!这个可能是世界上最丑的留言输入框功能~


当然,也是最丑的留言列表

有疑问发邮件到 : suibibk@qq.com 侵权立删
Copyright : 个人随笔   备案号 : 粤ICP备18099399号-2