图的基础知识在这两篇博客中:
数据结构——图的基础知识
数据结构——图的应用算法详解
一、图的结构定义
package GraphPackage;
public class GraphNode {
int[][] arc; //边的信息
char[] vex; //顶点信息
int arcnum; //边数目
int vexnum; //顶点数目
int[] visited; //访问标志数组,用来记录节点是否被访问过
public GraphNode(int[][] arc, char[] vex, int arcnum, int vexnum, int[] visited) {
this.arc = arc;
this.vex = vex;
this.arcnum = arcnum;
this.vexnum = vexnum;
this.visited = visited;
}
public GraphNode() {
this.arc = arc;
this.vex = vex;
this.arcnum = arcnum;
this.vexnum = vexnum;
this.visited = visited;
}
public int[] getVisited() {
return visited;
}
public void setVisited(int[] visited) {
this.visited = visited;
}
public int[][] getArc() {
return arc;
}
public void setArc(int[][] arc) {
this.arc = arc;
}
public char[] getVex() {
return vex;
}
public void setVex(char[] vex) {
this.vex = vex;
}
public int getArcnum() {
return arcnum;
}
public void setArcnum(int arcnum) {
this.arcnum = arcnum;
}
public int getVexnum() {
return vexnum;
}
public void setVexnum(int vexnum) {
this.vexnum = vexnum;
}
}
二、深度优先遍历
package GraphPackage;
import java.util.Stack;
public class DFS {
public static void dfs(GraphNode graph){
graph.setVisited(new int[graph.vexnum]); //初始化访问标志数组
Stack<Integer> stack = new Stack<Integer>();
for(int i = 0;i < graph.vexnum; i++){ //遍历图
if(graph.visited[i] == 0){ //如果该节点没有被访问过
graph.visited[i] = 1; //访问该节点,将访问标志数组置为1
System.out.print(graph.vex[i] + " "); //打印该节点
stack.push(i); //该节点进栈
}
while(!stack.isEmpty()){ //栈不为空,进入循环
int k = stack.pop(); //栈顶节点出栈
for(int j = 0; j < graph.vexnum; j++){
//如果是相邻的节点且没有访问过
if(graph.arc[k][j] == 1 && graph.visited[j] == 0){
graph.visited[j] = 1; //访问该节点,将访问标志数组置为1
System.out.print(graph.vex[j] + " "); //打印该节点
stack.push(j); //该节点进栈
break; //这条路结束,返回上一个节点
}
}
}
}
}
public static void main(String[] args) {
GraphNode graph = new GraphNode();
char[] vex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
int[][] arc = {{0,1,1,1,0,0,0},{1,0,0,1,1,0,0},{1,0,0,0,0,1,0},
{1,1,0,0,0,1,1},{0,1,0,0,0,0,1},{0,0,1,1,0,0,1},{0,0,0,1,1,1,0}};
graph.setVex(vex); //给顶点赋值
graph.setArc(arc); //给边赋值
graph.setVexnum(vex.length); //给顶点个数赋值
int arccount = 0; //计算边的个数
for (int i = 0; i < vex.length; i++){
for (int j = 0; j < vex.length; j++){
if (arc[i][j] == 1){
arccount++;
}
}
}
graph.setArcnum(arccount/2); //给边个数赋值
System.out.println("深度优先遍历:");
dfs(graph);
}
}
三、广度优先遍历
package GraphPackage;
import java.util.LinkedList;
import java.util.Stack;
public class BFS {
public static void bfs(GraphNode graph){
graph.setVisited(new int[graph.vexnum]); //初始化访问标志数组
LinkedList<Integer> queue = new LinkedList<>();
for (int i = 0; i < graph.vexnum; i++){
if (graph.visited[i] == 0){
graph.visited[i] = 1; //访问该节点,将访问标志数组置为1
System.out.print(graph.vex[i] + " "); //打印该节点
queue.push(i); //该节点入队
}
while(!queue.isEmpty()){ //队列不为空,进入循环
int k = queue.poll(); //队头节点出队
for(int j = 0; j < graph.vexnum; j++){
//如果是相邻的节点且没有访问过
if(graph.arc[k][j] == 1 && graph.visited[j] == 0){
graph.visited[j] = 1; //访问该节点,将访问标志数组置为1
System.out.print(graph.vex[j] + " "); //打印该节点
queue.push(j); //该节点入队
}
}
}
}
}
public static void main(String[] args) {
GraphNode graph = new GraphNode();
char[] vex = {'A', 'B', 'C', 'D', 'E', 'F', 'G'};
int[][] arc = {{0,1,1,1,0,0,0},{1,0,0,1,1,0,0},{1,0,0,0,0,1,0},
{1,1,0,0,0,1,1},{0,1,0,0,0,0,1},{0,0,1,1,0,0,1},{0,0,0,1,1,1,0}};
graph.setVex(vex); //给顶点赋值
graph.setArc(arc); //给边赋值
graph.setVexnum(vex.length); //给顶点个数赋值
int arccount = 0; //计算边的个数
for (int i = 0; i < vex.length; i++){
for (int j = 0; j < vex.length; j++){
if (arc[i][j] == 1){
arccount++;
}
}
}
graph.setArcnum(arccount/2); //给边个数赋值
System.out.println("广度优先遍历:");
bfs(graph);
}
}
四、最短路径(Dijkstra)
package GraphPackage;
public class Dijkstra {
public static int[] dijkstra(GraphNode graph){
int[] results = new int[graph.vexnum];
graph.setVisited(new int[graph.vexnum]); //初始化访问标志数组
graph.visited[0] = 1; //0顶点已经被访问过
for (int i = 1; i < graph.vexnum; i++){
results[i] = graph.arc[0][i];
}
for (int i = 1; i < graph.vexnum; i++){
int min = Integer.MAX_VALUE; //用于暂时存放顶点A到i的最短距离,初始化为最大值
int k = 0;
//找到顶点A到其他顶点中距离最小的一个顶点
for (int j = 1; j < graph.vexnum; j++){
if (graph.visited[j] == 0 && results[j] != -1 && min > results[j]){
min = results[j];
k = j;
}
}
graph.visited[k] = 1; //将距离最小的点记为已遍历
//将顶点A到其他顶点的距离 与 加入中间顶点k之后的距离 进行比较,更新最短距离
for (int j = 1; j < graph.vexnum; j++){
if (graph.visited[j] == 0){ //顶点j未被遍历
//顶点k到j有边;
//并且,顶点0到j的距离>顶点0到k再到j的距离 或 顶点0无法直接到达顶点j
if (graph.arc[k][j] != -1 &&
(results[j] > min + graph.arc[k][j] || results[j] == -1)){
results[j] = min + graph.arc[k][j]; //更新顶点0到j的最短距离
}
}
}
}
return results;
}
public static void main(String[] args) {
GraphNode graph = new GraphNode();
char[] vex = {'A', 'B', 'C', 'D', 'E', 'F'};
int[][] arc = {{0,6,3,-1,-1,-1},{6,0,2,5,-1,-1},{3,2,0,3,4,-1},
{-1,5,3,0,2,3},{-1,-1,4,2,0,5},{-1,-1,-1,3,5,0}};
graph.setVex(vex); //给顶点赋值
graph.setArc(arc); //给边赋值
graph.setVexnum(vex.length); //给顶点个数赋值
int arccount = 0; //计算边的个数
for (int i = 0; i < vex.length; i++){
for (int j = 0; j < vex.length; j++){
if (arc[i][j] != -1 && arc[i][j] != 0){
arccount++;
}
}
}
graph.setArcnum(arccount/2); //给边个数赋值
System.out.println("A点到其他各点的最短路径:");
int[] results = dijkstra(graph);
for (int result : results){
System.out.print(result + " ");
}
}
}
输入的测试用例为下面这个图: