图的递归非递归深度优先搜索和广度优先搜索,两种最小生成树算法

时间:2022-12-22 12:34:03

代码如下:


以邻接矩阵构建图


public class Graph {

public static void main(String[] args) {
/**
* 定义一个图
*
* 本次实验为无向图
*
* 为了与平日思维习惯,第一行和第一列不用
*
* 从map[1][1]算作第一个点
*
* map:图
*
* mapUsed:标识该结点有没有遍历到
*
* edges:存储结点到结点的权重
*/
int[][] map = new int[10][10];
boolean[] mapUsed = new boolean[10];
Edge edges[] = new Edge[11];

/**
* 初始化图
*
*/
initMap(map, edges);

/**
* 深度优先遍历
*/
Depth_First_Traversal(map, mapUsed);

/**
* 广度优先遍历
*/
Breadth_First_Traversal(map, mapUsed);

/**
* 两种方式求最小生成树
*/
Minimal_Spanning_Tree(map, edges);

}

/**
* 初始化图的数据
*/
public static void initMap(int[][] map, Edge[] edges) {

/**
* 假定不能到达的点为Integer类型最大值
*/
for (int i = 0; i < 10; i++) {

for (int j = 0; j < 10; j++) {

map[i][j] = Integer.MAX_VALUE;

}

}

/**
* 初始化图
*/
map[1][2] = 3;
map[2][1] = 3;
edges[1] = new Edge(1, 2, 3);

map[2][8] = 10;
map[8][2] = 10;
edges[2] = new Edge(2, 8, 10);

map[8][5] = 9;
map[5][8] = 9;
edges[3] = new Edge(5, 8, 9);

map[7][9] = 4;
map[9][7] = 4;
edges[4] = new Edge(7, 9, 4);

map[4][8] = 7;
map[8][4] = 7;
edges[5] = new Edge(4, 8, 7);

map[3][7] = 18;
map[7][3] = 18;
edges[6] = new Edge(3, 7, 18);

map[9][6] = 15;
map[6][9] = 15;
edges[7] = new Edge(6, 9, 15);

map[4][5] = 13;
map[5][4] = 13;
edges[8] = new Edge(4, 5, 13);

map[5][6] = 10;
map[6][5] = 10;
edges[9] = new Edge(5, 6, 10);

map[4][7] = 23;
map[7][4] = 23;
edges[10] = new Edge(4, 7, 23);
}

/**
* 深度优先遍历
*
* @param map
* @param mapUsed
*/
public static void Depth_First_Traversal(int[][] map, boolean[] mapUsed) {

System.out.println("从点1,递归方式深度优先遍历图:");
DFS_Recursion(map, mapUsed, 1);
System.out.println();

System.out.println("从点1,非递归方式深度优先遍历图:");
DFS_NotRecursion(map);
System.out.println();

}

/**
* 广度优先遍历
*
* @param map
* @param mapUsed
*/
public static void Breadth_First_Traversal(int[][] map, boolean[] mapUsed) {

System.out.println("从点1,非递归方式广度优先遍历图:");
BFS_NotRecursion(map);
System.out.println();

mapUsed = new boolean[10];
System.out.println("从点1,递归方式广度优先遍历图:");
System.out.print(1 + " ");
mapUsed[1] = true;
Queue nextBFS = new Queue();
BFS_Recursion(map, mapUsed, 1, nextBFS);
System.out.println();

}

/**
* 求最小生成树
*
* @param map
* @param edges
*/
public static void Minimal_Spanning_Tree(int[][] map, Edge[] edges) {

System.out.println("Prim算法求最小生成树:");
Prim(9, map);

System.out.println("Kruskal算法求最小生成树:");
Kruskal(edges);

}

/**
* 递归方式深度优先遍历
*
* @param map
*/
public static void DFS_Recursion(int[][] map, boolean[] mapUsed, int next) {

// 打印,即访问next结点
System.out.print(next + " ");
// 标识next结点已经被访问
mapUsed[next] = true;

// 在next结点的出度里寻找下一个
for (int i = 1; i < map.length; i++) {

// 找下一个需要遍历的点
if (!mapUsed[i] && map[next][i] < 1000) {

// 递归
DFS_Recursion(map, mapUsed, i);

}

}
}

/**
* 递归方式广度优先遍历
*
* @param map
*/
public static void BFS_Recursion(int[][] map, boolean[] mapUsed, int next,
Queue nextBFS) {

// 在next结点的出度里寻找下一个
for (int i = 1; i < map.length; i++) {

// 如果没有访问
if (!mapUsed[i] && map[next][i] < 1000) {

// 访问i结点
mapUsed[i] = true;
System.out.print(i + " ");

// 将i结点排入队列
nextBFS.enQueue(i);

}

}

// 如果队列不为空
while (!nextBFS.isEmpty()) {

// 出队列
int nextBFSNumber = nextBFS.deQueue();

// 递归
BFS_Recursion(map, mapUsed, nextBFSNumber, nextBFS);
}

}

/**
* 非递归方式深度优先遍历
*
* @param map
*/
public static void DFS_NotRecursion(int[][] map) {

Stack stack = new Stack();
boolean[] mapUsed = new boolean[10];

// 将1压入栈
stack.push(1);
System.out.print(1 + " ");
mapUsed[1] = true;

while (!stack.isEmpty()) {

// 取得栈顶元素
int next = stack.getTop();

for (int i = 1; i < map.length; i++) {

if (!mapUsed[i] && map[next][i] < 1000) {

// 访问i结点
mapUsed[i] = true;
stack.push(i);

System.out.print(i + " ");

// 访问完i之后,重新得到栈顶元素,即i元素
next = stack.getTop();
// 重新遍历
i = 1;
}

}

// 如果执行到这一步,说明该点没有什么好遍历的了,从栈顶弹出
stack.pop();

}

}

/**
* 非递归方式广度优先遍历
*
* @param map
*/
public static void BFS_NotRecursion(int[][] map) {

Queue queue = new Queue();
boolean[] mapUsed = new boolean[10];

for (int i = 1; i < map.length; i++) {

if (!mapUsed[i]) {

mapUsed[i] = true;
System.out.print(i + " ");

// 将i排入队列
queue.enQueue(i);

// 如果队列不空,就接着执行
while (!queue.isEmpty()) {

// 取得队列的第一个值
int next = queue.deQueue();

for (int j = 1; j < 10; j++) {

if (!mapUsed[j] && map[next][j] < 1000) {

// 访问j
mapUsed[j] = true;
System.out.print(j + " ");

// 将j排入队列
queue.enQueue(j);

}

}

}

}

}

}

/**
* Prim算法求最小生成树
*
* @param map
* @return
*/
public static void Prim(int n, int[][] map) {

// 权重
int[] lowcost = new int[n + 1];
// 相邻结点
int[] closest = new int[n + 1];
boolean[] s = new boolean[n + 1];

s[1] = true;

for (int i = 2; i <= n; i++) {

lowcost[i] = map[1][i];
closest[i] = 1;

}

// 取得lowcost中最小值的点
for (int i = 1; i < n; i++) {

int min = Integer.MAX_VALUE;
int j = 1;

for (int k = 2; k <= n; k++) {
if ((lowcost[k] < min) && (!s[k])) {

min = lowcost[k];
j = k;

}
}

// 访问j结点
System.out.println(j + ", " + closest[j]);
s[j] = true;

// 依次遍历k,找出j到k结点的最小值,给lowcost[k]
// 距离k最近的结点为:closest[k]=j
for (int k = 2; k <= n; k++) {
if ((map[j][k] < lowcost[k]) && (!s[k])) {

lowcost[k] = map[j][k];
closest[k] = j;

}
}

}

}

/**
* Kruskal算法求最小生成树
*
* @param edges
* @return
*/
public static void Kruskal(Edge edges[]) {

int[] parent = new int[100];

// 冒泡排序,将edges数组中的Edge按weight升序排列
for (int i = edges.length - 1; i > 0; i--) {

for (int j = 1; j < i; j++) {

if (edges[j].weight > edges[j + 1].weight) {

int bTemp = edges[j].begin;
int eTemp = edges[j].end;
int wTemp = edges[j].weight;

edges[j].begin = edges[j + 1].begin;
edges[j].end = edges[j + 1].end;
edges[j].weight = edges[j + 1].weight;

edges[j + 1].begin = bTemp;
edges[j + 1].end = eTemp;
edges[j + 1].weight = wTemp;

}

}

}

for (int i = 1; i < edges.length; i++) {

// 寻找指向i边头结点的结点
int n = Find(parent, edges[i].begin);
// 寻找指向i边尾结点的结点
int m = Find(parent, edges[i].end);

// 如果没有形成回路
// 因为parent的值都在一条树枝上,即如果i.begin和i.end在一条树枝上,则n必定与m相等
if (n != m) {

// 指向n结点的是m结点
parent[n] = m;
System.out.println(edges[i].begin + " " + edges[i].end + " "
+ edges[i].weight);

}

}

}

/**
* 寻找相连结点
*
* @param parent
* @param f
* @return
*/
public static int Find(int[] parent, int f) {

// 直到一条链最后的那个结点
while (parent[f] > 0) {
f = parent[f];
}
// 返回该结点
return f;
}

}

/**
* 边
*
* weight:权重
*
* begin:起始结点
*
* end:结束结点
*
* @author wanfeng
*
*/
class Edge {

public int weight;
public int begin, end;

Edge(int uu, int vv, int ww) {
begin = uu;
end = vv;
weight = ww;
}

}

/**
* 数据结构:栈
*
*
* @author wanfeng
*
*/
class Stack {

private int[] element;
private int length;

public Stack() {

element = new int[100];
length = -1;

}

/**
* 将元素压入栈顶
*
* @param integer
*/
public void push(int integer) {

length++;
element[length] = integer;

}

/**
* 得到栈顶元素
*
* @return
*/
public int getTop() {

return element[length];

}

/**
* 得到并删除栈顶元素
*
* @return
*/
public int pop() {

int res = element[length];

length--;

return res;
}

/**
* 因为初始值为-1,所以与-1进行判断
*
* @return
*/
public boolean isEmpty() {

return length == -1;

}

}

/**
* 数据结构:队列
*
* @author wanfeng
*
*/
class Queue {

private int[] element;
private int length;

public Queue() {
element = new int[100];
length = 0;
}

public void enQueue(int integer) {

element[length] = integer;

length++;

}

public int deQueue() {

int res = element[0];

for (int i = 0; i < length; i++) {

element[i] = element[i + 1];

}
length--;

return res;
}

public boolean isEmpty() {

return length == 0;

}

}