介绍
本文提供了图的邻接表、邻接矩阵的Java实现,包括深度优先算法、广度优先算法、prim算法和地杰斯特拉算法。
原理分析
输入图:
深度优先遍历:
广度优先遍历:
注意:邻接矩阵和邻接表同样的输入遍历的结果可能会不完全一样,原因邻接表的构造并非将小编号的结点连接在靠前的位置,因此导致遍历结果和邻接矩阵不相同,但其在逻辑上仍然满足图的深度优先遍历。另外,最小生成树和最短路径当图中存在两条相同长度的路径时,其结果也不一定唯一。
算法描述
包结构:
import java.util.List;
public interface Graph {
public void dfsTraverse(); //深度优先遍历
public void bfsTraverse(); //广度优先遍历
public List<String> prim(); //prim算法
public List<String> dijistra(int v1,int v2);//地杰斯特拉算法
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* 使用邻接表
*/
public class AGraph implements Graph{
private static Scanner scanner = new Scanner(System.in);
private class ArcNode{
public int adjvex; //边所指向的结点
public int w; //边的权值
ArcNode next;
}
private class VNode{
ArcNode firstArc;
String data;
}
int n,e; //顶点数,边数
VNode vnodes[];
public static AGraph createGraph(){
AGraph g = new AGraph();
System.out.println("输入定点数和边数");
g.n = scanner.nextInt();
g.e = scanner.nextInt();
g.vnodes = new VNode[g.n];
for(int i = 0;i<g.n;i++){
g.vnodes[i] = g.new VNode();
}
System.out.println("输入定点信息");
for (int i = 0; i < g.n; i++) {
g.vnodes[i].data = scanner.next();
}
System.out.println();
for(int i = 0;i<g.n;i++){
System.out.println("顶点" + g.vnodes[i].data + "的编号为" + i);
}
for (int i = 0; i < g.e; i++) {
System.out.println("输入边的两个定点编号和它的权值");
ArcNode arcNode1 = g.new ArcNode();
int x = scanner.nextInt();
int y = scanner.nextInt();
int w = scanner.nextInt();
arcNode1.adjvex = y;
arcNode1.w = w;
arcNode1.next = g.vnodes[x].firstArc;
g.vnodes[x].firstArc = arcNode1;
ArcNode arcNode2 = g.new ArcNode();
arcNode2.adjvex = x;
arcNode2.w = w;
arcNode2.next = g.vnodes[y].firstArc;
g.vnodes[y].firstArc = arcNode2;
}
return g;
}
public void dfs(int v,boolean visited[]){
if(visited[v]){
return;
}
visited[v] = true;
System.out.println(vnodes[v].data);
for(ArcNode node = vnodes[v].firstArc;node != null;node = node.next){
if(!visited[node.adjvex]){
dfs(node.adjvex,visited);
}
}
}
public void dfsTraverse(){
boolean visited[] = new boolean[n];
for(int i = 0;i<n;i++){
dfs(i,visited);
}
}
public void bfs(int v,boolean visited[]){
if(visited[v]){
return;
}
int que[] = new int[n];
int front = 0,rear = 0;
visited[v] = true;
System.out.println(vnodes[v].data);
rear = (rear + 1) % n;
que[rear] = v;
while(rear != front){
front = (front + 1)%n;
int j = que[front];
for(ArcNode node = vnodes[j].firstArc;node != null;node=node.next){
if(!visited[node.adjvex]){
rear = (rear + 1)%n;
que[rear] = node.adjvex;
System.out.println(vnodes[node.adjvex].data);
visited[node.adjvex] = true;
}
}
}
}
@Override
public void bfsTraverse() {
boolean visited[] = new boolean[n];
for(int i = 0;i<n;i++){
bfs(i,visited);
}
}
public List<String> prim(){
List<String> list = new ArrayList<String>();
int lowcost[] = new int[n];
boolean vset[] = new boolean[n];
for (int i = 0; i < lowcost.length; i++) {
lowcost[i] = Integer.MAX_VALUE;
}
int v = 0;
for(ArcNode node = vnodes[v].firstArc;node != null; node = node.next){
lowcost[node.adjvex] = node.w;
}
vset[v] = true;
for (int i = 0; i < n-1; i++) {
int min = Integer.MAX_VALUE;
int k = 0;
for (int j = 0; j < lowcost.length; j++) {
if(!vset[j] && lowcost[j]<min){
min = lowcost[j];
k = j;
}
}
list.add("(" + v + "," + k + ")");
vset[k] = true;
v = k;
for(ArcNode node = vnodes[k].firstArc;node != null; node = node.next){
if(!vset[node.adjvex] && node.w < lowcost[node.adjvex]){
lowcost[node.adjvex] = node.w;
}
}
}
return list;
}
public List<String> dijistra(int v1,int v2){
List<String> list = new ArrayList<String>();
boolean vset[] = new boolean[n];
int path[] = new int[n];
int dist[] = new int[n];
for (int i = 0; i < path.length; i++) {
dist[i] = Integer.MAX_VALUE;
path[i] = -1;
}
for(ArcNode node = vnodes[v1].firstArc;node != null;node = node.next){
dist[node.adjvex] = node.w;
path[node.adjvex] = v1;
}
vset[v1] = true;
path[v1] = -1;
for (int i = 0; i < n; i++) {
int min = Integer.MAX_VALUE;
int k = 0;
for (int j = 0; j < dist.length; j++) {
if(!vset[j] && dist[j] < min){
min = dist[j];
k = j;
}
}
vset[k] = true;
for(ArcNode node = vnodes[k].firstArc;node != null;node = node.next){
if(!vset[node.adjvex] && dist[node.adjvex] + dist[k] < dist[node.adjvex]){
dist[node.adjvex] = dist[node.adjvex] + dist[k];
path[node.adjvex] = k;
}
}
}
int p = v2;
while(path[p] != -1){
list.add(0, "(" + path[p] + "," + p +")");
p = path[p];
}
return list;
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
/**
* 邻接矩阵-
*/
public class MGraph implements Graph{
private class Node{
public String data;
}
protected static Scanner scanner = new Scanner(System.in);
protected int edges[][];
protected Node nodes[];
protected int n,e;
//创建图
public static MGraph createGraph(){
MGraph g = new MGraph();
System.out.println("分别输入顶点数量和边数量");
g.n = scanner.nextInt();
g.e = scanner.nextInt();
g.nodes = new Node[g.n];
for(int i = 0;i<g.n;i++){
g.nodes[i] = g.new Node();
}
g.edges = new int[g.n][g.n];
System.out.println("输入每个顶点的信息");
for(int i = 0;i<g.n;i++){
g.nodes[i].data = scanner.next();
}
System.out.println();
for(int i = 0;i<g.n;i++){
System.out.println("顶点" + g.nodes[i].data + "的编号为" + i);
}
for(int i=0;i<g.n;i++){
for(int j = 0;j<g.n;j++){
g.edges[i][j] = Integer.MAX_VALUE;
}
}
for(int i = 0;i<g.e;i++){
System.out.println("输入边的两个定点编号和它的权值");
int x = scanner.nextInt();
int y = scanner.nextInt();
g.edges[x][y] = scanner.nextInt();
g.edges[y][x] = g.edges[x][y];
}
return g;
}
//打印矩阵
public void show(){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(edges[i][j] == Integer.MAX_VALUE){
System.out.print( "N\t");
}else{
System.out.print(edges[i][j] + "\t");
}
}
System.out.println();
}
}
//深度优先遍历
public void dfsTraverse(){
boolean visited[] = new boolean[n];
for(int i = 0;i<n;i++){
dfs(i,visited);
}
}
private void dfs(int v,boolean visited[]){
if(visited[v])return;
visited[v] = true;
System.out.print(nodes[v].data+ "\t");
for(int i=0;i<n;i++){
if(edges[v][i] != Integer.MAX_VALUE && !visited[i]){
dfs(i,visited);
}
}
}
private void bfs(int v,boolean visited[]){
if(visited[v]){
return;
}
int que[] = new int[n];
int front = 0,rear = 0;
rear = (rear+1)%n;
que[rear] = v;
visited[v] = true;
System.out.print(nodes[v].data + "\t");
while(front != rear){
front = (front + 1)%n;
int flag = que[front];
for(int i = 0;i<n;i++){
for(int j=0;j<n;j++){
if(edges[flag][i] != Integer.MAX_VALUE && !visited[i]){
System.out.print(nodes[i].data+ "\t");
rear = (rear + 1)%n;
que[rear] = i;
visited[i] = true;
}
}
}
}
}
//广度优先遍历
public void bfsTraverse(){
boolean visited[] = new boolean[n];
for(int i = 0;i<n;i++){
bfs(i,visited);
}
}
//prim算法
public List<String> prim(){
List<String> list = new ArrayList<String>(); //用来保存最小生成树的边集
int lowcost[] = new int[n]; //记录所有点到最小生成的距离
boolean vset[] = new boolean[n];//记录已经加入到最小生成树的节点
int v = 0;
//从编号0开遍历
for(int i = 0;i<n;i++){
lowcost[i] = edges[0][i];
}
vset[v] = true;
for (int i = 0; i < n-1; i++) {
int min = Integer.MAX_VALUE;
int k = 0;
for (int j = 0; j < n; j++) {
if (!vset[j] && lowcost[j] < min) {
min = lowcost[j];
k = j;
}
}
list.add("(" + v + "," + k + ")");
vset[k] = true;
v = k;
for (int j = 0; j < n; j++) {
if(!vset[j] && edges[k][j] < lowcost[j]){
lowcost[j] = edges[k][j];
}
}
}
return list;
}
//地杰斯特拉算法
public List<String> dijistra(int v1,int v2){
List<String> list = new ArrayList<String>();
boolean vset[] = new boolean[n];
int path[] = new int[n];
int dist[] = new int[n];
for (int i = 0; i < n; i++) { //对个数组进行初始化
dist[i] = edges[v1][i];
if(edges[v1][i] < Integer.MAX_VALUE){
path[i] = v1;
}else{
path[i] = -1;
}
}
vset[v1] = true;
path[v1] = -1;
for (int i = 0; i < n-1; i++) {
int min = Integer.MAX_VALUE;
int v = 0;
for (int j = 0; j < n; j++) {
if(!vset[j] && dist[j] < min){
v = j;
min = dist[j];
}
}
vset[v] = true;
for (int j = 0; j < n; j++) {
if(!vset[j] && dist[v] + edges[v][j] < dist[j]){
dist[j] = dist[v] + edges[v][j];
path[j] = v;
}
}
}
int p = v2;
while(path[p] != -1){
list.add(0, "(" + path[p] + "," + p +")");
p = path[p];
}
return list;
}
}
import java.util.List;
import java.util.Scanner;
public class Main {
public static void main(String args[]){
Scanner scanner = new Scanner(System.in);
System.out.println("选择需要操作的序号");
System.out.println("1、使用邻接表的方法遍历");
System.out.println("2、使用邻接矩阵的方法遍历");
int flag = scanner.nextInt();
Graph g = null;
switch(flag){
case 1:
g = AGraph.createGraph();
break;
case 2:
g = MGraph.createGraph();
break;
}
traverse(g);
scanner.close();
}
public static void traverse(Graph g){
System.out.println("深度优先结果为:");
g.dfsTraverse();
System.out.println("广度优先结果为:");
g.bfsTraverse();
System.out.println("prim算法结果为:");
List<String> eset = g.prim();
for (String string : eset) {
System.out.println(string);
}
System.out.println("地杰斯特算法结果为:");
List<String> eset1 = g.dijistra(0, 2);
for (String string : eset1) {
System.out.println(string);
}
}
}
测试结果
选择需要操作的序号
1、使用邻接表的方法遍历
2、使用邻接矩阵的方法遍历
2
分别输入顶点数量和边数量
6 8
输入每个顶点的信息
1 2 3 4 5 6
顶点1的编号为0
顶点2的编号为1
顶点3的编号为2
顶点4的编号为3
顶点5的编号为4
顶点6的编号为5
输入边的两个定点编号和它的权值
0 1 3
输入边的两个定点编号和它的权值
0 2 4
输入边的两个定点编号和它的权值
1 2 2
输入边的两个定点编号和它的权值
1 3 7
输入边的两个定点编号和它的权值
3 5 3
输入边的两个定点编号和它的权值
1 4 4
输入边的两个定点编号和它的权值
2 4 1
输入边的两个定点编号和它的权值
4 5 5
深度优先结果为:
1 2 3 5 6 4
广度优先结果为:
1 2 3 4 5 6
prim算法结果为:
(0,1)
(1,2)
(2,4)
(4,5)
(5,3)
地杰斯特算法结果为:
(0,1)
(1,5)
(5,4)
(4,2)
总结
本文提供了图的几个重要算法的Java实现,最后给出了实验结果的原理分析。
来源:CSDN
作者:丶幻一
链接:https://blog.csdn.net/qq_25956141/article/details/103863303