图是一种复杂的非线性结构,其中任意两个节点都可能相连.图G一般由顶点集合V和边集合E组成.E由V中顶点的偶对组成,表示为 G(V,E).
图有多重存储结构, 常用的有 邻接矩阵、 临接表、 逆临接表、 十字链表。 本篇以临接矩阵和临接表方式演示
实现代码如下:
1 public class Graph { 2 //标记节点是否已访问过了 3 private boolean[] isVisit = {false,false,false,false,false,false,false,false,false,false}; 4 5 public static void main(String[] args) { 6 new Graph().table(); 7 } 8 9 /** 10 * 11 * @Title: matrix 12 * @Description: TODO 图的邻接矩阵表示 13 * @param 设定文件 14 * @return void 返回类型 15 * @throws 16 */ 17 public void matrix() { 18 19 //顶点表 20 Node[] nodes = {new Node(0),new Node(1),new Node(2),new Node(3),new Node(4)}; 21 22 23 24 //无向图的临接矩阵存储,对称矩阵,这个矩阵描述了图的边集合 25 //边表, 不带权,i表示行标, j表示列标.第i行表示第i个定点(i对应nodes顶点的key值和下标), 26 //第i个节点指向的节点key 作为j的下标, 赋值1,表示有连接 27 int[][] table = { 28 {0, 1, 0, 1, 0},//第0号定点指向了第1号节点和第3号节点 29 {1, 0, 0, 1, 0}, 30 {0, 0, 0, 0, 0}, 31 {1, 1, 0, 0, 1}, 32 {0, 0, 0, 1, 0}, 33 }; 34 35 //有向图, 36 //第i行的非0节点,表示顶点i的出度 37 //第i列的非0节点,表示顶点i的入度 38 //定点不能指向自己,主对角线为0 39 int[][] table2 = { 40 {0, 1, 0, 1, 0},//第0号节点指向了第1号节点和第3号节点 41 {1, 0, 0, 0, 1}, 42 {0, 0, 0, 0, 0}, 43 {1, 0, 1, 0, 1}, 44 {0, 1, 0, 1, 0}, 45 }; 46 47 //对于带权边的表示:用权值替换1,用MAX_VALUE替换0 48 } 49 50 /** 51 * 52 * @Title: table 53 * @Description: TODO 图的临接表表示 54 * @param 设定文件 55 * @return void 返回类型 56 * @throws 57 */ 58 public void table() { 59 60 //临接表表示法类似与 HashMap 的存储结构.数组与链表组合.数组的每个节点都是一个链表的头结点 61 //顶点表 62 Vertex_node[] nodes = {new Vertex_node(0),new Vertex_node(1),new Vertex_node(2),new Vertex_node(3),new Vertex_node(4)}; 63 64 //有向图 65 nodes[0].head = new Side_node(1,new Side_node(4,null));//指向1号和4号节点 66 nodes[1].head = new Side_node(2,new Side_node(3,null));//指向3号和2号节点 67 nodes[2].head = new Side_node(1,null); //指向1号节点 68 nodes[3].head = new Side_node(0,new Side_node(4,null));//指向0/4号节点 69 nodes[4].head = new Side_node(1,null); //指向1号节点 70 71 //数组元素表示顶点,数组元素的链表,表示这个元素的边集合 72 73 //每个顶点的初度是边表的长度 74 //入度需要扫描整个临接表, 75 76 //对于带权边的表示:需要在 side_node 类中添加一个 value 域,存放权值 77 78 79 printGraph(nodes); 80 81 //图的遍历 82 //深度优先搜素 83 84 85 //深度优先搜索 86 System.out.println("深度优先搜索"); 87 DFS(nodes,0); 88 89 for(int i = 0; i < isVisit.length; i++) { 90 isVisit[i] = false; 91 } 92 93 //广度优先搜索 94 System.out.println("广度优先搜索"); 95 BFS(nodes,0); 96 97 98 99 100 101 } 102 103 /** 104 * @Title: BFS 105 * @Description: TODO 广度优先搜索 106 * @param @param nodes 邻接表方式存储的 顶点集合 107 * @param @param index 第一个访问的顶点,index应小于nodes.length 108 * @return void 返回类型 109 * @throws 110 */ 111 private void BFS(Vertex_node[] nodes, int index) { 112 //队列用LinkedList 113 Queue<Integer> queue = new LinkedList<Integer>(); 114 115 116 117 //访问第一个节点 118 if(index >= 0 && index < nodes.length) { 119 120 isVisit[index] = true; 121 System.out.println("visited :"+nodes[index].key); 122 queue.add(nodes[index].key);//入队 123 } 124 125 //循环条件是队列不为null 126 while(!queue.isEmpty()) { 127 int idx = queue.poll();//出队 128 129 Side_node n = nodes[idx].head; 130 while(n != null) { 131 132 // if the node is not visited, visit that and add that to queue 133 if(!isVisit[n.key]) { 134 //visite 135 isVisit[n.key] = true; 136 System.out.println("visited :"+n.key); 137 //入队列 138 queue.add(n.key); 139 } 140 141 n = n.next; 142 143 } 144 145 146 } 147 148 } 149 150 151 152 /** 153 * 154 * @Title: DFS 155 * @Description: TODO 深度优先搜索 156 * @param @param nodes 邻接表方式存储的 顶点集合 157 * @param @param index 第一个访问的顶点,index应小于nodes.length 158 * @return void 返回类型 159 * @throws 160 */ 161 private void DFS(Vertex_node[] nodes, int index) { 162 //节点 index 是否已访问 163 if(isVisit[index] || index >= nodes.length) { 164 return; 165 } 166 //访问, --print 167 isVisit[index] = true; 168 System.out.println("visited :"+nodes[index].key); 169 170 //递归nodes[index]出度节点 171 Side_node n = nodes[index].head; 172 while(n != null) { 173 if(!isVisit[n.key]) 174 DFS(nodes, n.key); 175 n = n.next; 176 177 } 178 179 } 180 181 private void printGraph(Vertex_node[] nodes) { 182 // TODO Auto-generated method stub 183 for(Vertex_node n : nodes) { 184 System.out.print(n.key+":--> "); 185 186 Side_node n1 = n.head; 187 while(n1 != null) { 188 System.out.print(n1.key+" --> "); 189 n1 = n1.next; 190 191 } 192 193 System.out.println(); 194 } 195 196 } 197 198 class Node{ 199 public int key;//节点的名称.比如第key号节点,不可重复 200 public int value;//权值 201 202 public Node(int key) { 203 super(); 204 this.key = key; 205 } 206 public Node(int key, int value) { 207 super(); 208 this.key = key; 209 this.value = value; 210 } 211 public Node() { 212 } 213 214 215 } 216 217 218 /** 219 * 220 * @ClassName: Vertex_node 221 * @Description: TODO 临接表表示方式的 顶点类 222 * @author: zw 223 * @date: 2018年3月26日 下午3:17:46 224 */ 225 class Vertex_node{ 226 public int key;//节点的名称.比如第key号节点,不可重复 227 228 public Side_node head;//出度链表的首结点 229 230 public Vertex_node(int key) { 231 super(); 232 this.key = key; 233 } 234 public Vertex_node(int key, Side_node head) { 235 super(); 236 this.key = key; 237 this.head = head; 238 } 239 public Vertex_node() { 240 } 241 242 243 } 244 245 /** 246 * 247 * @ClassName: Side_node 248 * @Description: TODO 临接表表示方式的 边表节点类 249 * @author: zw 250 * @date: 2018年3月26日 下午3:18:39 251 */ 252 class Side_node{ 253 public int key;//节点的名称.比如第key号节点,不可重复 254 255 public Side_node next;//兄弟节点 256 257 public Side_node(int key) { 258 super(); 259 this.key = key; 260 this.next = null; 261 } 262 public Side_node(int key, Side_node next) { 263 super(); 264 this.key = key; 265 this.next = next; 266 } 267 public Side_node() { 268 } 269 270 } 271 }
输出结果
0:--> 1 --> 4 -->
1:--> 2 --> 3 -->
2:--> 1 -->
3:--> 0 --> 4 -->
4:--> 1 -->
深度优先搜索
visited :0
visited :1
visited :2
visited :3
visited :4
广度优先搜索
visited :0
visited :1
visited :4
visited :2
visited :3