package test1;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
public class test {
//邻接矩阵
final static int MAX = 65535; // 两个顶点之间没有路径时的长度
int verticts; // 顶点数
int sides; // 边数
String[] vex; // 一维数组 存储顶点信息
int[][] arc; // 二维数组 存储边的权重;
test(int verticts){
this.verticts = verticts;
this.sides = 0;
for(int i = verticts-1;i>0;i--){
this.sides +=i; // 计算边数,共n(n-1)/2;
}
this.vex = new String[verticts]; // 创建 顶点数组
this.arc = new int[verticts][verticts]; // 创建 边数组
//初始化一个无向图,所有边设为最大权值(即不可能达到的值)
for(int i = 0; i < verticts;i++){
for(int j = 0; j < verticts;j++){
if(i!=j){
this.arc[i][j] = MAX;
}else{
this.arc[i][j]=0;
}
}
}
}
// 建立无向网图, 给图中的 顶点内容 和 边权重 赋值
public void addGraph(){
//顶点数据
this.vex[0] = "beijing";
this.vex[1] = "shanghai";
this.vex[2] = "tianjing";
this.vex[3] = "chengdu";
this.vex[4] = "changsha";
this.vex[5] = "chongqing";
//边的权值
for(int i = 1; i < verticts;i++){
for(int j = 0; j < i;j++){
int n = (int)(Math.random()*100); //随机生成权值
if(n > 0){
this.arc[i][j]=this.arc[j][i] = n;
}else if(n == 0){
this.arc[i][j]=this.arc[j][i] = MAX;
}
}
}
}
//利用图的二维数组输出
public void printGraph(){
for(int i = 0; i < verticts;i++){
//输出第一行的名称
if(i == 0){
System.out.print("* ");
for(int x=0;x<verticts;x++){
System.out.print(this.vex[x]+" ");
}
System.out.println();
System.out.println(" ==============================================================");
}
//给每行前面输出地址
System.out.print(this.vex[i]+" ");
for(int j = 0; j < verticts;j++){
System.out.print(this.arc[i][j]+" ");
}
System.out.println();
System.out.println();
}
}
/*//得到最小生成树之克鲁斯卡尔(Kruskal)算法
//得到边集数组并按权由大到小排序 这一步是利用Edge类来实现的
//注意 此函书还有错误,有时候会输出6条边,尚待解决(MinispanTree_kruskal在寻找的过程中不可能形成环路,所以不可能多一条边)
//上述错误已经解决,有两个地方出来问题,第一:Edge的begin必须小于end,否则在Find函数中判断将出现错误,因为如果end小于begin的话,end有可能
//出现等于0的情况,第二:循环每一条边时,i应该小于G.sides;而我之前写成了i<G.verticts
public void MiniSpanTree_Kruskal(test G){
Edge edge = new Edge();
edge.Edge_1(G);
//edge.PrintEdge();
int i, n, m;
int num = 0; //记录找到了多少条边
int parent[] = new int[G.verticts]; //定义一个数组用来判断边与边是否形成回路
for( i = 0;i < G.verticts;i++){
parent[i] = 0; //初始化数组为-1
}
for(i = 0;i < G.sides;i++){ // 循环每一条边,15为顶点
n = Find(parent,edge.edge[i].begin);
m = Find(parent,edge.edge[i].end);
if(n != m ){ //n不等于m 说明边与边没有形成环路
parent[n] = m;//将此边的尾节点放入下标为起点的parent中
System.out.println("("+edge.edge[i].begin+","+edge.edge[i].end+")"+" 权长:"+edge.edge[i].weight);
num++;
//for(int j = 0;j < G.verticts;j++){
//System.out.print(" !!!!"+parent[j]); //初始化数组为0
//}
}
if(num >= G.verticts) break; //如果找到了(顶点数-1)条边,并且没有构成回路,就已经完成任务了,不用再找了,
}
}
public int Find(int[] parent,int f){ //查找连线顶点的尾部下表
while(parent[f] > 0){
f = parent[f];
}
return f;
}
*/
//测试函数
public static void main(String[] args){
test graph = new test(6); //创建一个顶点个数为6的图
graph.addGraph();
System.out.println("将图以二维矩阵的方式输出");
graph.printGraph();
Edge edge = new Edge();
edge.Edge_1(graph);
edge.PrintEdge();
/* System.out.println();
System.out.println("最小生成树之克鲁斯卡尔算法Kruskal ");
graph.MiniSpanTree_Kruskal(graph);
*/
}
}
//Edge类 利用深度优先遍历得到树的所有路径以及这些路径的权值,并根据权值的大小进行从小到大排序
class Edge{
public int begin; //这两个顶点的开始顶点
public int end; //这两个顶点的结束顶点
public int weight; //两个顶点之间的权值
Edge edge[] = new Edge[15]; //edge数组 图的边数没有传入,计算最大值
public void Edge_1(test G){
DFSTraverse_1(G); //得到edge数组
sortEdge(); //对edge进行排序
}
public void SetEdge(int begin,int end,int weight){
this.begin = begin;
this.end = end;
this.weight = weight;
}
int k=0; //用于数组赋值是计数
//利用深度优先遍历得到edge数组
public void DFS_1(test G,int i,boolean[] visited){
int j;
visited[i] = true;
//System.out.print(G.arc[i][i+1]+" "); //打印顶点的值
for(j = 0;j < G.verticts;j++)
{
if(G.arc[i][j]>0 && !visited[j]){
//System.out.print(G.arc[i][j]+" ");
DFS_1(G,j,visited); //对访问的邻接顶点递归调用
}
if(G.arc[i][j] > 0 && i < j){
this.edge[this.k] = new Edge();
edge[this.k].SetEdge(i,j,G.arc[i][j]); //edge数组中的每个元素都是Edge类型,即每个元素有begin,end和weight三个属性
this.k++;
}
}
}
public void DFSTraverse_1(test G){
boolean[] visited = new boolean[G.verticts];
for(int i = 0;i < G.verticts;i++){
visited[i] = false; //初始状态所有顶点都是未访问过的状态
}
for(int i = 0;i < G.verticts;i++){
if(!visited[i])
DFS_1(G,i,visited); //对未访问过的顶点调用DFS 如果是连通图,则只会执行一次
}
}
//对得到的数组进行排序
public void sortEdge(){
Edge newEdge = new Edge();
newEdge.edge[0] = new Edge();
for(int i = 0;i < this.edge.length;i++){
for(int j = i;j < this.edge.length;j++){
if(this.edge[i].weight > this.edge[j].weight){
newEdge.edge[0] = this.edge[i];
this.edge[i] = this.edge[j];
this.edge[j] = newEdge.edge[0];
}
}
}
}
//输出Edge数组,用以测试Edge是否创建、赋值成功
public void PrintEdge(){
for(int i = 0; i < this.edge.length;i++){
System.out.println("数组"+i+": "+this.edge[i].begin+" "+this.edge[i].end+" "+this.edge[i].weight);
}
}
}
从图中提取边的开始begin、结束end和权重weight
最新推荐文章于 2021-08-24 19:53:08 发布